如何在__getattr__中区分hasattr和普通属性访问?

时间:2013-09-14 03:09:04

标签: python

class a_class:
    def __getattr__(self, name):
        # if called by hasattr(a, 'b') not by a.b
        # print("I am called by hasattr")
        print(name)

a = a_class()
a.b_attr

hasattr(a, 'c_attr')

请查看__getattr__内的评论。我怎么做?我正在使用Python 3.原因是我想动态创建属性但我不想在使用hasattr时这样做。感谢。

2 个答案:

答案 0 :(得分:10)

你不能没有作弊。正如the documentation所说:

  

这个[hasattr]是通过调用getattr(object, name)并查看是否引发异常来实现的。

换句话说,如果不阻止hasattr,则无法阻止getattr,这基本上意味着如果您关心访问属性,则根本无法阻止hasattr

通过“作弊”我的意思是这些解决方案中的一个,聪明的人喜欢在这里发布涉及基本上所有Python的最终运行。它们通常涉及重新分配内置函数,检查/操作调用堆栈,使用内省来查看文字源代码,修改对象的“秘密”内部属性​​等等。例如,您可以查看调用堆栈以查看调用链中是否有hasattr。这种类型的解决方案是可能的,但是非常脆弱,可能会在未来的Python版本中破坏,在非CPython实现上,或者在使用另一个同样丑陋和狡猾的黑客的情况下。

您可以看到类似的问题和一些讨论here

答案 1 :(得分:0)

此讨论适用于Python3。(事实证明它也适用于Python 2.7)

与您描述的方式不完全相同,但以下几点可能会有所帮助:

  • __getattr__仅在以常规方式找不到属性时才能访问
  • hasattr()检查是否引发了AttributeError

看看下面的代码是否有帮助!

>>> class A:
...     def __init__(self, a=1, b=2):
...         self.a = a
...         self.b = b
...
...     def __getattr__(self, name):
...         print('calling __getattr__')
...         print('This is instance attributes: {}'.format(self.__dict__))
...
...         if name not in ('c', 'd'):
...             raise AttributeError()
...         else:
...             return 'My Value'
...         return 'Default'
>>>         
>>> a = A()
>>> print('a = {}'.format(a.a))
a = 1
>>> print('c = {}'.format(a.c))
calling __getattr__
This is instance attributes: {'a': 1, 'b': 2}
c = My Value
>>> print('hasattr(a, "e") returns {}'.format(hasattr(a, 'e')))
calling __getattr__
This is instance attributes: {'a': 1, 'b': 2}
hasattr(a, "e") returns False
>>>