决定__get __,__ getattr__和__getattribute__之间的一些经验法则是什么?

Inv*_*sus 8 python python-3.x

在特定情况下,选择在给定类中实现哪些内容的一般经验法则是什么?

我已经阅读了文档,因此理解它们之间的区别.相反,我正在寻找关于如何最好地将他们的使用集成到我的工作流程中的指导,方法是更好地注意到使用它们的更微妙的机会,以及何时使用它们.那种事.有问题的方法是(据我所知):

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

Kar*_*tel 7

对于__getattr__vs __getattribute__,请参阅__getattr__与__getattribute__之间的差异.

__get__并不是真的有关系.我将在这里引用描述符协议官方文档:

属性访问的默认行为是从对象的字典中获取,设置或删除属性.例如,ax具有一个查找链,从查找链开始a.__dict__['x'],然后type(a).__dict__['x']继续通过type(a)排除元类的基类.如果查找的值是定义其中一个描述符方法的对象,则Python可以覆盖默认行为并调用描述符方法.在优先级链中发生这种情况取决于定义了哪些描述符方法.

目的__get__是控制a.x通过"查找链"找到的事件(例如,创建方法对象而不是返回通过其发现的普通函数type(a).__dict__['x']); 改变查找链本身的目的__getattr__和目的__getattribute__.

没有,__setattribute__因为只有一种方法可以在引擎盖下实际设置对象的属性.您可能希望在设置属性时"神奇地"使其他事情发生; 但__setattr__涵盖了那些.__setattribute__无法提供任何尚未提供的功能__setattr__.

然而 - 在绝大多数情况下,最好的答案是甚至不考虑使用其中任何一种.首先看一下更高级别的抽象,比如propertys,classmethods和staticmethods.如果您认为自己需要这样的专业工具,并且无法自己解决这个问题,那么您的思维很可能是错的.但无论如何,最好在这种情况下发布一个更具体的问题.


che*_*ner 7

__setattribute__不存在,因为__setattr__一直叫.__getattr__f.x当属性查找通过正常通道(由其提供__getattribute__,因此类似地始终调用)失败时才会调用.

描述符协议与其他协议略微正交.特定

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

f = Foo()
Run Code Online (Sandbox Code Playgroud)

以下是真实的:

  • f.xf.__getattribute__('x')如果定义了会调用.
  • f.xf.__getattr__('x')如果已定义则不会调用.
  • f.y将调用f.__getattr__('y'),如果它被定义,否则 f.__getattribute__('y'),如果被定义.

该描述符调用一个属性,而不是一个属性.那是:

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

class Foo(object):
    x = MyDescriptor()

f = Foo()
Run Code Online (Sandbox Code Playgroud)

现在,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__()if定义的结果,并在定义时f.x = y调用f.x.__set__(y).

(以上调用__get____set__仅约正确的,因为我已经离开了的什么样的参数细节__get____set__实际收到,但这应该足以解释之间的差异__get____getattr[ibute]__.)

换句话说,如果MyDescriptor没有定义__get__,那么f.x就会简单地返回实例MyDescriptor.