6
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 时我不想这样做。谢谢。

4

2 回答 2

10

你不能,不作弊。正如文档所说:

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

换句话说,你不能在没有阻塞的hasattr情况下阻塞getattr,这基本上意味着hasattr如果你关心访问属性,你根本就不能阻塞。

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

你可以在这里看到一个类似的问题和一些讨论。

于 2013-09-14T03:12:01.110 回答
0

这个讨论适用于 Python 3。(结果它也适用于 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
>>> 
于 2020-11-19T09:37:47.317 回答