为什么hasattr返回错误的结果?

时间:2018-09-03 04:30:30

标签: python

下面是我的测试代码:

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和callable函数返回true?

具有Python2.7的CentOS7.4。

1 个答案:

答案 0 :(得分:1)

内置函数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')