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

问题描述 投票:0回答:1

以下是我的测试代码:

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?

CentOS7.4与Python2.7。

python
1个回答
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')

© www.soinside.com 2019 - 2024. All rights reserved.