Найти в Дзене
Art of Data&Statistics

Дофаминовые рецепторы и парадигма объектно-ориентированного программирования (ООП)

Дофаминовые рецепторы и парадигма объектно-ориентированного программирования (ООП): легко и просто!

Дофаминовые рецепторы играют важную роль в функционировании центральной нервной системы. Основной эндогенный лиганд-агонист этих рецепторов, как видно из названия, дофамин. Дофаминовые рецепторы участвуют в процессах мотивации, обучения, тонкой моторной координации, модулирования нейроэндокринных сигналов. Этот класс включает пять типов рецепторов: D1, D2, D3, D4 и D5 (из Википедии).

1. Дофаминовые рецепторы являются полноценным классом, а пять типов рецепторов: D1, D2, D3, D4 и D5 - являются вполне себе экземплярами этого класса. Объявим класс:

class Dopamine_receptor:

Укажем атрибут класса, чтобы было понятно, что это дофаминовый рецептор - "дофаминовый рецептор»:

species = "дофаминовый рецептор"

По структурным, биохимическим и фармакологическим характеристикам соответствующие рецепторы подразделяют на D1-подобные (D1, D5) и D2-подобные (D2, D3, D4) (из Википедии).

Уже внутри класса укажем атрибуты экземпляра. Для этого воспользуемся специальной функцией-конструктором __init__().

В качестве атрибутов укажем name (имя) и subtype (подтип). Они и будут аргументами-ключевыми словами. Имя может принимать значения D1, D2, D3, D4 и D5. Подтип может принимать значения D1- и D2-подобные.

def __init__(self, name, subtype):
self.name = name

self.subtype = subtype

После атрибутов можно уже создать сами экземпляры класса. Их атрибуты уже указаны в __init__(), причём мы прописали 2 признака, и теперь прописываем их по отношению к каждому экземпляру.

D1 = Dopamine_receptor("D1-рецептор", "D1-подобных рецепторов")
D2 = Dopamine_receptor("D2-рецептор", "D2-подобных рецепторов")

D3 = Dopamine_receptor("D3-рецептор", "D2-подобных рецепторов")

D4 = Dopamine_receptor("D4-рецептор", "D2-подобных рецепторов")

D5 = Dopamine_receptor("D5-рецептор", "D1-подобных рецепторов")

Теперь мы можем получить доступ к атрибуту/атрибутам класса и атрибуту/атрибутам экземпляра. Атрибуты класса для всех экземпляров этого класса - одинаковы. Доступ к ним получают через __class__.species. Используем экземпляры D1 и D2.

print('D1 относится к классу "{}"'.format(D1.__class__.species))

print('D2 также относится к классу "{}"'.format(D2.__class__.species))

Атрибуты экземпляра индивидуальны для каждого экземпляра. Доступ к ним получают через аргументы, прописанные в __init__(): .name и .subtype. Используем экземпляры D1 и D2.

print("{} относится к подтипу {}".format(D1.name, D1.subtype))

print("А {} относится к подтипу {}".format(D2.name, D2.subtype))

В итоге у нас получилось:

-2

2. Помимо атрибутов у экземпляра есть ещё и поведение! Поведение мы определяем так называемым «методом» - это функция, объявленные внутри тела класса. Она определяет поведение экземпляра.

Для примера поработаем с дофаминовым рецептором D1: сначала объявим класс Dopamine_receptor, пропишем атрибут класса - "дофаминовый рецептор», в методе __init__() указываем атрибуты экземпляра name (имя) и subtype (подтип):

class Dopamine_receptor:

species = "дофаминовый рецептор"

def __init__(self, name, subtype):
self.name = name
self.subtype = subtype

Теперь объявим метод экземпляра. Пусть это будет локализация данного дофаминового рецептора. В нашем случае, D1.

Дофаминовый рецептор D1 является самым широко распространённым дофаминовым рецептором в головном мозге, он синтезируется в большем количестве чем другие рецепторы. Он обнаруживается в высокой концентрации в нигростриарном, мезолимбическом и мезокортикальном путях, а именно в лобных долях, полосатом теле, чёрной субстанции, прилежащем ядре, обонятельном бугорке и миндалевидном теле (из Википедии).

Так как это длиннотекст, мы используем """ для его переноса на другие строки.

def localization(self): # Задаём метод экземпляра №2
return ("""{} является самым широко распространённым дофаминовым рецептором
в головном мозге, он синтезируется в большем
количестве чем другие рецепторы. Он обнаруживается в высокой
концентрации в нигростриарном, мезолимбическом и мезокортикальном путях,
а именно в лобных долях, полосатом теле, чёрной субстанции, прилежащем ядре,
обонятельном бугорке и миндалевидном теле.
Также в меньшей концентрации он присутствует в гиппокампе, мозжечке,
таламической и гипоталамической областях""").format(self.name)

создаем экземпляр класса

Создаем экземпляр класса Dopamine_receptor - D1:

D1 = Dopamine_receptor("D1-рецептор", "D1-подобный рецептор")

Получим доступ к атрибутам класса и экземпляра, а также вызовем метод экземпляра

print('D1 относится к классу "{}"'.format(D1.__class__.species))
print("{} относится к подтипу {}".format(D1.name, D1.subtype))

print(D1.localization())

Всё вместе:

-3

3. Атрибуты экземпляра могут создаваться буквально «на лету». Рассмотрим это теперь на примере поработаем с дофаминового рецептора D3. Сначала объявим класс Dopamine_receptor, пропишем атрибут класса - "дофаминовый рецептор», в методе __init__() указываем атрибуты экземпляра name (имя) и subtype (подтип), создадим экземпляры класса: D1, D2, D3, D4 и D5.

class Dopamine_receptor:

species = "дофаминовый рецептор"

def __init__(self, name, subtype):
self.name = name

self.subtype = subtype

D1 = Dopamine_receptor("D1-рецептор", "D1-подобных рецепторов")

D2 = Dopamine_receptor("D2-рецептор", "D2-подобных рецепторов")

D3 = Dopamine_receptor("D3-рецептор", "D2-подобных рецепторов")

D4 = Dopamine_receptor("D4-рецептор", "D2-подобных рецепторов")

D5 = Dopamine_receptor("D5-рецептор", "D1-подобных рецепторов")

Теперь, после создания экземпляра D3, припишем ему новый атрибут: пусть это будет локализация.

Рецептор D3 имеет более узкий профиль распространения, чем рецепторы, описанные выше. В наибольшей концентрации он присутствует в прилежащем ядре, обонятельном бугорке и островках Калеха. В существенно более низких концентрациях рецептор D3 обнаруживается в компактной части чёрной субстанции, вентральной области покрышки и мозжечке (из Википедии).

Опять используем "", так как текст достаточно длинный.

D3 = Dopamine_receptor("D3-рецептор", "D2-подобных рецепторов")
D3.localization = ("""{} имеет более узкий профиль распространения, чем
D1 и D2. В наибольшей концентрации он присутствует в прилежащем ядре,
обонятельном бугорке и островках Калеха. В существенно более
низких концентрациях рецептор D3 обнаруживается в компактной части чёрной
субстанции, вентральной области покрышки и мозжечке""".format(D3.name))

Получим доступ к атрибутам как класса, так и экземпляра у экземпляров D1 и D3:

print('D1 относится к классу "{}"'.format(D1.__class__.species))
print('D3 также относится к классу "{}"'.format(D3.__class__.species))
print("{} относится к подтипу {}".format(D1.name, D1.subtype))

print("А {} относится к подтипу {}".format(D3.name, D3.subtype))

И отобразим индивидуальный атрибут экземпляра D3:

print(D3.localization)

Всё вместе:

-4

Важная деталь: атрибут .localization доступен только для экземпляра D3; если мы попытаемся применить его с экземпляром, положим, D1, у нас будет ошибка:

print(D1.localization)

-5

4. Наследование — способ создания класса. Его суть заключается в том, что функциональность нового класса наследуются от уже существующего класса. Новый класс называется производным (дочерним). Существующий — базовым (родительским).

Так как дофаминовые рецепторы подразделяют на D1-подобные (D1, D5) и D2-подобные (D2, D3, D4), то, допустим, D1-подобные рецепторы уверенно могут стать дочерним классом по отношению к родительскому Dopamine_receptor:

class Dopamine_receptor:

class D1_like_receptors(Dopamine_receptor):

Родительский класс Dopamine_receptor: в методе __init__() укажем атрибут экземпляра (self), и ограничимся (здесь и далее) одним предложением ("""Основной эндогенный лиганд-агонист дофаминовых рецепторов - дофамин."""). Пропишем ещё два метода путём объявления функций def what_is_This(self) и def drug(self).

class Dopamine_receptor:
def __init__(self):
print("""Основной эндогенный лиганд-агонист
дофаминовых рецепторов - дофамин.""")
def what_is_This(self):
print("""Дофаминовые рецепторы участвуют в процессах мотивации, обучения,
тонкой моторной координации, модулирования нейроэндокринных сигналов.""")
def drug(self):
print("""Дофаминовые рецепторы являются мишенями для
множества лекарственных препаратов. Подавляющее большинство
антипсихотиков — антагонисты рецепторов дофамина, а психостимуляторы
зачастую косвенно их активируют.""")

Теперь дочерний класс: class D1_like_receptors(Dopamine_receptor) - пропишем метод__init__(self), и сделаем вот что: используем функцию super() внутри метода __init__(). Это позволяет запускать метод __init__() родительского класса внутри дочернего. Также укажем методы def what_is_This(self) (!название метода совпадает с родительским!) и def gene(self):

class D1_like_receptors(Dopamine_receptor):
def __init__(self):
super().__init__()
print("""D1-подобные рецепторы активируют G-белки семейства Gαs/olf, которые в
свою очередь активируют аденилатциклазу""")
def what_is_This(self):
print("""D1-подобные рецепторы обнаруживаются только
на постсинаптических мембранах клеток, чувствительных к дофамину.""")
def gene(self):
print("""Гены D1-подобных рецепторов не содержат интронов, поэтому

D1- и D5-рецепторы существуют в единственном сплайс-варианте.""")

Объявим переменную как экземпляр дочернего класса D1_like_receptors:

D1 = D1_like_receptors()

И посмотрим, как можно через D1. вызвать методы как родительского, так и дочернего класса:

D1 = D1_like_receptors() - отображаются атрибуты __init__() обоих классов
D1.what_is_This() - несмотря на то, что название совпадает с названием метода родительского класса, отображается метод дочернего класса)
D1.drug()
D1.gene()

Суммируя написанное:

-6

5. Инкапсуляция - ограничение доступа к методам и переменным, что позволяет предотвратить модификацию данных. Как это работает?

Дофаминовых рецепторов насчитываю пять типов.

Этот класс включает пять типов рецепторов: D1, D2, D3, D4 и D5 (из Википедии).

Этот факт мы хотим отобразить. Объявим класс Dopamine_receptor. В методе __init__() указываем в качестве атрибута экземпляра self.__number. И приравниваем его к «5», так как рецепторов - 5 разновидностей. Обратим внимание, что нижним подчеркиванием: одинарным _ или двойным __,выделяются именно приватные атрибуты (не подлежат изменению).

class Dopamine_receptor:
def __init__(self):
self.__number = 5

Объявим метод экземпляра с помощью функции def whatIsNumber(), которая принимаем на вход число дофаминовых рецепторов. Которое, как мы помним, не подлежит изменению:

def whatIsNumber(self):
print(('Класс "дофаминовые рецепторы" включает в себя {} типов рецепторов').format(self.__number))

Cоздадим экземпляр D класса Dopamine_receptor. Получим доступ к атрибуту этого экземпляра, прописанному в методе __init__() - число дофаминовых рецепторов. Для этого вызовем метод def whatIsNumber() экземпляра:

D = Dopamine_receptor()
D.whatIsNumber()

Есть деталь - дофаминовых рецепторов может быть не пять, а семь!

Предполагается наличие рецепторов D6 и D7, но их существование пока не доказано (из Википедии).

В связи с этим попробуем изменить атрибут экземпляра D, который находится внутри метода __init__(), и поменять __number с «5» на «7». Воспользуемся методом .whatIsNumber(), чтобы посмотреть, что получится.

D.__number = 7

D.whatIsNumber()

А ничего не получится:

-7

Дофаминовых рецепторов по-прежнему «5»!

Чтобы всё-таки исправить число рецепторов, объявим для этого специальную функцию def set_whatIsNumber(self, number)

def set_whatIsNumber(self, number):

Аргумент number (!его название совпадает с тем, что задано в __init__!) можно будет задать самостоятельно:

def set_whatIsNumber(self, number):
self.__number = number

Зададим аргумент, равный «7», и вызовем метод .whatIsNumber():

D.set_whatIsNumber(7)
D.whatIsNumber()

Всё получилось!

-8

Суммируя сказанное:

-9

6. Так как дофаминовые рецепторы бывают D1-и D2-подобными, то почему бы не рассмотреть на их примере, как работает полиморфизм?

Полиморфизм — один из ключевых принципов ООП, который позволяет объектам разных классов иметь одинаковый интерфейс (то есть одинаковые методы) и вести себя по-разному в зависимости от конкретного класса.

Объявим два класса, и заодно пропишем атрибуты этих классов:

class D1_like_receptor:

species_1 = "D1-подобный рецептор"

class D2_like_receptor:

species_2 = "D2-подобный рецептор"

Про D1-подобные рецепторы:

Характерной особенностью рецепторов этого класса является то, что они активируют G-белки семейства Gαs/olf, которые в свою очередь активируют аденилатциклазу (из Википедии).

Про D2-подобные рецепторы:

Эти рецепторы связываются с G-белками семейства Gαi/o и поэтому ингибируют аденилатциклазу (из Википедии).

Теперь зададим общие для двух классов методы def G() и def Adenylate_cyclase(). Функции у них - разные, соответственно, они определяют разное (в данном случае противоположное) поведение экземпляра (какое - вытекает из текста выше).

def G(self):

print("Семейство G-белков, которое активирует этот рецептор: Gαs/olf;")
def Adenylate_cyclase(self):
print("Аденилатциклаза: активируется.")
def G(self):
print("Семейство G-белков, которое активирует этот рецептор: Gαi/o;")
def Adenylate_cyclase(self):
print("Аденилатциклаза: ингибируется.")

Для использование полиморфизма создадим общий интерфейс — функцию def mechanism(Dopamine_receptor). В качестве аргумента она принимает любой объект, после чего происходит вызов его собственных методов, описанных в def G() и def Adenylate_cyclase(). Так как мы будем вносить туда только разновидности дофаминовых рецепторов, так и назовём этот аргумент Dopamine_receptor)

def mechanism(Dopamine_receptor):
Dopamine_receptor.G()
Dopamine_receptor.Adenylate_cyclase()

Зададим экземпляры D1 и D2 (рецепторы) как представители своего класса D1_like_receptor и D2_like_receptor соответственно:

D1 = D1_like_receptor()
D2 = D2_like_receptor()

…и опишем сначала D1, потом D2, по схеме 1) доступ к атрибуту класса, 2)механизм действия - поведение экземпляров, описанное в def G() и def Adenylate_cyclase():

print('D1 относится к классу "{}"'.format(D1.__class__.species_1))

mechanism(D1)

print('D2 относится к классу "{}"'.format(D2.__class__.species_2))

mechanism(D2)

Суммируя всё, получаем:

-10