有没有办法在 Python 中调用子类定义的方法?
Is there a way to call a method on definition of a subclass in Python?
__init__
方法定义了在创建 class 的实例时要执行的操作。创建 subclass 时我可以做一些等效的事情吗?
假设我有摘要 class Entity
:
class Entity:
def __onsubclasscreation__(cls):
for var in cls.__annotations__:
cls.__dict__[var] = property(lambda self:self.vars[var])
这意味着每当我定义一个继承自 Entity
的新 class 时,该 class 的所有注释变量都会收到 getter:
class Train(Entity):
wagons: int
color: str
>>> t = Train()
>>> t.vars["wagons"] = 5
>>> t.wagons
5
我无法在实例化时执行此操作,因为需要在 class 中定义属性,而且我无法在 superclass 中执行此操作,因为我不知道哪些属性将需要。有没有办法在 subclass 创建时动态地做一些事情?
您描述的是 __init_subclass__
钩子 (docs) 的基本用法:
Whenever a class inherits from another class, __init_subclass__
is called on that class. This way, it is possible to write classes which change the behavior of subclasses.
>>> class A:
... def __init_subclass__(cls):
... print(f"init {cls}")
...
>>> class B(A):
... pass
...
init <class '__main__.B'>
有关详细信息,请参阅 PEP 487 -- Simpler customisation of class creation。
注意:这是 3.6+ 的功能。在旧的 Python 版本中,使用元类 __new__
实现相同的:
>>> class MyMeta(type):
... def __new__(meta, name, bases, class_dict):
... print("MyMeta.__new__", meta, name, bases, class_dict)
... return type.__new__(meta, name, bases, class_dict)
...
>>> class A(metaclass=MyMeta):
... pass
...
MyMeta.__new__ <class '__main__.MyMeta'> A () {'__module__': '__main__', '__qualname__': 'A'}
>>> class B(A):
... pass
...
MyMeta.__new__ <class '__main__.MyMeta'> B (<class '__main__.A'>,) {'__module__': '__main__', '__qualname__': 'B'}
您可以将此功能抽象为另一个方法,然后从超类的构造函数中调用该方法。如果子类调用超类的构造函数(它们应该调用),那么该方法将在实例化子类时执行。
class Entity:
@classmethod
def _onsubclasscreation(cls):
for var in cls.__annotations__:
cls.__dict__[var] = property(lambda self:self.vars[var])
def __init__(self):
...
self.__class__._onsubclasscreation()
然后,只要子类不覆盖 _onsubclasscreation()
的功能,行为应该符合预期。
__init__
方法定义了在创建 class 的实例时要执行的操作。创建 subclass 时我可以做一些等效的事情吗?
假设我有摘要 class Entity
:
class Entity:
def __onsubclasscreation__(cls):
for var in cls.__annotations__:
cls.__dict__[var] = property(lambda self:self.vars[var])
这意味着每当我定义一个继承自 Entity
的新 class 时,该 class 的所有注释变量都会收到 getter:
class Train(Entity):
wagons: int
color: str
>>> t = Train()
>>> t.vars["wagons"] = 5
>>> t.wagons
5
我无法在实例化时执行此操作,因为需要在 class 中定义属性,而且我无法在 superclass 中执行此操作,因为我不知道哪些属性将需要。有没有办法在 subclass 创建时动态地做一些事情?
您描述的是 __init_subclass__
钩子 (docs) 的基本用法:
Whenever a class inherits from another class,
__init_subclass__
is called on that class. This way, it is possible to write classes which change the behavior of subclasses.
>>> class A:
... def __init_subclass__(cls):
... print(f"init {cls}")
...
>>> class B(A):
... pass
...
init <class '__main__.B'>
有关详细信息,请参阅 PEP 487 -- Simpler customisation of class creation。
注意:这是 3.6+ 的功能。在旧的 Python 版本中,使用元类 __new__
实现相同的:
>>> class MyMeta(type):
... def __new__(meta, name, bases, class_dict):
... print("MyMeta.__new__", meta, name, bases, class_dict)
... return type.__new__(meta, name, bases, class_dict)
...
>>> class A(metaclass=MyMeta):
... pass
...
MyMeta.__new__ <class '__main__.MyMeta'> A () {'__module__': '__main__', '__qualname__': 'A'}
>>> class B(A):
... pass
...
MyMeta.__new__ <class '__main__.MyMeta'> B (<class '__main__.A'>,) {'__module__': '__main__', '__qualname__': 'B'}
您可以将此功能抽象为另一个方法,然后从超类的构造函数中调用该方法。如果子类调用超类的构造函数(它们应该调用),那么该方法将在实例化子类时执行。
class Entity:
@classmethod
def _onsubclasscreation(cls):
for var in cls.__annotations__:
cls.__dict__[var] = property(lambda self:self.vars[var])
def __init__(self):
...
self.__class__._onsubclasscreation()
然后,只要子类不覆盖 _onsubclasscreation()
的功能,行为应该符合预期。