我试图迭代类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'
答案 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)