【问题标题】:How to prevent hasattr from retrieving the attribute value itself如何防止 hasattr 检索属性值本身
【发布时间】:2015-07-29 04:49:52
【问题描述】:

我有一个使用__getattr__ 实现虚拟属性的类。属性可能很昂贵,例如执行查询。现在,我正在使用一个库,它会在实际获取对象之前检查我的对象是否具有该属性。

因此,一个查询被执行了两次而不是一次。当然,实际执行__getattr__ 以真正知道该属性是否存在是有意义的。

class C(object):
    def __getattr__(self, name):
        print "I was accessed"
        return 'ok'

c = C()
hasattr(c, 'hello')

有什么办法可以防止这种情况发生吗?

如果 Python 支持 __hasattr__,那么我可以简单地检查查询是否存在,而不是实际运行它。

我可以创建一个缓存,但它很重,因为查询可能有参数。当然,服务器可能会自己缓存查询并将问题最小化,但如果查询返回大量数据,它仍然很重。

有什么想法吗?

【问题讨论】:

  • 如果我理解的情况正确,您只需要基于name 进行缓存,所以这可能只是一个字典。 BTW,你为什么要让它看起来像一个属性?
  • 如果对象不支持查询,你希望发生什么?
  • hasattr 不是属性的轻量级测试;它调用getattr 本质上类似于try: getattr('name'); except AttributeError: return False; else: return True
  • 我认为除了猴子补丁hasattr之外,没有其他方法可以做你想做的事,不推荐这样做。如果没有办法避免调用hasattr,我相信您唯一的选择是缓存结果或允许查询运行两次。
  • @shashank,如果查询不可用(按名称),则返回未找到属性的异常。

标签: python getattr hasattr


【解决方案1】:

虽然最初我不喜欢猴子修补的想法,总的来说是一个“坏主意”,但我在 1999 年遇到了一个非常巧妙的解决方案!

http://code.activestate.com/lists/python-list/14972/

def hasattr(o, a, orig_hasattr=hasattr):
    if orig_hasattr(o, "__hasattr__"):
        return o.__hasattr__(a)
    return orig_hasattr(o, a)

__builtins__.hasattr = hasattr

基本上它在 Python 中创建了对 __hasattr__ 的支持,这是我最初认为的最佳解决方案。

【讨论】:

  • 猴子补丁太棒了。 Ruby 爱好者长期以来一直喜欢丑陋的猴子。 Pythonistas 也应该如此。您对内置 hasattr() 库存的扩充以支持 __hasattr__() 特殊方法就是一个完美的例子。感谢您让这个优雅的黑客重新焕发活力!
【解决方案2】:

我认为这通常可能是一种不好的模式,但您始终可以检查对象的底层__dict__

In [1]: class A(object):
   ....:     @property
   ....:     def wha(self):
   ....:         print "was accessed"
   ....:

In [2]: A.__dict__
Out[2]:
<dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'wha': <property at 0x10f6b11b0>}>

In [3]: a = A()

In [4]: "wha" in a.__class__.__dict__
Out[4]: True

【讨论】:

  • 我认为 OP 正在处理调用 hasattr 的第三方库,因此这需要分叉库。
  • 我想你误会了,类没问题,我需要使用__getattr__()。加上@bjudson 所说的话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 2010-11-22
相关资源
最近更新 更多