Python - 从导入的模块注册函数
Posted
技术标签:
【中文标题】Python - 从导入的模块注册函数【英文标题】:Python - Register functions from imported module 【发布时间】:2020-12-14 09:50:11 【问题描述】:我正在尝试确定实现我的应用程序的最佳方式,其中将有一个主程序 (main.py) 和一个单独的规则模块 (rules.py),其中可以编写任意数量的规则,它们将都可以在 main.py 中应用来操作一些数据(字典)。应用程序的用户可以在 rules.py 中添加他们的自定义规则,而不会影响 main.py 中的逻辑。
我在想装饰器在这里可以用来注册 rules.py 中的每个函数,而 main.py 可以迭代它们,但我不确定具体的实现。这是我的骨架代码。
main.py
import rules
modifiers = [] # List of fuctions to modify data
def add_modifier(f):
modifiers.append(f)
return f
def invoke_modifiers(data):
for modifier in modifiers:
data = modifier(data)
return data
if __name__ == "__main__":
data = 'foo': 'bar'
print(f"Invoking modifiers on data: data")
data = invoke_modifiers(data)
print(f"Done invoking modifiers: data")
rules.py
from main import add_modifier
@add_modifier
def mod1(data):
data['foo'] = 'baz'
return data
@add_modifier
def mod2(data):
data['quz'] = 'qux'
return data
但是当我执行代码时,它并没有修改我的数据。
$ python main.py
Invoking modifiers on data: 'foo': 'bar'
Done invoking modifiers: 'foo': 'bar'
所以我的问题有两个:
-
这是在主应用程序之外使用用户定义函数的好方法吗?
在rules.py模块中需要修改哪些数据才能得到mod1和mod2修改的数据?
编辑
如果我在 rules.py 中省略 from main import add_modifier
,我会在执行期间得到以下信息:
Traceback (most recent call last):
File "main.py", line 3, in <module>
import rules
File "/home/telorb/Python/registerTest/rules.py", line 3, in <module>
@add_modifier
NameError: name 'add_modifier' is not defined
【问题讨论】:
看起来你有一个循环导入。这可能会在您的 rules.py 中引发错误。 查看我的编辑以获取从 rules.py 中省略导入语句的结果。还有其他方法吗? 【参考方案1】:Python 导入机制相当复杂,但在这种情况下,解释为什么原始代码不起作用很简单。
当调用main.py
时,其模块名称为"__main__"
而不是"main"
。当rules
被导入并反过来导入main
时,会创建一个名为"main"
(无下划线)的新模块,它有自己的modifiers
实例。您可以通过将 print("modifiers id = ", id(modifiers))
到 add_modifier
放入主块中轻松检查这一点。
我认为这里最好的解决方案是创建一个管理修饰符的新模块:
main.py
from modifiers import invoke_modifiers
import rules
if __name__ == "__main__":
data = 'foo': 'bar'
print(f"Invoking modifiers on data: data")
data = invoke_modifiers(data)
print(f"Done invoking modifiers: data")
rules.py
from modifiers import add_modifier
@add_modifier
def mod1(data):
data['foo'] = 'baz'
return data
@add_modifier
def mod2(data):
data['quz'] = 'qux'
return data
modifiers.py
_modifiers = [] # List of fuctions to modify data
def add_modifier(f):
_modifiers.append(f)
return f
def invoke_modifiers(data):
for modifier in _modifiers:
data = modifier(data)
return data
结果
azelcer@ZX80:~$ python main.py
Invoking modifiers on data: 'foo': 'bar'
Done invoking modifiers: 'foo': 'baz', 'quz': 'qux'
【讨论】:
【参考方案2】:现在我将使用此处找到的解决方案:How can I decorate all functions imported from a file?
main.py
import types
import functools
modifiers = [] # List of fuctions to modify data
def decorate_all_in_module(module, decorator):
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, types.FunctionType):
setattr(module, name, decorator(obj))
def add_modifier(f):
print(f"Adding modifier: f")
modifiers.append(f)
return f
def invoke_modifiers(data):
print(f'Invoking len(modifiers) modifiers')
for modifier in modifiers:
print(f'Invoking modifier')
data = modifier(data)
return data
@add_modifier
def mod_main(data):
data['xray'] = 'zulu'
return data
import rules
if __name__ == "__main__":
decorate_all_in_module(rules, add_modifier)
data = 'foo': 'bar'
print(f"Invoking modifiers on data: data")
data = invoke_modifiers(data)
print(f"Done invoking modifiers: data")
rules.py
def mod1(data):
data['foo'] = 'baz'
return data
def mod2(data):
data['quz'] = 'qux'
return data
$ python main.py
Adding modifier: <function mod_main at 0x7fe69ce75160>
Adding modifier: <function mod1 at 0x7fe69ce75040>
Adding modifier: <function mod2 at 0x7fe69ce75700>
Invoking modifiers on data: 'foo': 'bar'
Invoking 3 modifiers
Invoking <function mod_main at 0x7fe69ce75160>
Invoking <function mod1 at 0x7fe69ce75040>
Invoking <function mod2 at 0x7fe69ce75700>
Done invoking modifiers: 'foo': 'baz', 'xray': 'zulu', 'quz': 'qux'
【讨论】:
【参考方案3】:我对装饰器不是很熟悉,所以也许其他人可以就此提供建议。
但考虑到您正在做的事情,我认为为用户创建一个类来添加功能将拥有您正在寻找的功能。
这个帖子的东西:Is there a way to loop through and execute all of the functions in a Python class?
一个建议的解决方案确实使用了装饰器,因此可以阐明如何更好地构建您的结构。
【讨论】:
以上是关于Python - 从导入的模块注册函数的主要内容,如果未能解决你的问题,请参考以下文章