覆盖数字魔法作为classmethod

发布于 2025-02-09 10:11:16 字数 1074 浏览 0 评论 0原文

我尝试使用Metaclass为几个类实现数字魔法方法,然后在“类实例”中覆盖其中的一些方法。

from abc import ABCMeta
class Meta(ABCMeta):
  def __add__(self, other):
    print('meta')

class C(metaclass=Meta):
  @classmethod
  def __add__(cls, other):
    print('C')

C + 3 # meta
C.__add__(3) # C

它表明+操作员与Meta's __添加__直接调用,但c。 > getAttr(c,'__ADD __')并正确使用Overriden类方法。
我尝试了几个代码来确认这一点。

class Meta(ABCMeta):
  def call(self):
    print('meta')

class C(metaclass=Meta):
  @classmethod
  def call(cls):
    print('C')

C.call() # C
class C:
  @classmethod
  def __add__(cls, other):
    print('C')

C + 3 # TypeError
C.__add__(3) # C

我猜我“注册”我对__添加__的暗示时会发生一些特殊的事情,因此Decorator @ClassMethod不起作用。
那么,Python如何评估c + 3的表达式?如果我想覆盖__添加__ c,除了从meta继承其他元口外,还有其他解决方案吗?

I try to use metaclass to implement numeric magic methods for several classes, then override some of them in the "class instance".

from abc import ABCMeta
class Meta(ABCMeta):
  def __add__(self, other):
    print('meta')

class C(metaclass=Meta):
  @classmethod
  def __add__(cls, other):
    print('C')

C + 3 # meta
C.__add__(3) # C

It shows that the + operator is directly called with Meta's __add__, but C.__add__ calls getattr(C, '__add__') and correctly use the overriden class method.
I've tried several code pieces to confirm that.

class Meta(ABCMeta):
  def call(self):
    print('meta')

class C(metaclass=Meta):
  @classmethod
  def call(cls):
    print('C')

C.call() # C
class C:
  @classmethod
  def __add__(cls, other):
    print('C')

C + 3 # TypeError
C.__add__(3) # C

I guess something special happends when I "register" my implmentation of __add__, so the decorator @classmethod does not work.
So, how does python evaluates the expression C + 3? If I want to override __add__ for C, is there any solution other than inherit another metaclass from Meta?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

楠木可依 2025-02-16 10:11:17

那么,Python如何评估表达式C + 3?

这里发生的是Python的方法和属性搜索优先级不同于普通方法(例如call),以及通过使用操作员(例如__添加__

,以后,Python直接将添加到添加实例类的插槽中。也就是说:当您将“ C”与+运算符一起使用时,其类是“元”,meta .__添加__被调用。

在普通属性中,使用符号(c.call,甚至c .__添加__(使用+),属性访问的正常规则 - 遵循对象中实现的。 /70590552/hy-do-getting-a级 - 阶级 - 统计 - and-instance-raise-an-attributeError/70593783#70593783>这个答案。但简而言之:对于虚线访问,在“ class'Class”中定义的方法之前检索了类“实例”中的类别(就像__ dict dict of the a a a a a a a class'class''普通实例“与同类中的相同属性相比)。

至于:“如果我想覆盖__添加__,除了从Meta继承另一个Metaclass外,还有其他解决方案吗?”

“显而易见的方法”是为每个类别提供一个单独的元素,您要实现“类__添加__”的方法。但是,您可以编写meta。它。

from abc import ABCMeta

class Meta(ABCMeta):
    def __add__(cls, other):
        print('meta')
        cls_add = getattr(cls, "__add__", None)
        if not cls_add:
            return NotImplemented    
        # checks for __add__ both as an ordinary and as a classmethod
        if (unbound:= getattr(method, "__func__", None)) is not  None and unbound is __class__.__add__ :
            # getattr returned an __add__ method from the metaclass (this very same method here)
            raise NotImplemented
        if unbound:  # if this is not None, __add__ is a class method
            return method(other)
        return method(cls, other) # __add__ is an ordinary method, and we have to fill the 'self' parameter with cls

So, how does python evaluates the expression C + 3?

What takes place here is that Python's method and attribute search priority are different from ordinary methods (like call), and methods that are intended to be called indirectly by the language, through the use of an operator (like __add__)

For the later, Python defers directly to the slot in the class of the instance being added. That is: When you use "C" with the + operator, its class is "Meta", and Meta.__add__ is called.

In an ordinary attribute access using the . notation (either C.call or even C.__add__(insteaf of using +)), the normal rules for attribute access - which are implemented in object.__getattribute__ are followed - I've summarized the precedence in this answer. But in short: for dotted access, the classmethod in the class "instance" is retrieved before the method defined in the "class'class" (just as would happen for an attribute in the __dict__ of an "ordinary instance" compared to the same attribute in its class).

As for: "If I want to override __add__ for C, is there any solution other than inherit another metaclass from Meta?"

The "obvious way" would be to have a separate metaclass for each class you want to implement a "class __add__" method to. However, you can write Meta.__add__ so that it, upon being called, check for the existence of an __add__ method in the class, and forwards the execution of the opertation to it.

from abc import ABCMeta

class Meta(ABCMeta):
    def __add__(cls, other):
        print('meta')
        cls_add = getattr(cls, "__add__", None)
        if not cls_add:
            return NotImplemented    
        # checks for __add__ both as an ordinary and as a classmethod
        if (unbound:= getattr(method, "__func__", None)) is not  None and unbound is __class__.__add__ :
            # getattr returned an __add__ method from the metaclass (this very same method here)
            raise NotImplemented
        if unbound:  # if this is not None, __add__ is a class method
            return method(other)
        return method(cls, other) # __add__ is an ordinary method, and we have to fill the 'self' parameter with cls
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文