为什么hasattr会执行@属性装饰器代码块
Why does hasattr execute the @property decorator code block
在 Python 中,当我在 @property
装饰器上调用 hasattr
时,hasattr
函数实际上运行 @property
代码块。
例如一个 class:
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()
运行 以下代码调用配置文件 属性 并实际进行调用:
#Check if the call is an attribute
if not hasattr(google_plus_user, call):
self.response.out.write('Unknown call')
return
为什么?如何在不拨打 api 电话的情况下解决这个问题?
hasattr()
通过实际 检索属性 来工作;如果抛出异常 hasattr()
returns False
。这是因为这是了解属性是否存在的唯一可靠方法,因为有很多动态方法可以将属性注入 Python 对象(__getattr__
、__getattribute__
、property
对象、元 classes 等)。
This is implemented by calling getattr(object, name)
and seeing whether it raises an exception or not.
如果您不想在执行此操作时调用 属性,则不要使用 hasattr
。使用 vars()
(returns 实例字典)或 dir()
(也为您提供 class 上的名称列表)。
hasattr
基本上是这样实现的(C中除外):
def hasattr(obj, attrname):
try:
getattr(obj, attname)
except AttributeError:
return False
return True
所以在真正的 "easier to ask for forgiveness than permission" (EAFP) 中,要找出对象是否具有给定的属性,Python 只是尝试获取该属性,并将失败转换为 return False
的值。由于是真正获取成功案例中的属性,hasattr()
可以触发property
等描述符的代码。
要在不触发描述符的情况下检查属性,您可以编写自己的 hasattr
遍历对象的方法解析顺序并检查名称是否在每个 class 的 __dict__
(或 __slots__
)。由于这不是属性访问,因此不会触发属性。
方便的是,Python 已经有一种方法可以遍历方法解析顺序并从实例的 classes 中收集属性名称: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()
不会找到动态属性(即,其中 __getattr__
被覆盖)。当然,这些代码仍然会被触发,所以如果您不在乎找不到它们,您可以省略 or
子句。
总的来说,这是一种浪费,因为当我们只对某个特定的属性是否存在感兴趣时,它会获取所有相关的属性名称,但它会在紧要关头完成。我什至不确定自己做循环而不是调用 dir()
平均来说会更快,因为它将在 Python 而不是 C.
将变量设置为 class 变量,然后对其调用 hasattr 就成功了。
if not hasattr(google_plus_user, GooglePlusUser.call):
self.response.out.write('Unknown call')
return
在 Python 中,当我在 @property
装饰器上调用 hasattr
时,hasattr
函数实际上运行 @property
代码块。
例如一个 class:
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()
运行 以下代码调用配置文件 属性 并实际进行调用:
#Check if the call is an attribute
if not hasattr(google_plus_user, call):
self.response.out.write('Unknown call')
return
为什么?如何在不拨打 api 电话的情况下解决这个问题?
hasattr()
通过实际 检索属性 来工作;如果抛出异常 hasattr()
returns False
。这是因为这是了解属性是否存在的唯一可靠方法,因为有很多动态方法可以将属性注入 Python 对象(__getattr__
、__getattribute__
、property
对象、元 classes 等)。
This is implemented by calling
getattr(object, name)
and seeing whether it raises an exception or not.
如果您不想在执行此操作时调用 属性,则不要使用 hasattr
。使用 vars()
(returns 实例字典)或 dir()
(也为您提供 class 上的名称列表)。
hasattr
基本上是这样实现的(C中除外):
def hasattr(obj, attrname):
try:
getattr(obj, attname)
except AttributeError:
return False
return True
所以在真正的 "easier to ask for forgiveness than permission" (EAFP) 中,要找出对象是否具有给定的属性,Python 只是尝试获取该属性,并将失败转换为 return False
的值。由于是真正获取成功案例中的属性,hasattr()
可以触发property
等描述符的代码。
要在不触发描述符的情况下检查属性,您可以编写自己的 hasattr
遍历对象的方法解析顺序并检查名称是否在每个 class 的 __dict__
(或 __slots__
)。由于这不是属性访问,因此不会触发属性。
方便的是,Python 已经有一种方法可以遍历方法解析顺序并从实例的 classes 中收集属性名称: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()
不会找到动态属性(即,其中 __getattr__
被覆盖)。当然,这些代码仍然会被触发,所以如果您不在乎找不到它们,您可以省略 or
子句。
总的来说,这是一种浪费,因为当我们只对某个特定的属性是否存在感兴趣时,它会获取所有相关的属性名称,但它会在紧要关头完成。我什至不确定自己做循环而不是调用 dir()
平均来说会更快,因为它将在 Python 而不是 C.
将变量设置为 class 变量,然后对其调用 hasattr 就成功了。
if not hasattr(google_plus_user, GooglePlusUser.call):
self.response.out.write('Unknown call')
return