首页 > 解决方案 > 为什么 hasattr 返回错误的结果?

问题描述

下面是我的测试代码:

import functools


class LazyLoader(object):

    def __init__(self, klass, *args, **kwargs):
        self.klass = klass
        self.args = args
        self.kwargs = kwargs
        self.instance = None

    def __getattr__(self, name):
        return functools.partial(self.__run_method, name)

    def __run_method(self, __name, *args, **kwargs):
        if self.instance is None:
            self.instance = self.klass(*self.args, **self.kwargs)
        return getattr(self.instance, __name)(*args, **kwargs)


class SchedulerReportClient(object):
    def method(self):
        print 'method called'

    def __getattr__(self, name):
        print '__getattr__ called'
        return functools.partial(self.__run_method, name)

    def __run_method(self, __name, *args, **kwargs):
        print '__run_method called'
        return getattr(self, __name)(*args, **kwargs)


if __name__ == "__main__":
    a = SchedulerReportClient()
    entity = LazyLoader(a)

    print hasattr(entity, 'obj_to_primitive')
    print(callable(entity.obj_to_primitive))
    print entity.__class__.__name__
    if hasattr(entity, 'obj_to_primitive') and callable(entity.obj_to_primitive):
        entity.obj_to_primitive()

出局是:

True
True
Traceback (most recent call last):
LazyLoader
  File "C:/Users/chen/PycharmProjects/pytest/main", line 42, in <module>
    entity.obj_to_primitive()
  File "C:/Users/chen/PycharmProjects/pytest/main", line 17, in __run_method
    self.instance = self.klass(*self.args, **self.kwargs)
TypeError: 'SchedulerReportClient' object is not callable

代码主要在openstack nova中,我复制了一些。

类中没有obj_to_primitive方法SchedulerReportClient,为什么hasattr和可调用函数返回true?

CentOS7.4 与 Python2.7。

标签: python

解决方案


内置函数hasattr是通过调用getattr并检查它是否引发异常来实现的。这在文档中有所说明。

结果是True字符串是否是对象属性之一的名称,False如果不是。(这是通过调用 getattr(object, name) 并查看它是否引发异常来实现的。)

在这种情况下,您定义了LazyLoader.__getattr__返回部分评估方法的方法,LazyLoader.__run_method而不管参数的值如何name

def __getattr__(self, name):
        return functools.partial(self.__run_method, name)

提醒一下,__getattr__当通过通常的方式找不到属性时会调用该方法。

所以当你得到时entity.obj_to_primitive,返回的是functools.partial(entity.__run_method, 'obj_to_primitive').


推荐阅读