【问题标题】:Which special methods bypasses __getattribute__ in Python?哪些特殊方法绕过了 Python 中的 __getattribute__?
【发布时间】:2012-10-04 01:45:52
【问题描述】:

除了为了正确性而绕过任何实例属性之外,隐式特殊方法查找通常还会绕过对象元类的__getattribute__()方法。

The docs提到了__hash____repr____len__等特殊方法,根据经验我知道它还包括用于Python 2.7的__iter__

引用an answer to a related question

“魔术__methods__()被特殊对待:它们被内部分配到类型数据结构中的“槽”以加快它们的查找速度,它们只在这些槽中查找。”

为了改进我对another question 的回答,我需要知道:我们具体讨论的是哪些方法?

【问题讨论】:

  • 哪些方法分配给槽?
  • 我认为每个方法都列出了here。无论如何要考虑到,这仅在您使用“其语法”调用该方法时才适用。例如a+5 不会调用__getattribute__,而a.__add__(5) 调用它。基本上,只要您使用点 (.) 访问属性,就会调用 __getattribute__
  • @Bakuriu:非常有用,谢谢。
  • @Bakuriu:你能把你的cmets放在一个答案中吗?另外,请注意 Python 3 的行为与您描述的相同,但在这一点上有更清晰的文档。
  • @Bakuriu __getattribute__ 也使用了 hasattr(obj, method) 方法

标签: python magic-methods


【解决方案1】:

您可以在 python3 documentation for object.__getattribute__ 中找到答案,其中指出:

无条件调用以实现类实例的属性访问。如果该类还定义了__getattr__(),则 除非__getattribute__() 调用后者,否则不会调用后者 显式地或引发 AttributeError。此方法应返回 (计算的)属性值或引发 AttributeError 异常。在 为了避免这种方法中的无限递归,它的实现 应该总是调用同名的基类方法来访问 它需要的任何属性,例如 object.__getattribute__(self, name)

注意

当通过语言语法或内置隐式调用查找特殊方法时,仍可能绕过此方法 职能。请参阅特殊方法查找。

this 页面也解释了这个“机器”是如何工作的。从根本上讲,__getattribute__ 仅在您使用 .(dot) 运算符访问属性时才会调用(并且正如 Zagorulkin 指出的那样,也可以通过 hasattr 访问)。

请注意,该页面未指定隐式查找哪些特殊方法,因此我认为这适用于所有方法(您可能会发现 here

【讨论】:

  • 你真的检查了吗?我确实检查了 2.7.9,但似乎文档不太正确。
【解决方案2】:

在 2.7.9 中签入

找不到任何方法绕过对__getattribute__ 的调用,使用objecttype 上的任何神奇方法:

# Preparation step: did this from the console
# magics = set(dir(object) + dir(type))
# got 38 names, for each of the names, wrote a.<that_name> to a file
# Ended up with this:

a.__module__
a.__base__
#...

把这个放在那个文件的开头,我把它重命名为一个合适的python模块(asdf.py)

global_counter = 0

class Counter(object):
    def __getattribute__(self, name):
        # this will count how many times the method was called
        global global_counter
        global_counter += 1
        return super(Counter, self).__getattribute__(name)

a = Counter()
# after this comes the list of 38 attribute accessess
a.__module__
#...
a.__repr__
#...

print global_counter  # you're not gonna like it... it printer 38

然后我还尝试通过getattrhasattr 获取每个名称 -> 相同的结果。每次都调用__getattribute__

因此,如果有人有其他想法...我懒得查看 C 代码,但我确信答案就在某个地方。

所以要么是我做的不对,要么是文档在撒谎。

【讨论】:

  • 如果我没记错的话,我的问题是关于repr(a) 而不是a.__repr__()。我已经有一段时间没有接触这些东西了,但我猜你会得到 getattribute 版本,因为你会查找属性,而我们正在谈论的内置方法(全局 repr,而不是 __repr__)绕过__repr__ 的存在。
  • 覆盖 __getattribute__ 以在调用时发出打印,然后执行:Counter('a') + Counter('a') 并查看它不打印任何内容。因为它绕过标准名称查找并直接点击Counter.__dict__['__add__']或以优化的名义进行一些愚蠢的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 2015-02-11
  • 2012-04-28
  • 1970-01-01
  • 1970-01-01
  • 2015-11-26
  • 2019-03-16
相关资源
最近更新 更多