2009-10-12 10 views
61

少し構文的な砂糖を除いて、property()はうまくいきません。Pythonで組み込み関数のプロパティ()を使用する方法と使用方法

確かに、それはa.setB(2)の代わりにa.b=2を書くことができてうれしいですが、ab = 2は、単純な代入は、いくつかの予期しない結果が発生する可能性があるため、このようa.b=2をのいずれかとして、トラブルのためのレシピのように見えるではないという事実を隠します実際にa.b1になります。または例外が発生します。またはパフォーマンスの問題。それとも、混乱しているだけですか?

私はそれをうまく利用するための具体的な例を教えていただけますか? (問題のあるコードを修正するためにそれを使用することはカウントされません;-)

+11

あなたは間違っています。 .setB()は、実際のプロパティを持たない言語用のパッチです。 Python、C#およびその他のものはプロパティを持ち、解決方法は同じです。 – liori

+4

私はJavaの方が悪いことを知っています。これはゲッターとセッターをすべての属性に書き込むことです。後ですべてをリファクタリングするのは苦痛だからです。 –

+4

@gnibbler、プロパティをサポートしていない言語(またはプロパティよりもはるかに前のPythonの '__getattr__/__setattr__'などのやや同等の可能性)では、他に" Javaの人 " C++などの言語はカプセル化を維持するために可能性があります)。 –

答えて

113

は、Javaのように、彼らを想定しないし、言うことが、何もしないと予想している - x.getB()は論理属性bの現在の値を返しますが、何もしなかった場合、それは驚くだろう、またはx.setB(2)が何らかの内部作業を行う必要がある場合でも何でもした場合x.getB()返信2

はしかし、何の言語に課さ保証この予想される動作について、名前getまたはsetで始まるメソッドの本体に、すなわち、コンパイラ強制制約はありません。むしろ、それは常識まで残って、社会的慣習、 "スタイルガイド"、およびテスト。

x.bの挙動がアクセスし、割り当てようx.b = 2として、(含むがパイソンに限定されるものではない言語のセット)の特性を持っている言語では、ゲッターとセッターメソッドと同じ正確あります例えば、Java:同じ期待、言語強制保証の同じ欠如。

プロパティの最初の勝利は、構文と読みやすさです。例えば、代わりに神々への復讐のために叫んで

x.b += 1 
明白なの

x.setB(x.getB() + 1) 

を記述すること。プロパティをサポートする言語では、クラスのユーザーがそのようなByzantine定型文の旋律を通過するように強制する正当な理由は全くなく、コードの可読性には何の影響も与えません。

具体的には、getterやsetterの代わりにプロパティ(または他の記述子)を使用することにはもう1つ大きな利点があります。クラスを再編成して基礎となるsetterとgetterがもう必要なくなる場合、クラスの公開されているAPIを破ることなく)単にそれらのメソッドとそれに依存するプロパティを削除して、をxのクラスの通常の「格納済み」属性にします。

Pythonでは、メソッドを経由せずに直接(実行可能な場合)作業を行うことが重要な最適化であり、プロパティを体系的に使用することで、いつでもこの最適化を実行できます。メソッドおよびプロパティを介してアクセスおよび/または設定時に計算を必要とする)。あなたは、ユーザーのコードの可読性に影響を与える超えたゲッターとセッターの代わりのプロパティを、使用している場合

だから、あなたはが無償で無駄マシンサイクル(およびそれらのサイクルの中に自分のコンピュータに行くエネルギーがある;-) 、再び何の理由もありません。

プロパティに対するあなたの唯一の引数は、 「外部のユーザーは、割り当ての結果として通常は副作用を期待しません」ということです。 (getterやsetterが普及しているJavaなどの言語で)同じユーザーがセッターを呼び出した結果として(観察可能な)「副作用」を期待しないという事実を忘れている;-)。彼らは妥当な期待です。クラスの作者として、あなたのセッターとゲッターが直接的に、あるいは財産を通して使用されても、違いはありません。目に見える重要な副作用を持つメソッドがある場合は、ではなくという名前を付けてください。getThissetThat、およびプロパティで使用しないでください。

プロパティが「実装を隠す」苦情は全く不当である:最もOOPのすべては、情報隠蔽を実装についてです - 外の世界への論理インタフェースを提示し、それが最善として内部的にそれを実装するためのクラスが責任を作りますできる。ゲッターとセッターは、プロパティとまったく同じように、この目標に向けたツールです。プロパティは、より良い仕事をします(それをサポートする言語で;-)。

+4

また、C++の演算子のオーバーロード。同じ「外部ユーザーは期待しないだろう...」という議論が適用されます。ユーザーに知らせたくない場合もあります。そのような場合、ユーザーに驚かないようにすることはあなた次第です。 –

+4

@Oren、良い点、Pythonの演算子オーバーロードはC++とよく似ています(代入は演算子ではないのでオーバーロードすることはできませんが、一般的な概念は似ています)。コーダーの礼儀、懲らしめ、そして常識を避けてください。 「__add__」は自分自身を変更したり、リモートで何もしなくても何かを追加したりしています。つまり、オペレータのオーバーロードは上品で賢明に使われたときに悪いことではありません(Javaのデザイナーは、 - )。 –

+0

"...(クラスの公開されたAPIを壊さずに)単純にこれらのメソッドとそれに依存するプロパティを削除して、xのクラスの通常の"保存 "属性を"論理 "のものにして計算します。 - ???私はこれを理解していない、プロパティを構成する基本的な内部属性を変更する場合、プロパティによって提供されるパブリック "インターフェイス"は変更する必要はありませんが、これはゲッター/セッターにも当てはまります。両方とも、オブジェクトの内部にあるべき値よりも上の抽象レイヤーです。ここで何を言おうとしていますか? –

30

実際に必要になるまでゲッターとセッターを書く必要がないようにすることです。

だから、あなたが書いたオフを開始します

class MyClass(object): 
    def __init__(self): 
     self.myval = 4 

が明らかになりましたmyobj.myval = 5を書くことができます。

しかし、後で、同時に賢明なことをしたいと思うので、あなたはセッターが必要と判断します。しかし、クラスを使用するすべてのコードを変更する必要はありません。つまり、セッターを@propertyデコレータにラップするだけで、すべて動作します。

+1

あなたの例はまさに私が「問題のあるコードにパッチを当てる」ことを意味していました...まあ「問題がある」というのは正しい単語ではありませんが、パッチIMOです。 – olamundo

+0

私は@olamundoの考えを裏付けました。あまりにもしばしば、変数がセッター/ゲッターにいくつかのロジックを追加し、互換性を壊さないために '@property 'になることを見てきました。これは意図的に '@property'の副作用をもたらし、将来のプログラマにとっては同じコードで混乱します。 –

5

基本的な理由は、実際にはそれがよりよく見えるということです。それはより多くのpythonicです。特に図書館の場合。 something.getValue()はsomething.valueより劣って見えます

plone(かなり大きいCMS)では、値を保存したり、再度インデックスを作成するなど、多くのことを行うdocument.setTitle()を使用していました。 。ちょうどdocument.title = '何か'をやっている方がよかったです。あなたは、とにかく舞台裏でたくさんのことが起こっていることを知っています。

14

しかしa.b = 2が 単純な代入はあなたががその事実を隠していないトラブル

のレシピ のように見えるではないという事実を隠します。その事実は決してそこにはなかった。これはPythonです。これは高水準の言語です。アセンブリではありません。その中にある "単純な"ステートメントのほとんどは、単一のCPU命令にまで沸き立っています。シンプルさを課題に読み込むことは、そこにないものを読むことです。

x.b = cと言うとき、おそらくあなたが考えるべきことは、「何が起こったのか、x.bは現在cでなければならない」ということです。ゲッターとセッターに依存している言語で

+0

私はあなたの言ったことに同意しますが、私はまだ外部のユーザーが割り当ての結果として影響を受けるとは思わないという意味で、内部の仕組みを「隠している」と考えています。 – olamundo

+5

それは本当のnoamです。一方で、OOPは、存在するインターフェースを除いてブラックボックスのオブジェクトを持つことに関するものなので、不思議で魔法のようなものが表面の下で行われていると思われるはずです; –

+2

ab = 2はほとんどありません代入がx = 2よりも大きい。それらが異なって実装されている場合、OOPの全体のポイントは実装の詳細を隠すことである。 a.b = 2が何かを490に設定すると、とにかくa.setB(2)によって解決されない厄介な副作用です。暗黙のうちにab = 2が非常に速い操作であると考えるならば、あなたはPythonであり、少なくともCよりも遅い順序であることを認識するべきです。 – Clueless

2

ここに私の古い例があります。私は "void dt_setcharge(int atom_handle、int new_charge)"や "int dt_getcharge(int atom_handle)"のような関数を持ったCライブラリをラップしました。 Pythonレベルで "atom.charge = atom.charge + 1"を実行したかったのです。

「プロパティ」デコレータはそれを簡単にします。何かのように:私はこのパッケージを書いたとき

class Atom(object): 
    def __init__(self, handle): 
     self.handle = handle 
    def _get_charge(self): 
     return dt_getcharge(self.handle) 
    def _set_charge(self, charge): 
     dt_setcharge(self.handle, charge) 
    charge = property(_get_charge, _set_charge) 

10年前、私はそれが可能になった__getattr__と__setattr__を使用する必要がありましたが、実装は、より多くのエラーが発生しやすくしました。

class Atom: 
    def __init__(self, handle): 
     self.handle = handle 
    def __getattr__(self, name): 
     if name == "charge": 
      return dt_getcharge(self.handle) 
     raise AttributeError(name) 
    def __setattr__(self, name, value): 
     if name == "charge": 
      dt_setcharge(self.handle, value) 
     else: 
      self.__dict__[name] = value 
3

あなたは正しいです、それは構文的な砂糖です。問題のあるコードの定義に応じて、それをうまく使用していない可能性があります。

アプリケーションで広く使用されているFooクラスがあるとします。今、このアプリケーションはかなり大きくなっており、非常に普及しているwebappだと言えます。

Fooがボトルネックを引き起こしていることを確認します。おそらく、高速化のためにFooにキャッシュを追加することは可能です。プロパティを使用すると、Foo以外のコードやテストを変更することなく、プロパティを使用できます。

もちろんこれは問題のあるコードですが、$$をたくさん保存するだけですぐに修正できます。

あなたが数百人または数千人のユーザーがいる図書館にFooがある場合はどうなりますか?さて、Fooの最新バージョンにアップグレードするときに高価なリファクタリングをするように伝えなければならなくなりました。

リリースノートには、段落の移植ガイドではなく、Fooについてのラインアイテムがあります。

経験豊富なPythonプログラマーは、以外では、a.b==2以外に多くのことを期待していませんが、それでもそうでないかもしれません。クラス内で起こることは、それ自身のビジネスです。

0

getterとsetterは多くの目的で必要とされ、コードに対して透過的であるため非常に便利です。オブジェクトに何かプロパティの高さがある場合は、Something.height = 10という値を割り当てますが、heightにgetterとsetterがある場合は、その値を代入するときにminやmaxの検証など、値は、高さが変更されたためにイベントがトリガされ、新しい高さ値の関数で他の値が自動的に設定され、Something.height値が割り当てられた瞬間に発生する可能性があります。コード内でそれらを呼び出す必要はなく、プロパティ値を読み書きすると自動的に実行されることを覚えておいてください。ある意味では、プロパティXが値を変更するときとプロパティXの値が読み込まれるときのイベントプロシージャのようなものです。

関連する問題