Дофаминовые рецепторы играют важную роль в функционировании центральной нервной системы. Основной эндогенный лиганд-агонист этих рецепторов, как видно из названия, дофамин. Дофаминовые рецепторы участвуют в процессах мотивации, обучения, тонкой моторной координации, модулирования нейроэндокринных сигналов. Этот класс включает пять типов рецепторов: 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. Помимо атрибутов у экземпляра есть ещё и поведение! Поведение мы определяем так называемым «методом» - это функция, объявленные внутри тела класса. Она определяет поведение экземпляра.
Для примера поработаем с дофаминовым рецептором 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. Атрибуты экземпляра могут создаваться буквально «на лету». Рассмотрим это теперь на примере поработаем с дофаминового рецептора 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)
Всё вместе:
Важная деталь: атрибут .localization доступен только для экземпляра D3; если мы попытаемся применить его с экземпляром, положим, D1, у нас будет ошибка:
print(D1.localization)
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()
Суммируя написанное:
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()
А ничего не получится:
Дофаминовых рецепторов по-прежнему «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()
Всё получилось!
Суммируя сказанное:
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)
Суммируя всё, получаем: