gpt4 book ai didi

python - 修补 __init_subclass__

转载 作者:行者123 更新时间:2023-12-04 08:27:12 28 4
gpt4 key购买 nike

我在修补自定义类时遇到问题'__init_subclass__ .我认为这与我将修补函数绑定(bind)到类的方式有关:

def _patched_initsubclass(cls, **kwargs):
print(f"CLS from subclassing A: {cls}")
super(cls, cls).__init_subclass__(**kwargs)

class A: ...

A.__init_subclass__ = _patched_initsubclass.__get__(A, A)

class B(A): ... # Output: CLS from subclassing A: <class '__main__.A'>
但是,我知道正确设置 __init_subclass__应该有不同的输出:
class F:

def __init_subclass__(cls, **kwargs):
print(f"CLS from subclassing F: {cls}")
pass

class C(F): ... # Output: CLS from subclassing F: <class '__main__.C'>
cls在 super 类里' __init_subclass__子类化时定义应该是子类。我试图通过不同的 SO 帖子以及 docs 找到绑定(bind) dunder 方法的正确方法。 ,但一直没有找到正确的方法来做到这一点。

最佳答案

您对 super 的使用是无效的;它应该被传递给它被调用的类的类型(例如它被定义的类)和它被传递的实际类型(它被调用的类),所以 super(cls, cls)在撒谎;您对描述符协议(protocol)函数的显式使用__get__预绑定(bind)到 A (在 B 上调用它时绕过描述符协议(protocol)),所以它总是说“我正在从 A 调用 A ”,即使它实际上是在其他东西上调用的。
你想要的并不容易以正确的方式去做; your approach of making it a classmethod (which means it actually gets B , not A , as expected) and calling super(cls, None) , 仍然是错误的,即使它碰巧在这里起作用。你在告诉 super遍历 None 的 MRO对象并调用第一个 __init_subclass__它在 B 之后找到在 MRO 中。显然,即使 B不在 MRO 中(应该是错误 according to the docs :“如果第二个参数是对象,isinstance(obj, type) 必须为真。如果第二个参数是类型,issubclass(type2, type) 必须为真。”;c 'est la vie),它默默地返回 object.__init_subclass__并称它为;它之所以有效,是因为 object.__init_subclass__什么都不做,也不反对被叫。
正确执行此操作的唯一方法是制作 _patched_initsubclass 的新版本。对于每个要修补的类,都知道它正在修补哪个类。奖励,在执行此操作时,您可以以启用零参数 super() 的方式进行闭包通过把 __class__在新方法的闭包范围内(零参数 super() 魔术是由编译器完成的,它使引用 __class__super 的类中定义的所有函数实际上以 __class__ 闭包在闭包范围内可见)。
一个示例解决方案是:

def make_patched_initsubclass_for(__class__):  # Receive class to patch as __class__ directly
# Same as before, just defined inside function to get closure scope,
# and super() is called with no arguments
def _patched_initsubclass(cls, **kwargs):
print(f"CLS from subclassing A: {cls}")
super().__init_subclass__(**kwargs) # super() roughly equivalent to super(__class__, cls)

# Returns a classmethod so it descriptor protocol
# knows to provide class uniformly, never an instance
return classmethod(_patched_initsubclass)

class A: ...

A.__init_subclass__ = make_patched_initsubclass_for(A) # Produces valid closure for binding to A

class B(A): ... # Output CLS from subclassing A: <class '__main__.B'>
如果您没有将参数命名为 make_patched_initsubclass_for __class__ (命名为 patched_cls 或类似名称),您必须使用 super(patched_cls, cls)而不是 super() ,但无论哪种方式都可以。

关于python - 修补 __init_subclass__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65205205/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com