web-dev-qa-db-ja.com

Python mixinsはアンチパターンですか?

pylintと他の静的分析ツールがすべてを知っているわけではなく、時にはそれらのアドバイスに従わない必要があることを十分に認識しています。 (これは、conventionsだけでなく、さまざまなクラスのメッセージに適用されます。)


私のようなクラスがある場合

class related_methods():

    def a_method(self):
        self.stack.function(self.my_var)

class more_methods():

    def b_method(self):
        self.otherfunc()

class implement_methods(related_methods, more_methods):

    def __init__(self):
        self.stack  = some()
        self.my_var = other()

    def otherfunc(self):
        self.a_method()

明らかに、それは不自然です。 必要に応じて、より良い例を示します

このスタイルは「ミックスイン」を使って呼ばれていると思います。

他のツールと同様に、pylintは、-21.67 / 10およびmore_methodsselfまたは属性otherfuncstack、anndがないと考えているため、このコードをrelated_methodsで評価しますmy_varは、コードを実行しないと、related_methodsmore_methodsimplement_methodsに混在しているように見えないためです。

コンパイラーと静的分析ツールは常に停止問題を解決できるわけではありません ですが、これは確かにimplement_methodsによって継承されたものを見るとこれが完全に有効であることを示す場合であり、それは非常に重要です簡単なこと。

静的分析ツールがこの有効な(私は思う)OOPパターンを拒否するのはなぜですか?

どちらか:

  1. 彼らは継承をチェックする試行さえしません

  2. 慣用的で読みやすいPythonでは、ミックスインは推奨されません。


#1は明らかに正しくありません。_pylintに、unittest.TestCaseを使用するself.assertEqualを継承するクラス(unittest.TestCaseでのみ定義されているもの)を教えてもらった場合、文句を言う。

ミックスインは非Pythonicですか?

39
cat

ミックスインは、ツールで検討された使用例ではありません。それは、それが必ずしも悪いユースケースであることを意味するのではなく、Pythonの珍しいものです。

ミックスインが特定のインスタンスで適切に使用されるかどうかは、別の問題です。私が最も頻繁に目にするミックスインのアンチパターンは、1つの組み合わせの混合のみが意図されている場合にのみ、ミックスインを使用しています。これは、神のクラスを隠すための迂回的な方法にすぎません。 今のところスワップアウトしたり、ミックスインの1つを除外したりする理由がわからない場合は、ミックスインであってはなりません。

18
Karl Bielefeldt

Mixinsは、絶対にPythonicになることができると私は信じています。ただし、リンターを沈黙させ、Mixinsの可読性を向上させる慣用的な方法は、(1)define abstract methods で、Mixinの子が実装する必要があるメソッドを明示的に定義します。 (2)子が初期化する必要があるMixinデータメンバーのNone値フィールドを事前定義します。

このパターンをあなたの例に適用する:

from abc import ABC, abstractmethod


class related_methods():
    my_var = None
    stack = None

    def a_method(self):
        self.stack.function(self.my_var)


class more_methods(ABC):
    @abstractmethod
    def otherfunc(self):
        pass

    def b_method(self):
        self.otherfunc()


class implement_methods(related_methods, more_methods):
    def __init__(self):
        self.stack  = some()
        self.my_var = other()

    def otherfunc(self):
        self.a_method()
17
UltraBird

私は思いますミックスインは良いことですが、この場合、パイリントも正しいと思います。免責事項:オピニオンベースのものが続きます。

良いクラスには、ミックスインが含まれ、明確な責任が1つあります。理想的には、ミックスインはアクセスするすべての状態と、それを処理するロジックを運ぶ必要があります。例えば。良いmixinはlast_updatedフィールドをORMモデルクラスに追加し、それを設定するためのロジックを提供し、最も古い/最新のレコードを検索するメソッドを提供します。

宣言されていないインスタンスメンバー(変数とメソッド)を参照すると、少し奇妙に見えます。

適切なアプローチは、手元のタスクに大きく依存します。

これは、関連する状態のビットが保持されているミックスインである可能性があります。

下位クラスの実装の違いがサブクラスに属している一方で、ミックスインを介して現在配布しているメソッドが基本クラスにある別のクラス階層である可能性があります。これは、スタック操作の場合に最も適しているように見えます。

メソッドを1つまたは2つ追加するクラスデコレータである場合があります。これは通常、メソッドの生成に影響を与えるためにいくつかの引数をデコレータに渡す必要がある場合に意味があります。

あなたの問題を述べ、あなたのより大きなデザインの懸念を説明してください、そしてあなたのケースで何かがアンチパターンであるかどうか私たちは議論することができます。

9
9000

リンターは、クラスをミックスインとして使用していることを認識していません。 Pylintは、クラス名の末尾に「mixin」または「Mixin」という接尾辞を追加すると、ミックスインを使用することを認識しており、リンターは文句を言いません。

linter_without_mixinslinter2_with_mixin

ミックスイン自体は悪いものでも良いものでもありません。単なるツールです。あなたはそれらを良い使い方か悪い使い方にします。

8
dotoscat

ミックスインは大丈夫ですか?

Python mixinsはアンチパターンですか?

ミックスインは推奨されていません-多重継承の良いユースケースです。

リンターが不満を言うのはなぜですか?

otherfuncstack、およびmy_varがどこから来ているのかがわからないため、Pylintは明らかに文句を言っています。

取るに足らない?

これらの2つのメソッドを別々の親クラスに分ける理由がすぐには明らかではありません。問題の例か、ここに示す簡単なリンクされた例のどちらかです。

201
202 class OpCore():
203     # nothing runs without these
204
205 class OpLogik(): 
206     # logic methods... 
207 
208 class OpString(): 
209     # string things
210 
211 
212 class Stack(OpCore, OpLogik, OpString): 
213 
214     "the mixin mixer of the above mixins" 

ミックスインとノイズのコスト

あなたがしていることのコストはあなたのリンターレポートを騒がしくしています。このノイズにより、コードのより重要な問題がわかりにくくなる場合があります。これは重要なコストです。もう1つのコストは、相互に関連するコードを異なる名前空間に分離しているため、プログラマーがその意味を見つけにくくなる可能性があることです。

結論

継承により、コードの再利用が可能になります。あなたがあなたのミックスインでコードを再利用するなら、すばらしいことですが、おそらく他の可能なコストを上回る価値を生み出しています。コード行のコードの再利用/重複排除が得られない場合、ミックスインの価値はあまり得られないでしょう。その時点で、ノイズのコストはメリットよりも大きいと思います。

1
Aaron Hall