Python 为什么hasattr执行@property decorator代码块

Python 为什么hasattr执行@property decorator代码块,python,python-2.7,properties,Python,Python 2.7,Properties,在Python中,当我对@property装饰程序调用hasattr时,hasattr函数实际上运行@property代码块 例如,a类: class GooglePlusUser(object): def __init__(self, master): self.master = master def get_user_id(self): return self.master.google_plus_service.people().get(

在Python中,当我对
@property
装饰程序调用
hasattr
时,
hasattr
函数实际上运行
@property
代码块

例如,a类:

class GooglePlusUser(object):

    def __init__(self, master):
        self.master = master

    def get_user_id(self):
        return self.master.google_plus_service.people().get(userId='me').execute()['id']


    @property
    def profile(self):
        # this runs with hasattr
        return self.master.google_plus_service.people().get(userId='me').execute()
运行以下代码将调用profile属性并实际进行调用:

#Check if the call is an attribute
if not hasattr(google_plus_user, call):
    self.response.out.write('Unknown call')
    return
为什么??我如何在不调用api的情况下解决这个问题

hasattr()
通过实际检索属性来工作;如果抛出异常
hasattr()
将返回
False
。这是因为这是知道属性是否存在的唯一可靠方法,因为有很多动态方法可以在Python对象上注入属性(
\uuu getattr\uuu
\uu getattribute\uuu
属性
对象,元类等)

从:

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


如果不希望在执行此操作时调用属性,则不要使用
hasattr
。使用
vars()

因此,在真正的“请求原谅比请求许可更容易”(EAFP)方式中,为了确定对象是否具有给定的属性,Python只是尝试获取该属性,并将失败转换为返回值
False
。由于它在成功案例中真正获得了属性,
hasattr()
可以触发
属性
和其他描述符的代码

要在不触发描述符的情况下检查属性,您可以编写自己的
hasattr
,遍历对象的方法解析顺序,并检查名称是否位于每个类的
\uuuuu dict\uuu
(或
\uu slots\uuu
)中。因为这不是属性访问,所以不会触发属性

方便的是,Python已经有了一种方法来遍历方法解析顺序并从实例类中收集属性名称:
dir()
。那么,编写这种方法的简单方法是:

# gingerly test whether an attribute exists, avoiding triggering descriptor code
def gentle_hasattr(obj, name):
    return name in dir(obj) or hasattr(obj, name)
请注意,如果在
dir()
中找不到所需的名称,我们将返回使用
hasattr()
,因为
dir()
将找不到动态属性(即,
\uuu getattr\uuuu
被覆盖的位置)。当然,这些代码仍然会被触发,因此如果您不介意找不到它们,您可以省略子句


总的来说,这是浪费,因为当我们只关心某个特定的属性是否存在时,它会获取所有相关的属性名称,但在必要的时候它会这样做。我甚至不确定自己执行循环而不是调用
dir()
平均速度会更快,因为它将在Python中而不是在C中。将变量作为类变量,然后对其调用hasattr对我来说很有帮助

if not hasattr(google_plus_user, GooglePlusUser.call):
  self.response.out.write('Unknown call')
  return

使用了
dir
,这对我来说很管用。再次感谢Martijn。需要注意的重要一点是:如果抛出任何异常,它会得出结论说它没有attr。@felix:只有在Python 2中,只有在Python 3中
AttributeError
才会导致
hasattr()
返回
False
。其他异常会被传播。更好的是,尽管在该方法调用中的任何地方引发的任何AttributeError都会这样做。我刚刚修复了一个发生数据库调用的问题,因为我错误地认为我可以使用
hasattr
@felix进行对象特性测试:是的,任何
AttributeError
都会这样做,因为无法区分故意和意外的属性错误。起初我不相信这一点,但这是真的。如果
attrname
指定了一个引发
AttributeError
hasattr
的属性,则会令人困惑地返回
False
if not hasattr(google_plus_user, GooglePlusUser.call):
  self.response.out.write('Unknown call')
  return