Was ist der Unterschied zwischen einer Python-Eigenschaft und einem Attribut?

146

Ich bin im Allgemeinen verwirrt über den Unterschied zwischen einer "Eigenschaft" und einem "Attribut" und kann keine großartige Ressource finden, um die Unterschiede genau zu beschreiben.

Carson
quelle

Antworten:

184

Eigenschaften sind eine besondere Art von Attribut. Grundsätzlich, wenn Python auf folgenden Code stößt:

spam = SomeObject()
print(spam.eggs)

es schaut nach oben eggsin spamund prüft dann , eggsum zu sehen , ob es einen hat __get__, __set__oder __delete__Verfahren - wenn es funktioniert, ist es eine Eigenschaft ist. Wenn es sich um eine Eigenschaft handelt, wird anstelle nur des eggsObjekts (wie bei jedem anderen Attribut) die __get__Methode aufgerufen (da wir nachgeschlagen haben) und alles zurückgegeben, was diese Methode zurückgibt.

Weitere Informationen zum Datenmodell und zu den Deskriptoren von Python .

Ethan Furman
quelle
Es hört sich so an, als ob Eigenschaften eine zusätzliche Verarbeitung erfordern, um auf den Zielwert zuzugreifen. Wissen Sie, wie bedeutend / viel langsamer er ist?
Martineau
@martineau: Nun, es gibt einen zusätzlichen Funktionsaufruf, aber höchstwahrscheinlich hängt die zusätzliche Arbeit und Zeit davon ab, wie viel die Eigenschaft tut (allgemeiner Rat: Eigenschaften zum Verstecken von E / A tun / nicht / verwenden).
Ethan Furman
56

Mit einer Eigenschaft haben Sie die vollständige Kontrolle über ihre Getter-, Setter- und Deleter-Methoden, die Sie nicht (wenn Sie keine Einschränkungen verwenden) mit einem Attribut haben.

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
Neurino
quelle
Dies ("vollständige Kontrolle") kann jedoch auch mit "Nicht-Eigenschafts" -Attributen erfolgen, nur ohne solch einfache Dekorateure.
8
Mir gefällt, dass diese Antwort ein realistisches und nützliches Beispiel darstellt. Ich bin der Meinung, dass zu viele Antworten auf dieser Website unnötig erklären, wie die Dinge im Back-End funktionieren, ohne zu klären, wie der Benutzer mit ihnen interagieren soll. Wenn man nicht versteht, warum / wann man Funktionen nutzen soll, macht es keinen Sinn zu wissen, wie sie hinter den Kulissen funktionieren.
Tom
Diese Antwort verstößt gegen das "Zen of Python - Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun". Es gibt zwei Möglichkeiten, den x-Wert festzulegen.
Tin Luu
@TinLuu - Es gibt nur eine Möglichkeit, den Wert von x festzulegen. Es gibt auch nur eine Möglichkeit, den Wert von _x festzulegen. Die Tatsache, dass sie dasselbe sind, ist ein Implementierungsdetail. Der weise Benutzer dieser Klasse verwendet _x nicht.
beleuchtet
1
@TinLuu - Ich denke, wir sagen beide dasselbe aus entgegengesetzten Richtungen. Der Benutzer der Klasse sollte nur sehen x. Einweg. Wenn der Benutzer der Klasse von _x erfährt, verwendet er es auf eigenes Risiko.
beleuchtet
19

Im Allgemeinen sind eine Eigenschaft und ein Attribut dasselbe. In Python gibt es jedoch einen Eigenschaftsdekorator, der Getter / Setter-Zugriff auf ein Attribut (oder andere Daten) ermöglicht.

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
six8
quelle
1
Könnten Sie bitte auch das erwartete Ergebnis dieses Codes erwähnen?
Hasan Iqbal
2
Was meinst du? Ist das nicht am Ende des Codes?
Six8
12

Mit der Eigenschaft können Sie Werte wie normale Attribute abrufen und festlegen. Darunter befindet sich jedoch eine Methode, die aufgerufen wird, um sie in einen Getter und Setter für Sie zu übersetzen. Es ist wirklich nur eine Annehmlichkeit, die Kesselplatte von Calling Getter und Setter zu reduzieren.

Nehmen wir zum Beispiel an, Sie hatten eine Klasse, die einige x- und y-Koordinaten für etwas enthielt, das Sie brauchten. Um sie einzustellen, möchten Sie vielleicht etwas tun wie:

myObj.x = 5
myObj.y = 10

Das ist viel einfacher zu betrachten und zu überlegen als zu schreiben:

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

Das Problem ist, was ist, wenn sich Ihre Klasse eines Tages so ändert, dass Sie Ihr x und y um einen Wert versetzen müssen? Jetzt müssten Sie Ihre Klassendefinition und den gesamten Code, der sie aufruft, ändern, was sehr zeitaufwändig und fehleranfällig sein kann. Mit dieser Eigenschaft können Sie die erstere Syntax verwenden und gleichzeitig die Flexibilität der Änderung der letzteren erhalten.

In Python können Sie mit der Eigenschaftsfunktion Getter, Setter und Löschmethoden definieren. Wenn Sie nur die Eigenschaft read möchten, können Sie über Ihrer Methode auch einen @ property-Dekorator hinzufügen.

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

falcojr
quelle
Nur eine Antwort, die praktisch Sinn machte!
Dude156
8

Zusammenfassend habe ich 2 Unterschiede zum Standort von Bernd Klein gelernt :

1. Eigenschaft ist eine bequemere Methode zur Datenkapselung.

Beispiel: Wenn Sie ein öffentliches Attribut mit der Länge "Objekt" haben, müssen Sie es später in Ihrem Projekt kapseln, dh: es in "privat" ändern und Getter und Setter bereitstellen => Sie müssen viele der zuvor geschriebenen Codes ändern:

#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

Wenn Sie @property und @ lenght.setter => verwenden, müssen Sie diese alten Codes nicht ändern

2. Eine Eigenschaft kann mehrere Attribute kapseln

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!"

In diesem Beispiel __physic_healthund __mental_healthprivat ist und nicht direkt von außerhalb Seite zugegriffen werden kann, ist der einzige Weg , außerhalb des Unterrichts mit ihnen interagieren Throught Eigenschaftcondition

Tin Luu
quelle
8

Es gibt auch einen nicht offensichtlichen Unterschied, den ich zum Zwischenspeichern oder Aktualisieren von Daten verwende. Oft haben wir eine Funktion, die mit dem Klassenattribut verbunden ist. Zum Beispiel muss ich die Datei einmal lesen und den dem Attribut zugewiesenen Inhalt beibehalten, damit der Wert zwischengespeichert wird:

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

Ausgabe:

func running
func value
func value

Wir haben zweimal auf das Attribut zugegriffen, aber unsere Funktion wurde nur einmal ausgelöst. Wenn Sie das obige Beispiel so ändern, dass die Eigenschaft verwendet wird, wird der Wert jedes Mal aktualisiert, wenn Sie darauf zugreifen:

class Misc():

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

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

Ausgabe:

func running
func value
func running
func value
brc
quelle