[英]Why does hasattr execute the @property decorator code block
In Python when I call the hasattr
on a @property
decorator the hasattr
function actually runs the @property
code block. 在Python中,当我在
@property
装饰器上调用hasattr
时, hasattr
函数实际上运行@property
代码块。
Eg a 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()
Running the following code calls the profile property and actually makes the call: 运行以下代码调用profile属性并实际进行调用:
#Check if the call is an attribute
if not hasattr(google_plus_user, call):
self.response.out.write('Unknown call')
return
Why? 为什么? How can I solve this without making the api call?
如何在不拨打api电话的情况下解决这个问题?
hasattr()
works by actually retrieving the attribute ; hasattr()
通过实际检索属性来工作 ; if an exception is thrown hasattr()
returns False
. 如果抛出异常,
hasattr()
返回False
。 That's because that is the only reliable way of knowing if an attribute exists, since there are so many dynamic ways to inject attributes on Python objects ( __getattr__
, __getattribute__
, property
objects, meta classes, etc.). 这是因为这是了解属性是否存在的唯一可靠方法,因为有很多动态方法可以在Python对象上注入属性(
__getattr__
, __getattribute__
, property
对象,元类等)。
From the hasattr()
documentation : 从
hasattr()
文档 :
This is implemented by calling
getattr(object, name)
and seeing whether it raises an exception or not.这是通过调用
getattr(object, name)
并查看它是否引发异常来实现的。
If you don't want a property to be invoked when doing this, then don't use hasattr
. 如果您不希望在执行此操作时调用属性,则不要使用
hasattr
。 Use vars()
(which returns the instance dictionary) or dir()
(which gives you a list of names on the class as well). 使用
vars()
(返回实例字典)或dir()
(它也为您提供类的名称列表)。
hasattr
is basically implemented like this (except in C): hasattr
基本上是这样实现的(C中除外):
def hasattr(obj, attrname):
try:
getattr(obj, attname)
except AttributeError:
return False
return True
So in true "easier to ask for forgiveness than permission" (EAFP) fashion, to find out if an object has a given attribute, Python simply tries to get the attribute, and converts failure to a return value of False
. 因此,在真正的“更容易请求宽恕而非许可”(EAFP)时尚中,为了找出对象是否具有给定属性,Python只是尝试获取属性,并将失败转换为返回值
False
。 Since it's really getting the attribute in the success case, hasattr()
can trigger code for property
and other descriptors. 由于它确实在成功案例中获得了属性,因此
hasattr()
可以触发property
和其他描述符的代码。
To check for an attribute without triggering descriptors, you can write your own hasattr
that traverses the object's method resolution order and checks to see whether the name is in each class's __dict__
(or __slots__
). 要在不触发描述符的情况下检查属性,可以编写自己的
hasattr
来遍历对象的方法解析顺序,并检查名称是否在每个类的__dict__
(或__slots__
)中。 Since this isn't attribute access, it won't trigger properties. 由于这不是属性访问,因此不会触发属性。
Conveniently, Python already has a way to walk the method resolution order and gather the names of attributes from an instance's classes: dir()
. 方便的是,Python已经有了一种方法来处理方法解析顺序并从实例的类中收集属性的名称:
dir()
。 A simple way to write such a method, then, would be: 那么,编写这样一个方法的简单方法是:
# gingerly test whether an attribute exists, avoiding triggering descriptor code
def gentle_hasattr(obj, name):
return name in dir(obj) or hasattr(obj, name)
Note that we fall back to using hasattr()
if we can't find the desired name in dir()
, because dir()
won't find dynamic attributes (ie, where __getattr__
is overridden). 请注意,如果我们在
dir()
找不到所需的名称,我们将回退到使用hasattr()
,因为dir()
将找不到动态属性(即,覆盖__getattr__
位置)。 Code for these will still be triggered, of course, so if you don't care that you don't find them, you could omit the or
clause. 当然,仍然会触发这些代码,所以如果你不在乎你没有找到它们,你可以省略
or
子句。
On balance, this is wasteful, since it gets all relevant attribute names when we're interested only in whether a specific one exists, but it'll do in a pinch. 总的来说,这是浪费,因为当我们只关心特定的属性是否存在时,它会获得所有相关的属性名称,但它会在紧要关头。 I'm not even sure that doing the loop yourself rather than calling
dir()
would be faster on average, since it'll be in Python rather than in C. 我甚至不确定自己做循环而不是调用
dir()
会平均更快,因为它将在Python中而不是在C中。
Making the variable as a class variable and then calling hasattr on it did the trick for me. 将变量作为类变量,然后在其上调用hasattr对我来说是个窍门。
if not hasattr(google_plus_user, GooglePlusUser.call):
self.response.out.write('Unknown call')
return
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.