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

时间:2015-05-09 19:09:02

标签: python python-2.7 properties

在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电话的情况下解决这个问题?

3 个答案:

答案 0 :(得分:10)

hasattr()实际上检索属性;如果抛出异常hasattr()返回False。那是因为这是了解属性是否存在的唯一可靠方法,因为有很多动态方法可以在Python对象上注入属性(__getattr____getattribute__property对象,元类等等。)。

来自hasattr() documentation

  

这是通过调用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