语境
我正在尝试在我的代码中添加一些“插件”(我不确定这是不是正确的定义)。通过“插件”,我的意思是一个模块,它定义了一个模型(这是一个科学代码),它的存在足以在代码的其他任何地方使用它。
当然,这些插件必须遵循一个模板,该模板使用我的代码中定义的一些模块/函数/类。这是我的代码相关部分的一小段代码:
# [In the code]
class AllModels():
def __init__(self):
"""
Init.
"""
self.count = 0
def register(self, name, model):
"""
Adds a model to the code
"""
setattr(self, name, model)
self.count += 1
return
class Model():
def __init__(self, **kwargs):
"""
Some constants that defines a model
"""
self.a = kwargs.get("a", None)
self.b = kwargs.get("b", None)
# and so on...
def function1(self, *args, **kwargs):
"""
A function that all models will have, but which needs:
- to have a default behavior (when the instance is created)
- to be redefinable by the "plugin" (ie. the model)
"""
# default code for the default behavior
return
instance = AllModels()
这是“插件”的相关部分:
# [in the plugin file]
from code import Model, instance
newmodel = Model(a="a name", b="some other stuff")
def function1(*args, **kwargs):
"""
Work to do by this model
"""
# some specific model-dependent work
return
instance.register(newmodel)
附加信息和要求
function1
对于任何模型插件都有完全相同的签名,但通常为每个插件做不同的工作。我想要一个默认行为,
function1
这样如果插件没有定义它,我仍然可以做一些事情(尝试不同的可能性,和/或引发警告/错误)。在插件中,
function1
可能会用到一些仅在本插件中定义的其他功能。我之所以这么说是因为代码与多处理模块一起运行,并且我需要能够调用子进程的instance
实例。在父进程以及模型插件中定义,但将在不同的子进程中使用(虽然没有对其进行修改)。AllModels
function1
instance
真棒
function1
,当插件“重新定义”时,能够访问Model
实例的属性(即。self
)。
问题
我已经阅读了许多不同的 python 文档来源和一些 SO 问题。我只看到这个问题的两个/三个可能的解决方案:
1)不在类中声明function1
方法Model
,而是在插件创建它的新实例时将其设置为属性。
# [in the plugin file]
def function1(*args, **kwargs):
# ....
return
newmodel.function1 = function1
然后在需要时调用它。在那种情况下,function1
对象中的属性可能Model
会被初始化None
。一个警告是没有“默认行为” function1
(它必须在代码中处理,例如 testing if instance.function1 is None: ...
),更大的一个是我无法self
以这种方式访问......
2)以某种方式使用python装饰器。我从来没有使用过这个,而且我读过的文档并不是那么简单(我的意思是不直接,因为它的使用可能性很大)。但这似乎是一个很好的解决方案。但是我担心它对性能的影响(我已经读过它可能会减慢装饰函数/方法的执行速度)。如果这个解决方案是最好的选择,那么我想知道如何使用它(可能是一个快速的片段),以及是否可以使用类的属性Model
:
# [in the plugin file]
@mydecorator
def function1(self, *args, **kwargs):
"""
I'm not sure I can use *self*, but it would be great since some attributes of self are used for some other function similar to *function1*...
"""
# some stuff using *self*, eg.:
x = self.var **2 + 3.4
# where self.var has been defined before, eg.: newmodel.var = 100.
3)使用模块types
及其MethodType
......我不确定这是否与我的情况相关......但我可能是错的。
在这个长长的问题之后你可能会看到,我对这些 python 特性不是很熟悉,而且我现在对装饰器的理解真的很差。在继续阅读一些文档的同时,我认为可能值得在这里提出这个问题,因为我不确定为了解决我的问题而采取的方向。
解决方案
Senderle 答案的美妙之处在于它非常简单明了......错过了它是一种耻辱。很抱歉用那个问题污染了 SO。