gpt4 book ai didi

python - 如何检索元类方法

转载 作者:太空宇宙 更新时间:2023-11-03 13:37:42 25 4
gpt4 key购买 nike

在 Python 中工作,元类 (metamethod) 拥有的方法如何通过它实例化的类检索?在下面的场景中,这很简单——只需使用 getattr 或点符号:

* 所有示例都使用安全版本 with_metaclass

class A(type):
class A(type):
"""a metaclass"""

def method(cls):
m = "this is a metamethod of '%s'"
print(m % cls.__name__)

class B(with_metaclass(A, object)):
"""a class"""
pass

B.method()
# prints: "this is a metamethod of 'B'"

然而,这很奇怪,因为在 dir(B) 中的任何地方都找不到 'method'。由于这个事实,动态覆盖这样的方法变得困难,因为元类不在 super 的查找链中:

class A(type):
"""a metaclass"""

def method(cls):
m = "this is a metamethod of '%s'"
print(m % cls.__name__)

class B(with_metaclass(A, object)):
"""a class"""

@classmethod
def method(cls):
super(B, cls).method()

B.method()

# raises: "AttributeError: 'super' object has no attribute 'method'"

那么,正确覆盖元方法的最简单方法是什么?我已经对这个问题提出了自己的答案,但期待任何建议或替代答案。预先感谢您的回复。

最佳答案

正如您所说,并在实践中发现,A.method 在 B 的查找链上 - 类和元类的关系不是继承关系 - 它是“实例”之一,因为类是元类的实例。

Python 是一种优秀的语言,它以预期的方式运行,很少有意外 - 在这种情况下也是一样的:如果我们处理“普通”对象,你的情况就像有一个 < em>实例 B类(class) A .和 B.method将出现在 B.__dict__ 中- 对为此类实例定义的方法进行的“ super ”调用永远无法到达 A.method - 它实际上会产生错误。作为B是一个类对象,super在 B 的方法内部 __dict__是有意义的 - 但它会搜索 B 的 __mro__类链(在本例中为 (object,) )- 这就是您所命中的。

这种情况不应该经常发生,我什至认为根本不应该发生;从语义上讲,很难在既作为元类方法又作为类本身的方法都有意义的方法中存在任何意义。此外,如果method未在 B 中重新定义请注意,它甚至不会从 B 的实例中可见(也不可调用)。

也许您的设计应该:

一个。有一个基类 Base , 使用你的元类 A , 定义 method而不是在 A 中定义它- 然后定义 class B(Base):相反

或者有元类 A而是注入(inject) method在每个class它创建,其中包含代码 __init____new__方法 - 沿:

def method(cls):
m = "this is an injected method of '%s'"
print(m % cls.__name__)

class A(type):
def __init__(cls, name, bases, dct):
setattr(cls, 'method', classmethod(method))

这将是我的首选方法 - 但它不允许一个覆盖这个 method在使用此元类的类中 -如果没有一些额外的逻辑,上面的方法宁愿覆盖任何这样的 method显在体内。更简单的是有一个基类 Base如上所述,或注入(inject)具有不同名称的方法,如 base_method在最后一个类上,并在任何重写 method 中对它进行硬编码调用:

class B(metaclass=A):
@classmethod
def method(cls):
cls.base_method()
...

(在元类的 if 上使用额外的 __init__ 以便默认 method 别名为 base_method )

您真正要求的内容从这里开始

现在,如果您真的有从类中调用元类中的方法的用例,“一个明显的”方法就是简单地对调用进行硬编码,就像在 super 存在之前所做的那样。

您可以执行以下任一操作:

class B(metaclass=A):
@classmethod
def method(cls):
A.method(cls)
...

哪个不那么动态,但不那么神奇并且更易读——或者:

class B(metaclass=A):
@classmethod
def method(cls):
cls.__class__.method(cls)
...

哪个更动态(__class__ 属性适用于 cls 就像它在 B 只是 A 的一些实例时一样有效,就像我在第二段中的示例:B.__class__ is A )

在这两种情况下,您都可以避免调用不存在的 method。在带有简单 if hasattr(cls.__class__, "method"): ... 的元类中

关于python - 如何检索元类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37128880/

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