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

时间:2014-09-12 12:35:25

标签: python python-3.x

在给定的情况下,选择在给定的课程中实施哪些课程有哪些一般的经验法则?

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

## fallback
__getattr__
__setattr__
__delattr__

## full control
__getattribute__
##(no __setattribute__ ? What's the deal there?)

## (the descriptor protocol)
__get__
__set__
__delete__

2 个答案:

答案 0 :(得分:7)

对于__getattr__ vs __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__,因为只有一种方法可以实际设置对象的属性。你可能想要让其他事情发生并且#34;神奇地"设置属性时;但__setattr__涵盖了这一点。 __setattribute__无法提供__setattr__尚未提供的任何功能。

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

答案 1 :(得分:7)

__setattribute__不存在,因为__setattr__ 总是被调用。如果属性查找通过正常通道(由__getattr__提供)失败,则仅f.x调用__getattribute__,因此类似地始终调用该函数。)

描述符协议与其他协议略微正交。给定

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

f = Foo()

以下是真实的:

  • f.x如果已定义,则会调用f.__getattribute__('x')
  • 如果已定义,则
  • f.x不会调用f.__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()

现在,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)(如果已定义)。

(上述对__get____set__的调用只是近似正确,因为我遗漏了__get____set__实际收到的参数的详细信息,但是这应该足以解释__get____getattr[ibute]__之间的差异。)

换句话说,如果MyDescriptor没有定义__get__,那么f.x只会返回MyDescriptor的实例。