Классы в Python
Давайте посмотрим на следующий код:
class BaseClass:
def __init__(self):
print("In BaseClass constructor")
class SubClass(BaseClass):
def __init__(self, value):
super(SubClass, self).__init__()
self.value = value
def __getattr__(self, name):
print("Cannot found: %s" % name)
c = SubClass(7)
print(c.value)
Какие основные отличия от PHP мы можем выделить:
- self используется вместо $this и обращение всегда происходит через точку. При этом self обязан быть первым аргументом во всех методах (вернее, почти во всех). Идея здесь заключается в том, что Python во все методы передаёт первым аргументом указатель на сам объект (его, кстати, можно ловить в переменную с любым именем).
- Как и в PHP, здесь есть аналог магических имён. Вместо __construct — __init__. Вместо __get — __getattr__ и т.д.
- Не нужен new. Создать экземпляр класса — все равно, что вызвать функцию.
- Более громоздкое обращение к родительскому методу. С super надо постоянно помнить, что там и куда. parent:: в PHP — всё же более элегантная конструкция.
О чем еще следует сказать:
- Можно наследовать более чем один класс.
- Нет public, protected, private. Питон позволяет в runtime менять структуру экземпляра, да и сам класс обычным присваиванием, поэтому от какой-либо защиты решено было отказаться. По этой же причине не нужен и Reflection. Есть только аналог protected — если перед именем написать двойное подчеркивание. Но это просто меняет имя переменной/метода снаружи на неблагозвучное _%ClassName%__%varname%, и по нему прекрасно можно напрямую работать со скрытым.
- Нет static, финальных классов, абстрактных классов и интерфейсов. В Python более простая объектная модель в целом. Вместо Singleton у вас скорее всего будет файл со всем необходимым функционалом или файл, который при импорте будет возвращать один и тот же экземпляр. Вместо интерфейса вы скорее всего напишете класс, который бросает исключения на методы, которые забудут переопределить.
- Чистое ООП не приветствуется. Как бы странно это ни звучало, но благодаря тому, что всё и так объект (даже bool), а также потому, что в синтаксисе нет разных операторов для обращения к методу или функции из импортированного файла, любое обращения идёт через точку. Так вот, благодаря всему этому задача инкапсуляции решается не только через ООП. Поэтому в большинстве проектов классы пишутся только там, где они нужны.