在Python中,当我在hasattr
装饰器上调用@property
时,hasattr
函数实际运行@property
代码块。
E.g。一个班级:
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电话的情况下解决这个问题?
答案 0 :(得分:10)
hasattr()
实际上检索属性;如果抛出异常hasattr()
返回False
。那是因为这是了解属性是否存在的唯一可靠方法,因为有很多动态方法可以在Python对象上注入属性(__getattr__
,__getattribute__
,property
对象,元类等等。)。
这是通过调用
getattr(object, name)
并查看是否引发异常来实现的。
如果您不希望在执行此操作时调用属性,请不要使用hasattr
。使用vars()
(返回实例字典)或dir()
(它也会为您提供类中的名称列表)。
答案 1 :(得分:2)
hasattr
基本上是这样实现的(C中除外):
def hasattr(obj, attrname):
try:
getattr(obj, attname)
except AttributeError:
return False
return True
所以真的"更容易请求宽恕而不是许可" (EAFP)时尚,为了找出对象是否具有给定属性,Python只是尝试获取属性,并将失败转换为返回值False
。由于它在成功案例中确实获得了属性,hasattr()
可以触发property
和其他描述符的代码。
要检查属性而不触发描述符,您可以编写自己的hasattr
遍历对象的方法解析顺序,并检查名称是否在每个类中{{1} __dict__
1}}(或__slots__
)。由于这不是属性访问,因此不会触发属性。
方便的是,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)
请注意,如果我们无法在hasattr()
中找到所需的名称,我们会再次使用dir()
,因为dir()
无法找到动态属性(例如,其中__getattr__
被覆盖的地方)。当然,这些代码仍将被触发,因此,如果您不关心自己无法找到它们,则可以省略or
条款。
总的来说,这是浪费,因为当我们只对特定的属性是否存在感兴趣时,它会获得所有相关的属性名称,但它会在紧要关头。我甚至不确定自己做循环而不是调用dir()
平均会更快,因为它会在Python中而不是在C中。
答案 2 :(得分:2)
将变量作为类变量,然后在其上调用hasattr为我做了诀窍。
if not hasattr(google_plus_user, GooglePlusUser.call):
self.response.out.write('Unknown call')
return