python-3.x 在__get__、__getattr__和__getattribute__之间做出选择的经验法则是什么?

qxsslcnc  于 2023-04-22  发布在  Python
关注(0)|答案(2)|浏览(117)

在给定的类中,在给定的情况下,选择实现哪一个的一般经验法则是什么?
我已经阅读了这些文档,因此理解了它们之间的区别。相反,我正在寻找如何最好地将它们的使用集成到我的工作流程中的指导,以便更好地注意到使用它们的更微妙的机会,以及何时使用它们。这类事情。有问题的方法是(据我所知):

## fallback
__getattr__
__setattr__
__delattr__
## full control
__getattribute__
##(no __setattribute__ ? What's the deal there?)
## (the descriptor protocol)
__get__
__set__
__delete__
ecr0jaav

ecr0jaav1#

__setattribute__不存在,因为__setattr__ * 总是 * 被调用。__getattr__仅在通过正常通道(由__getattribute__提供,因此该函数同样总是被调用)查找属性失败时才为f.x调用。
描述符协议与其他协议稍微正交。

class Foo(object):
    def __init__(self):
        self.x = 5

f = Foo()

以下是正确的:

  • 如果定义了__getattribute__,则f.x将调用f.__getattribute__('x')
  • 如果定义了__getattr__,则f.x不会调用f.__getattr__('x')
  • 如果定义了__getattr__,则f.y将调用f.__getattr__('y');如果定义了__getattribute__,则f.__getattribute__('y')将调用f.__getattribute__('y')

描述符是由一个属性调用的,而不是为一个属性调用的。即:

class MyDescriptor(object):
    def __get__(...):
        pass
    def __set__(...):
        pass

class Foo(object):
    x = MyDescriptor()

f = Foo()

现在,f.x将导致调用type(f).__dict__['x'].__get__,而f.x = 3将调用type(f).__dict__['x'].__set__(3)
也就是说,Foo.__getattr__Foo.__getattribute__将用于查找f.x * 引用的内容 *;一旦你有了它,f.x会产生type(f.x).__get__()的结果(如果定义了),而f.x = y会调用f.x.__set__(y)(如果定义了)。
(The上面对__get____set__的调用只是大致正确的,因为我已经省略了__get____set__实际接收的参数的细节,但这应该足以解释__get____getattr[ibute]__之间的差异。
换句话说,如果MyDescriptor没有定义__get__,那么f.x将简单地返回MyDescriptor的示例。

piztneat

piztneat2#

关于__getattr____getattribute__,请参见Difference between getattr vs getattribute示例。
__get__并没有真正相关。我将引用official documentation for the descriptor protocol在这里:
属性访问的默认行为是从对象的字典中获取、设置或删除属性。例如,a.x有一个查找链,从a.__dict__['x']开始,然后是type(a).__dict__['x'],并继续通过type(a)的基类(不包括元类)。如果查找的值是定义描述符方法之一的对象,那么Python可能会覆盖默认行为,转而调用描述符方法。这在优先级链中的位置取决于定义了哪些描述符方法。
__get__的目的是控制通过“查找链”找到a.x后发生的事情(例如,创建一个方法对象,而不是返回通过type(a).__dict__['x']找到的普通函数);__getattr____getattribute__的目的是改变查找链本身。
这里没有__setattribute__,因为只有一种方法可以真正设置对象的属性,你可能想在设置属性时“神奇地”发生其他事情;但是__setattr__涵盖了这一点。__setattribute__不可能提供任何__setattr__还没有的功能。
然而,在绝大多数情况下,最好的答案是甚至不要考虑使用这些工具。首先看看更高级别的抽象,如property s、classmethod s和staticmethod s。如果您认为需要这样的专用工具,而自己又不能弄清楚,那么很有可能您的想法是错误的;但无论如何,在这种情况下,最好发布一个更具体的问题。

相关问题