Pythonの「プロパティ」と「属性」の違いは何ですか?


146

私は一般的に「プロパティ」と「属性」の違いについて混乱しており、違いを簡潔に詳述するための優れたリソースを見つけることができません。

回答:


184

プロパティは特別な種類の属性です。基本的に、Pythonが次のコードを検出した場合:

spam = SomeObject()
print(spam.eggs)

それは見上げeggsspam、次に調べeggs、それが持っているかどうかを確認するために__get____set__または__delete__方法を-それがないならば、それは財産です。それならばあるだけ返すのではなく、プロパティeggs(他の属性のために、それは同じように)オブジェクトをそれが呼び出されます__get__メソッド(ルックアップを行っていたため)、そのメソッドが返すものを返します。

Pythonのデータモデルと記述子に関する詳細情報。


プロパティはターゲット値にアクセスするために追加の処理を必要とするようです...それがどれほど重要で/はるかに遅いか知っていますか?
martineau

@martineau:さて、追加の関数呼び出しが1つありますが、おそらく追加の作業と時間は、プロパティの実行量に依存します(一般的なアドバイス:I / Oを非表示にするためにプロパティを使用する/使用しないでください)。
イーサンファーマン

56

プロパティを使用すると、ゲッターメソッド、セッターメソッド、および削除メソッドを完全に制御できます。これらのメソッドには、属性では(警告を使用しない場合は)ありません。

class A(object):
    _x = 0
    '''A._x is an attribute'''

    @property
    def x(self):
        '''
        A.x is a property
        This is the getter method
        '''
        return self._x

    @x.setter
    def x(self, value):
        """
        This is the setter method
        where I can check it's not assigned a value < 0
        """
        if value < 0:
            raise ValueError("Must be >= 0")
        self._x = value

>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
  File "ex.py", line 15, in <module>
    a.x = -1
  File "ex.py", line 9, in x
    raise ValueError("Must be >= 0")
ValueError: Must be >= 0

これ(「完全な制御」)は、「非プロパティ」属性でも実行できますが、そのような単純なデコレータは必要ありません。

8
この答えが現実的で有用な例を提供するのが好きです。このサイトの回答が多すぎて、ユーザーがどのように操作する必要があるのか​​を明確にせずに、バックエンドでの動作を不必要に説明しているように感じます。一部の機能を使用する理由とタイミングを理解していない場合、それがバックグラウンドでどのように動作するかを理解しても意味がありません。
トム

この答えは、「Pythonの禅-明白な方法が1つ(できれば1つだけ)あるはずです」に違反しています。x値を設定するには2つの方法があります。
Tin Luu

@TinLuu-xの値を設定する方法は1つだけです。_xの値を設定する唯一の方法もあります。それらが同じものであるという事実は、実装の詳細です。このクラスの賢明なユーザーは_xを使用しません。
点灯

1
@TinLuu-両方の視点から同じことを言っていると思います。クラスのユーザーはのみを表示する必要がありますx。一方通行。クラスのユーザーが_xについて知った場合は、自己の責任において使用します。
点灯

19

一般的に言えば、プロパティと属性は同じものです。ただし、Pythonには、属性(または他のデータ)へのゲッター/セッターアクセスを提供するプロパティデコレーターがあります。

class MyObject(object):
    # This is a normal attribute
    foo = 1

    @property
    def bar(self):
        return self.foo

    @bar.setter
    def bar(self, value):
        self.foo = value


obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo

1
このコードの予想される結果についてもお聞かせください。
Hasan Iqbal 2017

2
どういう意味ですか?それはコードの下部にありませんか?
6

12

このプロパティを使用すると、通常の属性と同じように値を取得および設定できますが、その下に、メソッドを取得してゲッターとセッターに変換するメソッドがあります。ゲッターとセッターを呼び出すというボイラープレートを減らすのは本当に便利なことです。

たとえば、必要なもののx座標とy座標を保持するクラスがあるとします。それらを設定するには、次のようなことを行います。

myObj.x = 5
myObj.y = 10

それは書くよりも見て、考えるのがはるかに簡単です:

myObj.setX(5)
myObj.setY(10)

問題は、ある日、クラスを変更して、xとyをある値だけオフセットする必要がある場合はどうなるでしょうか。次に、クラス定義とそれを呼び出すすべてのコードを変更する必要がありますが、これには時間がかかり、エラーが発生しやすくなります。このプロパティを使用すると、前者の構文を使用しながら、後者を柔軟に変更できます。

Pythonでは、プロパティ関数を使用して、getter、setter、およびdeleteメソッドを定義できます。readプロパティだけが必要な場合は、メソッドの上に追加できる@propertyデコレータもあります。

http://docs.python.org/library/functions.html#property


実用的な意味のある答えのみを入力してください。
Dude156

8

サイトから2つの違いを学びました 要約すると、ベルントクラインの。

1.プロパティは、データのカプセル化を行うためのより便利な方法です。

例:パブリック属性の長さのオブジェクトがある場合、後でプロジェクトでカプセル化する必要があります。つまり、プライベートに変更してゲッターとセッターを提供する=>以前に記述したコードの多くを変更する必要があります。

#Old codes
obj1.length=obj1.length+obj2.length
#New codes(Using private attibutes and getter and setter)
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly

@propertyと@ lenght.setter =>を使用する場合、これらの古いコードを変更する必要はありません

2.プロパティは複数の属性をカプセル化できます

class Person:
  def __init__(self, name, physic_health, mental_health):
    self.name=name
    self.__physic_health=physic_health #physic_health is real value in range [0, 5.0]
    self.__mental_health=mental_health #mental_health is real value in range [0, 5.0]
  @property
  def condition(self):
    health=self.__physic_health+self.__mental_health
    if(health<5.0):
      return "I feel bad!"
    elif health<8.0:
      return "I am ok!"
    else:
      return "Great!"

この例では、__physic_health__mental_healthプライベートであり、アウト側から直接アクセスすることはできません、彼らとの唯一の方法の外のクラスの相互作用はthroughtプロパティですcondition


8

データのキャッシュまたは更新に使用する明らかな違いも1つあります。多くの場合、クラス属性に接続された関数があります。たとえば、ファイルを1回読み取って、コンテンツを属性に割り当てたままにして、値がキャッシュされるようにする必要があります。

class Misc():
        def __init__(self):
            self.test = self.test_func()

        def test_func(self):
            print 'func running'
            return 'func value'

cl = Misc()
print cl.test
print cl.test

出力:

func running
func value
func value

属性に2回アクセスしましたが、関数は1回だけ起動されました。上記の例を変更してプロパティを使用すると、アクセスするたびに属性の値が更新されます。

class Misc():

    @property
    def test(self):
        print 'func running'
        return 'func value'

cl = Misc()
print cl.test
print cl.test

出力:

func running
func value
func running
func value
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.