【问题标题】:What are some rules of thumb for deciding between __get__, __getattr__, and __getattribute__?在 __get__、__getattr__ 和 __getattribute__ 之间做出决定的一些经验法则是什么?
【发布时间】:2014-11-06 15:27:21
【问题描述】:

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

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

## fallback
__getattr__
__setattr__
__delattr__

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

## (the descriptor protocol)
__get__
__set__
__delete__

【问题讨论】:

  • 致最接近的选民:IMX,学习者问题,例如“我如何在 X 和 Y 之间做出决定?”或“X 和 Y 有什么区别?”实际上是两个问题——“X 的预期目的是什么?”和“Y 的预期目的是什么?”或许单独询问它们会更好,但在目前的情况下,两者都不是“太宽泛”的 IMO,而且这里的不同魔法方法之间至少有一些联系。

标签: python python-3.x


【解决方案1】:

__setattribute__ 不存在,因为__setattr__总是被调用。 __getattr__ 仅在通过普通通道(由__getattribute__ 提供,因此同样始终调用该函数)的属性查找失败时才为f.x 调用。

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

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') 如果 已定义。

描述符是由 一个属性调用的,而不是for 一个属性。那就是:

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 的实例。

【讨论】:

  • 哦..我现在明白了。感谢您使这些联系更加清晰。有什么方法可以制作x = 3(通过限定方法附加到的对象?)
  • 但是,现在我已经玩了一点。我认为 getattribute 正是我所需要的。我的用例是无论如何它都在集合中,所以我认为这会起作用。谢谢。
  • 并重新阅读您非常好的答案,并且该编辑有所帮助。事实上,我可以做我想做的事。 (具有不必限定对象的语法)通过定义MyDescriptor,将其设置为x,然后执行分配x = 3。甜的!。谢谢。
  • 似乎无法创建描述符并在地面使用它? (在口译会话中)
  • 对;只有在访问类实例的属性时才会调用描述符协议。
【解决方案2】:

对于__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__ 尚未提供的任何功能。

但是,在绝大多数情况下,最好的答案是不要考虑使用其中任何一种。首先查看更高级别的抽象,例如propertys、classmethods 和staticmethods。如果您认为自己需要这样的专用工具,但自己无法弄清楚,那么您的想法很可能是错误的;但无论如何,在这种情况下最好发布一个更具体的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 2020-01-04
    相关资源
    最近更新 更多