简体   繁体   English

为什么hasattr执行@property装饰器代码块

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM