【发布时间】:2012-04-07 17:03:15
【问题描述】:
上下文
我正在尝试为我的代码添加一些“插件”(我不确定这是否是正确的定义)。 “插件”是指一个模块,它定义了一个模型(这是一个科学代码),它的存在足以在代码中的任何其他地方使用它。
当然,这些插件必须遵循一个模板,该模板使用我的代码中定义的一些模块/函数/类。这是我的代码相关部分的小sn-p:
# [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可能会使用一些仅在此插件中定义的其他功能。我之所以这么说是因为代码与多处理模块一起运行,并且我需要AllModels的instance实例才能在子进程中调用function1。instance定义在父进程和模型插件中,但会在不同的子进程中使用(但未对其进行修改)。如果
function1被插件“重新定义”后,能够访问Model实例的属性(即self),那就太棒了。
问题
我已经阅读了许多不同的 python 文档来源和一些 SO 问题。我只看到这个问题的两个/三个可能的解决方案:
1) 不在Model 类中声明function1 方法,而是在插件创建它的新实例时将其设置为属性。
# [in the plugin file]
def function1(*args, **kwargs):
# ....
return
newmodel.function1 = function1
然后在需要时调用它。在这种情况下,对象Model 中的属性function1 可能会初始化为None。其中一个警告是function1 没有“默认行为”(它必须在代码中处理,例如测试if instance.function1 is None: ...),更大的一个是我无法访问self这样……
2) 以某种方式使用 python 装饰器。我从来没有使用过这个,而且我读过的文档并不是那么简单(我的意思是不直接,因为它的使用有很多可能性)。但这似乎是一个很好的解决方案。但是我担心它对性能的影响(我已经读过它可能会减慢装饰函数/方法的执行速度)。如果这个解决方案是最好的选择,那么我想知道如何使用它(可能是一个快速的 sn-p),以及是否可以使用 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。
【问题讨论】:
-
最好将 AllModels 中的模型保存在 dict 属性中,而不是类命名空间中。否则,例如,当有人称模型为“计数”时,您会遇到疯狂的错误
-
如果这是 python2,如果你的类不从其他任何东西(如模型)继承,你需要使你的类成为新样式(从
object继承) -
@gnibbler 感谢您指出这一点!
-
@Daenyth 建议不要使用老式类吗?你能告诉我为什么吗?
-
@mhavel,新式类是真正的用户定义类型,但旧式类不是;旧式类的所有实例都属于同一类型,
instance。这意味着新式类可以做旧式类不能做的各种好事。此外,旧式课程正在逐步淘汰。基本上,他们只是讨厌。
标签: python function plugins decorator redefinition