mha*_*vel 6 python plugins function decorator redefinition
我正在尝试为我的代码添加一些"插件"(我不确定这是否是正确的定义).通过"插件",我指的是一个定义模型(这是一个科学代码)的模块,它的存在足以在代码中的任何其他地方使用它.
当然,这些插件必须遵循一个模板,该模板使用我的代码中定义的一些模块/函数/类.以下是我的代码相关部分的小片段:
# [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()
Run Code Online (Sandbox Code Playgroud)
这是"插件"的相关部分:
# [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)
Run Code Online (Sandbox Code Playgroud)
function1 对于任何模型插件都具有完全相同的签名,但通常为每个插件执行不同的工作.
我想要一个默认行为function1,如果它没有被插件定义,我仍然可以做某事(尝试不同的可能性,和/或引发警告/错误).
在插件中,function1可以使用仅在此插件中定义的一些其他功能.我说这是因为代码与多处理模块一起运行,我需要能够在子进程中调用的instance实例.在父进程中定义,以及模型插件,但将在不同的子进程中使用(尽管没有对它进行修改).AllModelsfunction1instance
function1当插件"重新定义"时,能够访问Model实例的属性(即.self),这将是非常棒的.
我已经阅读了许多不同的python文档来源和一些SO问题.我只看到这个问题的两个/三个可能的解决方案:
1)不在类中声明function1方法Model,而是在插件创建它的新实例时将其设置为属性.
# [in the plugin file]
def function1(*args, **kwargs):
# ....
return
newmodel.function1 = function1
Run Code Online (Sandbox Code Playgroud)
然后在需要时调用它.在这种情况下,function1对象中的属性Model可能会启动None.有一点需要注意的是,没有"默认行为" function1(它必须在代码中处理,例如测试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.
Run Code Online (Sandbox Code Playgroud)
3)使用模块types及其MethodType......我不确定这与我的情况有关......但我可能错了.
正如你在这个长期问题之后可能看到的那样,我对这些python功能并不是很熟悉,而且我对装饰器的理解现在非常糟糕.在继续阅读一些文档的同时,我认为在这里提出这个问题可能是值得的,因为我不确定要采取哪些方法来处理我的问题.
Senderle答案的美妙之处在于它非常简单明了......错过了它是一种耻辱.很抱歉用这个问题污染SO.
好吧,除非我弄错了,你想要继承 Model.这有点像创建一个实例Model并用function1插件模块中定义的函数替换它的属性(即你的选项1); 但它更清洁,并为您处理所有细节:
# [in the plugin file]
from code import Model, instance
class MyModel(Model):
def function1(*args, **kwargs):
"""
Work to do by this model
"""
# some specific model-dependent work
return
newmodel = MyModel(a="a name", b="some other stuff")
instance.register(newmodel)
Run Code Online (Sandbox Code Playgroud)
这样,所有其他方法(附加到Model实例的函数)都继承自Model; 它们将以相同的方式运行,但function1将被覆盖,并将遵循您的自function1定义定义.