Pull to refresh

Comments 16

Экземпляр класса - это же инстанс, ну когда память под класс выделили, так? А без экземпляра класс просто тип бестелесный, да?

Полагаю что нет. Как минимум, есть инстанс типа класса

Да, экземпляр класса - это инстанс этого класса. Что вы подразумеваете под бестелестностью? То, что у него нет ни полей, ни методов? Это не так. Все классы наследуются как минимум от object и обладают его атрибутами. Самое простое это магический метод __init__, а из полей можно привести в пример переменную __doc__. А экземпляры класса никак не влияют на его атрибуты.

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

Нет. В питоне у класса есть инстанс, по сути обычный объект с незначительными нюансами. Как бы статик методы на это намекают.

А про какой вы язык говорите? Если объяснять как дело обстоит в питоне, то можно привести следующий код:

>>> class MyClass:
    	class_attribute = "Hello"

    	@classmethod
    	def class_method(cls):
    		print("This is a class method")

    	def instance_method(self):
    		print("This is an instance method")

		
>>> MyClass.class_attribute
'Hello'
>>> MyClass.class_method()
This is a class method
>>> MyClass.instance_method(object)
This is an instance method

У нас нет экземпляра, но мы можем получить доступ как к полям, так и методам класса. И даже к методам экземпляра (на это указывает параметр self), однако надо передать явно ссылку, потому что когда метод экземпляра вызывает от экземпляра, то в него автоматически (неявно) передается ссылка на этот объект. Здесь, для работы функции, ссылка не важна и передаем ее просто для того, чтобы у нас не поднялось исключение.

Изучение ООП питона после C++ - тот ещё кошмар... А статья полезная: кратко, четко, лаконично. Спасибо!

Насколько метаклассы эффективны? Сами по себе или в контексте их использования где-то в коде? Конечно, если можно их не использовать, то лучше поискать аналог без них. Потому что они, как минимум, усложняют читабельность.

Метаклассы они для библиотек. Например, ABC удобно использовать для документации и автоматических проверок. А под капотом там метакласс. Использовать метаклассы можно и нужно (обычно это происходит неявно), а вот писать стоит пореже.

Может возникнуть заблуждение, что если класс A является экземпляром класса B (то есть isinstance(A, B) равно True), то можно создать экземпляры класса A с помощью класса B. Однако это не всегда верно.

Это вообще не верно

Класс А является экземпляром класса B. Это значит что B - метакласс. Класс int - экземпляр класса type. Очевидно что 3 и 7 нельзя создать с помощью класса type.

Возможно вы имели в виду "если объект А ... можно создать объект А и аналогичные ему"

Это заблуждение очень просто развеять на бытовом примере

d = Dog()
isinstance(d, Animal) == True

Очевидно что d нельзя создать с помощью только класса Animal, это его наследник.

Когда рассматриваем экземпляры (кто кого инстанцирует)

isinstance не отвечает на вопрос "кто кого инстанцирует"(!), он отвечает на вопрос "есть ли между первым аргументом и вторым is-a relationship", "может ли А быть интерпретировано как экземпляр класса B". И это снимает существенную часть вопросов - int это класс (тип), экземпляр класса type, а тот - наследник object'а. Очевидно, int можно, например, подставить в функцию которая принимает object.

Да, вы правы, здесь вообще лучше убрать упоминание о классах. Имелось в виду, что если функция isinstance возвращает True, то это еще не говорит о том, что первый объект экземпляр второго.

Очевидно что d нельзя создать с помощью только класса Animal, это его наследник.

Вы, верно, ошиблись. d не наследник Animal. Dog наследник Animal как я понял. И тут вы показали пример, о котором говорю и я. isinstance возвращает True, но второй аргумент не порождает первый.

isinstance не отвечает на вопрос "кто кого инстанцирует"(!)

В статье не было так написано. Я наоборот писал следующее:

Хотя если дословно переводить название функции (является экземпляром/есть экземпляр) ... При этом будет ошибкой как в наследовании сказать, что type порождает объекты целого типа ...

И я специально обозначил, что эта схема довольно условна. Говорится только о том, что и в каком порядке порождает объекты.

Не понял это:

он отвечает на вопрос ... "может ли А быть интерпретировано как экземпляр класса B" .

И что вы действительно думаете, что int может интерпретироваться как экземпляр object? int наследник object и не более.

Метакласс в двух словах: хук для создания класса. Другими словами возможность создать класс программно, а не декларативно.

Спасибо за поднятие темы еще раз в этом месяце. Могу отметить, что к пониманию, что такое метаклассы, так и не подобрались. И только в комментариях @Andrey_Solomatin наконец-то дал максимально близкое объяснение. Поблагодарил его отдельно.

Повторяя свой комментарий из соседней статьи. Метакласс это объект, который уточняет поведение какого либо другого класса, и метакласс, как и любой объект python, можно создать runtime (вопреки утверждению в статье):

MyMetaclass = type('MyMetaClass', (type,), {})

Управлять поведением класса и экземплярами класса можно несколькими способами: через декоратор, через наследование, через метакласс. Так в чем же разница?

  • Метакласс - официальный способ вклиниться в код ДО объявления класса. Это в статье отмечено, но не подчеркнуто, а ведь это единственное существенное отличие.

  • Декоратор класса: может донастраивать класс ПОСЛЕ объявления, поскольку получает на вход уже объявленный класс.

  • Родительский класс - уточняет поведение класса или экземпляров в runtime, предоставляя доступ к атрибутам и методам как напрямую так и через вызов super.

Именно хук beforeCreateClass и является тем важным инструментом метакласса, ради чего нужны метаклассы. И вот именно этот хук используется в ABC, хотя лучше бы использовать Protocol. Не реализовал метод протокола - лови Exception ДО создания класса на старте а не в runtime. Но это тоже шито белыми нитками из-за возможности объявления классов в runtime. Именно поэтому я категорически против Protocols/ABC, поскольку они способны добавить более сложные ошибки в код вместо упрощения.

Причина использования Metaclass в Django аналогична. На объявлении класса модели происходит внесение модели в реестр моделей (django.apps.apps.all_models). Последнее можно было бы решить более стандартно, например, через сигналы, но что сделано - то сделано.

В остальном по статье - утверждение "в Python все является объектом" намного глубже, чем может показаться на первый взгляд, и желаю автору добраться до настоящего понимания этого высказывания. Для этого, вероятно, стоит посмотреть повнимательнее внутрь cpython/Objects/typeobject.c

Спасибо за пример, что метаклассы действительно можно создавать динамически. Поправлю в статье. Можно ли использовать в статье ваши слова о том, что можно управлять поведением класса разными способами?

да, пожалуйста. Посмотри ещё соседнюю статью про метаклассы, там тоже интересно и обсуждение активное.

Sign up to leave a comment.

Articles