クラスメソッドから「return self」の目的は?


46

私はオープンソースプロジェクトでこのようなものに出会いました。インスタンス属性を変更するメソッドは、インスタンスへの参照を返します。この構成の目的は何ですか?

class Foo(object):

  def __init__(self):
    self.myattr = 0

  def bar(self):
    self.myattr += 1
    return self

2
そして、これがjQueryのほとんどすべてが書かれている方法です。ほとんどすべての関数は、jQueryオブジェクトを返します
CaffGeek

11
なぜそのように書かれたコードを信用しないのですか?
sepp2k

回答:


65

連鎖を許可するためです。

例えば:

var Car = function () {
    return {
        gas : 0,
        miles : 0,
        drive : function (d) {
            this.miles += d;
            this.gas -= d;
            return this;
        },
        fill : function (g) {
            this.gas += g;
            return this;
        },
    };
}

今、あなたは言うことができます:

var c = Car();
c.fill(100).drive(50);
c.miles => 50;
c.gas => 50;

20
記録のために、この種の連鎖は一般的に流れるようなインターフェースを持つコードで見られます
ライライアン

10

@Lie Ryanと@Frank Sheararが言及したように、それは「流fluentなインターフェース」と呼ばれていますが、そのパターンは長い間存在していました。

そのパターンの議論の余地のある部分は、オブジェクト指向では可変状態であるため、voidメソッドには暗黙の戻り値のthis種類があります。つまり、更新された状態のオブジェクトは戻り値の種類です。

したがって、可変状態のオブジェクト指向言語では、これら2つはほぼ同等です。

a.doA()
a.doB()
a.doC()

...とは対照的に

a.doA().doB().doC()

過去の人々は、流formなインターフェイスに抵抗していると聞いたことがあります。私が「流fluentなインターフェース」で聞いた別の名前は「列車事故」です;)

しかし、流interfacesなインターフェースはしわを追加するため、「多かれ少なかれ同等」と言います。彼らは「これを返す」必要はありません。彼らは「新しいものを返す」ことができます。それがオブジェクト指向で不変オブジェクトを達成する方法です。

だから、あなたは(擬似コード)を行うクラスAを持つことができます

function doA():
    return new A(value + 1)

function doB():
    return new A(value * 2)

function doC():
    return new A(sqrt(value))

現在、各メソッドは真新しいオブジェクトを返し、初期オブジェクトは変更されません。そして、それはコードをあまり変更せずに不変オブジェクトに入る方法です。


ただし、メソッドがを返す場合、new(...)メモリリークが発生します。
-smci

@smciこれは、言語、実装、および使用法に大きく依存します。確かに、C ++の場合は、あちこちでメモリリークが発生する可能性があります。しかし、これはすべて、ガベージコレクタを備えた言語によって簡単にクリーンアップされます。一部の実装(GCの有無にかかわらず)では、これらの新しいオブジェクトの1つが使用されず、実際には何も割り当てられないことを検出することさえあります。
8ビットツリー

@ 8bittree:Pythonについて話しているのですが、この質問は8年前にPythonとタグ付けされました。Python GCはあまり良くないので、そもそもメモリをリークしないことをお勧めします。__init__繰り返し呼び出すとオーバーヘッドも発生します。
SMCI

8

ほとんどの言語は「return self」イディオムを認識しており、行で使用されていない場合は無視します。ただし、Pythonでは、関数Noneがデフォルトで戻ることは注目に値します。

私がCS学校にいたとき、私のインストラクターは、機能、手順、ルーチン、および方法の違いについて非常に多くのことをしました。シャープなエッセイの質問の多くは、シャープペンシルがそのすべてについて私の手で熱くなり、徹底的に解決されました。

selfを返すことは、クラスメソッドを作成する決定的なオブジェクト指向の方法ですが、Pythonでは複数の戻り値、タプル、リスト、オブジェクト、プリミティブ、またはNoneを使用できます。

チェーンとは、最後の操作に対する答えを次の操作に入れることであり、Pythonのランタイムはそのようなことを最適化できます。リスト内包表記は、この組み込み形式です。(とてもパワフルな!)

したがって、Pythonでは、すべてのメソッドまたは関数が値を返すことはそれほど重要ではないため、デフォルトはNoneです。

プログラム内のすべてのアクションは、成功、失敗、または結果を呼び出し側のコンテキストまたはオブジェクトに報告する必要がありますが、ここではDOD ADA要件について説明していなかったという考え方があります。メソッドからフィードバックを取得する必要がある場合は、先に進むかどうかにかかわらず、一貫性を保つようにしてください。

メソッドが失敗する可能性がある場合、成功または失敗を返すか、処理する例外を発生させる必要があります。

1つの注意点は、return selfイディオムを使用すると、Pythonですべてのメソッドを変数に割り当てることができ、実際にオブジェクトを取得しているときにデータ結果またはリストを取得していると思われることです。

これを行おうとすると、型制限言語は叫び声を上げて叫びますが、解釈された言語(Python、Lua、Lisp)ははるかに動的です。


4

Smalltalkでは、明示的に何かを返さないすべてのメソッドには、暗黙的な「自己を返す」ことがあります。

(a)すべてのメソッドが何かを返すようにすると、コンピューティングモデルがより均一になり、(b)メソッドがselfを返すので非常に便利だからです。Josh Kが良い例です。


興味深いのはPython、明示的に何かを返さないすべてのメソッドには、暗黙の「Return None」があります。
ジョブ

2

オブジェクトを返すことの長所(return self

  • 例:

    print(foo.modify1().modify2())
    
    # instaed of
    foo.modify1()
    foo.modify2()
    print(foo)
    
  • プログラミングコミュニティでより一般的なスタイル(私は思う)。

オブジェクトを変更することの長所(no return self

  • return他の目的に使用する能力。
  • Guido van Rossum はこのスタイルを承認しています(彼の主張には同意しません)。
  • Pythonコミュニティでより人気のあるスタイル(私は思う)。
  • デフォルト(ソースコードが少ない)。

グイドの主張は私に説得力があります。特に、読者が「各メソッドに精通している必要があります」について話している部分、つまり、これが自己チェーンか出力チェーンかコンボかを判断する必要があります。チェーン
ナス

@Nat文字列処理操作は、他の操作と基本的にどのように異なりますか?
xged

違いは、文字列の場合、毎回完全に異なる新しいオブジェクトを生成していることです。すなわち、その場でアイテムを変更しません。既存のオブジェクトが変更されていないことは明らかです。戻り値の自己が暗黙的である言語では、逆のことが当てはまりますが、混合環境には問題があるようです
ナス

@Matt Python文字列は不変であることを思い出しました。それは私の質問に完全に答えます。
xged

1
@Matt「既存のオブジェクトが変更されていないことは明らかです」-ただ見ただけでは明らかではありません。
xged
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.