web-dev-qa-db-ja.com

Pythonの委任パターン:不人気ですか? Pythonicではないと考えられていますか?

Ruby/Railsの人として、私はメソッドの委任をよく扱います。メソッドを合成オブジェクトまたは定数に委譲すると便利なことがよくあります。 Rubyデリゲートを簡単に構築するためのdef_delegatorヘルパーメソッドもあり、RailsのActiveSupportはdelegateとの組み込みのインターフェースを改善します。

それでもPythonを調べたところ、stdlibにもPyPiにも、委任を作成するヘルパーは見つかりませんでした。 StackOverflowで手動で__getitem__をオーバーライドして委任者を宣言することをお勧めします。

だから私は尋ねなければなりません:このパターンは非Pythonicと見なされますか?それとも何か不足していますか?

ありがとうございました。

3
art-solopov

委任は可能ですが、実際には一般的ではありません。

  1. 委任に到達する可能性のある多くの場合、多重継承を使用することもできます。 Rubyには多重継承がないため、ミックスインや委任などの他のアプローチを使用する必要があります。Pythonは、ここでより柔軟なセマンティクスを持っています。

  2. ___getattr___または___getattribute___に基づく委任は複雑であり、適切に実装するにはPythonの低レベルの詳細を十分に理解する必要があります。これは、記述子プロトコル、およびdir()またはhelp()などのイントロスペクション機能、および___str___または___add___などの他のdunderメソッドと相互作用します。暗黙的に委任することはできません。メソッドをダンダーしますが、委任を実行するメソッドを実装する必要があります。

  3. この複雑さは非Pythonicとして認識されます。 「明示的は暗黙的よりも優れています。」

  4. ___getattr___による委任の代わりに、委任するメソッドまたはプロパティを手動で実装することもできます。メタプログラミングを使用して(メタクラスまたはクラスデコレーターを介して)これを簡略化するか、記述子プロトコルを使用して、インスタンスを介してアクセスしたときに委任を実行するクラスメンバーを作成できます。

  5. 特にリフレクションまたはメタプログラミング機能に基づく場合、委任は低速です。

記述子は、クラスメンバーを実装するオブジェクトです。クラスまたはインスタンスメンバーにアクセスするかどうかに応じて、さまざまな方法で呼び出されます。関数とプロパティは一般的に使用される記述子の実装ですが、ユーザー定義の記述子を作成できます。 ___get___メソッドを持つものはすべて記述子として使用できます。 1つのプロジェクトで、委任を実行するための記述子を実装しました。次のように使用されます:

_class Foo:
  delegated_method = delegate('TargetType', 'delegated_method', to='_target')

  def __init__(self, target):
    self._target = target

# Foo().delegated_method => Foo()._target.delegated_method
# Foo.delegated_method => returns the descriptor
# help(Foo.delegated_method)  # works
_

結局、そのプロジェクトでは記述子を使用することの複雑さとパフォーマンスへの影響が大きすぎたので、代わりに委任を明示的に説明しました。

5
amon