コンテクスト
私は自分のコードにいくつかの「プラグイン」(これがこれの正しい定義であるかどうかはわかりません)を持たせようとしています。「プラグイン」とは、モデル(これは科学的なコードです)を、その存在がコード内の他の場所で使用するのに十分な方法で定義するモジュールを意味します。
もちろん、これらのプラグインは、私のコードで定義されたいくつかのモジュール/関数/クラスを使用するテンプレートに従う必要があります。これが私のコードの関連部分の小さなスニペットです:
# [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の質問を読みました。私はこの問題に対して2つまたは3つの可能な解決策しか見ていません:
1)クラスでfunction1
メソッドを宣言するのではなく、プラグインが新しいインスタンスを作成するときに属性として設定するだけです。Model
# [in the plugin file]
def function1(*args, **kwargs):
# ....
return
newmodel.function1 = function1
そして、必要なときにいつでもそれを呼び出します。その場合、function1
オブジェクトの属性はおそらくModel
開始されます。None
その1つの注意点は、の「デフォルトの動作」がないことです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.
3)モジュールtypes
とそのモジュールを使用するMethodType
...私の場合、それが適切かどうかはわかりません...しかし、私は間違っている可能性があります。
この長い質問の後でわかるように、私はそのようなPython機能にあまり精通しておらず、デコレータについての私の理解は今では本当に貧弱です。いくつかのドキュメントを読み続けている間、問題を処理するための方向性がわからないので、ここで質問する価値があるかもしれないと思いました。
解決
Senderleの答えの美しさは、それが本当に単純で明白であるということです...そしてそれを逃したのは残念です。その質問でSOを汚染してすみません。