我试图将字典键分配给对象函数,但由于某些原因,它在装饰器中无法工作。当我尝试调用.run((时,self似乎没有被传递到dictionary func中。我也无法访问decorator中的f.self,所以我知道里面一定有问题。我写了一个简单的代码示例。我希望它类似于flask中的app.route,因为它初始化端点和函数之间的映射。
错误:
Traceback (most recent call last):
File "main.py", line 27, in <module>
a.run()
File "main.py", line 14, in run
self.rmap[k](data)
TypeError: one_way() missing 1 required positional argument: 'data'
代码:
class A (object):
def __init__(self):
self.rmap = {}
def route(self, r):
def decorator(f):
self.rmap[r] = f
return f
return decorator
def run(self):
data = [1,2,3]
for k in self.rmap.keys():
self.rmap[k](data)
a = A()
class B (object):
def __init__(self):
pass
@a.route('/one/way')
def one_way (self, data):
print('A WAY:{}'.format(self))
b = B()
a.run()
在对其进行装饰时,one_way()
是一个普通函数,而不是一个方法——只有在B
实例上查找时,它才会变成一个方法。IOW,当从A().run()
调用B
实例时,您需要明确地提供它(事实上,您的代码中有一个全局b
实例是无关紧要的——存储在a.rmap
中的函数对象对它一无所知,甚至对B
类FWIW也一无所知。
长话短说,你当前的设计不能按原样工作。如果你只打算装饰一个类中的方法(好吧,函数(,并在这个类的一个实例上调用它们,你可以将这个类的实例传递给a.run()
,即:
class A():
# ...
def run(self, obj):
data = [1,2,3]
for k in self.rmap.keys():
self.rmap[k](obj, data)
b = B()
a.run(b)
但是这将是非常有限的用途。
或者,您可以使用decorator来"标记"要用于路由的函数(以及有效路由(,向A
添加一些register()
方法,并明确地将B
或任何其他实例传递给该方法,即
def route(r):
def decorator(f):
f._A_route = r
return f
return decorator
class A (object):
def __init__(self):
self.rmap = {}
def register(self, *objects):
for obj in objects:
self._register(obj)
def _register(self, obj):
for name in dir(obj):
if name.startswith("_"):
continue
attr = getattr(obj, name)
if callable(attr) and hasattr(attr, "_A_route"):
self.rmap[attr._A_route] = attr
def run(self):
data = [1,2,3]
for k in self.rmap.keys():
self.rmap[k](data)
class B (object):
def __init__(self):
pass
@route('/one/way')
def one_way (self, data):
print('A WAY:{}'.format(self))
if __name__ == "__main__":
a = A()
b = B()
a.register(b)
a.run()
现在可能有更好的解决方案来解决您的具体用例,但如果不了解整个上下文等,就不可能判断。
调用self.rmap[k](data)
时,没有传入self
参数。这必须是类B
的实例才能工作。
通常情况下,您只需要传递用于调用装饰函数的参数,但您似乎希望以不同的方式使用装饰函数。在您的情况下,有效的方法是:
def run(self):
data = [1,2,3]
b = B()
for k in self.rmap.keys():
self.rmap[k](b, data)
当然,如果您想在调用之间重用B
实例,也可以在其他地方实例化它。