__dict__和getattr之间的区别是什么?

时间:2018-06-18 03:52:52

标签: python reflection

我试图迭代类A的所有变量,其中包含模块a.py中的一些协程方法。我用两种方法来实现我的目的,但结果却不同:

方法1:使用getattr()

a = __import__('a')
print('===========getattr()=============')
func_sync = getattr(a, 'func_sync')
func_async = getattr(a, 'func_async')
print(func_sync)  # <function func_sync at 0x7f827b98f510>
print(func_async)  # <function func_async at 0x7f8279cd01e0>
print(asyncio.iscoroutinefunction(func_async))  # True
# getattr class
A = getattr(a, 'A')
print(A)  # <class 'a.A'>
method_aa = getattr(A, 'aa')
method_bb = getattr(A, 'bb')
method_cc = getattr(A, 'cc')
print(method_aa)  # <bound method A.aa of <class 'a.A'>>  <----notice this
print(method_bb)  # <function A.bb at 0x7f8279cd00d0>
print(method_cc)  # <function A.cc at 0x7f8279cd0158>
print(asyncio.iscoroutinefunction(method_aa))  # True  <---- meet my expectations
print(asyncio.iscoroutinefunction(method_bb))  # True
print(asyncio.iscoroutinefunction(method_cc))  # False

似乎所有结果都符合我的期望。但是当我使用__dict__时,会出现问题

print('=========== __dict__ =============')
A = a.__dict__['A']
func_sync = a.__dict__['func_sync']
func_async = a.__dict__['func_async']
print(asyncio.iscoroutinefunction(func_async))  # True
print(A)  # <class 'a.A'>
method_aa = A.__dict__['aa']
method_bb = A.__dict__['bb']
method_cc = A.__dict__['cc']
print(method_aa)  # <classmethod object at 0x7f827a21c908>  <---- different from before
print(method_bb)  # <function A.bb at 0x7f8279cd00d0>
print(method_cc)  # <function A.cc at 0x7f8279cd0158>
print(asyncio.iscoroutinefunction(method_aa))  # False <----- I think it should be True
print(asyncio.iscoroutinefunction(method_bb))  # True
print(asyncio.iscoroutinefunction(method_cc))  # False

有人可以帮我解释一下吗?

这是a.py

class A:

    @classmethod
    async def aa(cls):
        return 123

    async def bb(self):
        return 456

    def cc(self):
        return 789


def func_sync():
    return 'sync'


async def func_async():
    return 'async'

1 个答案:

答案 0 :(得分:2)

classmethod装饰器的工作原理是返回一个实现descriptor protocol的对象。

当您使用属性访问或getattr通过类访问此类对象时,协议将付诸实施,您将获得所需的结果,即绑定到指定类的方法:

method_aa = getattr(A, 'aa')
# bound method - calling method_aa() automatically supplies `A` to the function

如果您通过班级__dict__访问它,则会获得原始classmethod 对象,可用于获取绑定到的方法上课,但本身并不是一个。

method_aa_desc = A.__dict__['aa']
# a descriptor, which we cannot call, but which we can _bind_ to AA
method_aa = method_aa_desc.__get__(None, A)