В мире Python почти все изменяемо.
Начало
метод класса__init_subclass__от3.6(whatsnew3.6) вводится для того, чтобы поведение подклассов можно было изменить без использования метакласса. Другими словами, он не зависит от программирования метаклассов, а также может обеспечивать средства редактирования других классов. Итак, как это понять?
Начните с примера
согласно св документеПример:
class Philosopher:
def __init_subclass__(cls, default_name, **kwargs):
super().__init_subclass__(**kwargs)
cls.default_name = default_name
class AustralianPhilosopher(Philosopher, default_name="Bruce"):
pass
В примере, когда подкласс наследуетPhilosopher,Так__init_subclass__будет называться. Содержание тоже очень простое, родительский классPhilosopherАтрибут default_name устанавливается для всех его подклассов.
__init_subclass__Подобно функции ловушки, которая срабатывает при определении подкласса.
Реализация по умолчаниюobject.__init_subclass__Ничего не делать. Но реализация по умолчанию не может передавать никакие параметры, иначе будет сообщено об ошибке.
Стоит отметить, что в примере__init_subclass__Первый параметрclsвместо общегоself. Это потому, что этот метод неявно@classmethodУкрасить(PEP-487). Это решение на самом деле связано с тем, что большинство людей забывают дать__prepare__плюс@classmethodУкрашено, создавая плохой пользовательский опыт; и в другом PEP__prepare__Он задокументирован как общий метод, поэтому его трудно изменить. И как новый метод в 3.6__init_subclass__Таким образом, есть причина для неявного декорирования (на самом деле я предпочитаю явное, потому что «явное лучше, чем неявное», как упоминается в Zen of Python).
Пользовательские шаги после создания объекта класса
несмотря на то что__init_subclass__не зависит от программирования метаклассов, но классы определяются метаклассом по умолчаниюtypeсоздан, затем вtype.__new__()Каковы шаги после создания класса:
- первый,
type.__new__Коллекция определений пространств имен классовset_name()все дескрипторы метода; - Во-вторых, эти
__set_name__Конкретный дескриптор вызывается в конкретном случае; - Наконец, вызовите хук в родительском классе.
__init_subclass__().
Если класс украшен декоратором, то передайте сгенерированный выше объект декоратору класса.
Суммировать
В целом,__init_subclass__()Это функция ловушки, она решает проблему того, как сообщить родительскому классу, что он унаследован. Хуки могут изменить поведение класса, не прибегая к метаклассам или декораторам классов. Хуки также проще в использовании и понятнее.
Хотя в этой статье также упоминается__set_name__, но это и__init_subclass__не связанные друг с другом,__set_name__В основном, чтобы решить, как сообщить дескриптору имя своего атрибута.
__init_subclass__Цель состоит в том, чтобы предоставить более простой способ настройки, а в простых сценариях — альтернативу метаклассам. Стоит попробовать.