在python中重新定义类方法

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.

sen*_*rle 5

好吧,除非我弄错了,你想要继承 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定义定义.