我们如何一致地重写/重载python的点运算符“getAttribute”?

2024-10-02 04:21:15 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我们使用的是python 3.x或更新版本,而不是python 2.x

与许多语言一样,Python也有一个点运算符:

# Create a new instance of the Rectangle class
robby = Rectangle(3, 10)

# INVOKE THE DOT OPERATOR       
x = robby.length 

Python的点运算符有时被实现为^{
以下内容相当于x = robby.length

x = Rectangle.__getattribute__(robby, "length")    

但是,点运算符不是始终实现为__getattribute__

Python有“神奇的方法”
魔法方法是名称以两个下划线字符开头和结尾的任何方法。
__len__()是一个神奇方法的例子

通过执行以下代码,您可以获得大多数python神奇方法的列表:

print("\n".join(filter(lambda s: s.startswith("__"), dir(int))))

输出为:

__abs__
__add__
__and__
__bool__
__ceil__
__class__
__delattr__
__dir__
__divmod__
__doc__
__eq__
__float__
[... truncated / abridged ...]
__rtruediv__
__rxor__
__setattr__
__sizeof__
__str__
__sub__
__subclasshook__
__truediv__
__trunc__
__xor__

假设我们编写了一个名为Rectangle的类,它是object的子类。
然后,我在Rectangle类中重写object.__getattribute__的尝试通常会失败

下面显示了一个类的示例,python有时会忽略重写的点运算符:

class Klass:
    def __getattribute__(self, attr_name):
        return print

obj = Klass()

obj.append()  # WORKS FINE. `obj.append == print`
obj.delete()  # WORKS FINE. `obj.delete == print`
obj.length    # WORKS FINE
obj.x         # WORKS FINE

# None of the following work, because they
# invoke magic methods.  

# The following line is similar to:
#     x = Klass.__len__(obj)
len(obj)

# obj + 5
#     is similar to:
# x = Klass.__add__(obj, 5)
x = obj + 5

# The following line is similair to:
#     x = Klass.__radd__(obj, 2)
x = 2 + obj

重写python的点运算符的方法不止一种。
一种可读、干净且一致的方法的示例是什么

通过consistent,我的意思是在源代码中使用.时调用我们的自定义点运算符,无论该方法是否为神奇方法

我不愿意在阳光下手动输入每一种魔法方法。
我不想看到成千上万行代码,它们看起来像:

def __len__(*args, **kwargs):
    return getattr(args[0], "__len__")(*args, **kwargs)

我理解__getattr____getattribute__
之间的区别 覆盖__getattribute__而不是__getattr__而不是当前的问题


Tags: 方法objlenis运算符lengthclassfollowing
1条回答
网友
1楼 · 发布于 2024-10-02 04:21:15

__getattribute__已经完成了您实际要求的操作-覆盖__getattribute__就是处理.运算符的所有使用所需的全部操作。(严格地说,如果__getattribute__失败,Python将退回到__getattr__,但只要不实现__getattr__,就不必担心这一点。)


你说你想让你的操作符被调用“只要源代码中使用了.”,但是len+,以及你担心的所有其他事情都不要使用.。在{}、{}或{}中没有{}

大多数魔法方法查找不使用属性访问。如果您实际查找yourobj.__len__yourobj.__add__,则将通过属性访问,并且将调用__getattribute__,但是当Python查找实现语言功能的神奇方法时,它会直接搜索对象类型的MRO。不涉及.运算符

没有办法覆盖magic方法查找。这是一个没有覆盖钩子的硬编码过程。您可以做的最接近的事情是重写单个的magic方法以委托给__getattribute__,但这与重写magic方法查找(或重写.)不同,这样很容易产生无限递归错误

如果您真正想做的是避免重复的单个魔术方法重写,那么可以将它们放在类装饰器或mixin中

相关问题 更多 >

    热门问题