it-swarm.it

Qual è la differenza tra a Python "proprietà" e "attributo"?

Sono generalmente confuso sulla differenza tra una "proprietà" e un "attributo" e non riesco a trovare una grande risorsa per dettagliare concisamente le differenze.

116
Carson

Le proprietà sono un tipo speciale di attributo. Fondamentalmente, quando Python incontra il seguente codice:

spam = SomeObject()
print(spam.eggs)

cerca eggs in spam, quindi esamina eggs per vedere se ha un __get__, __set__, o __delete__ metodo - se lo fa, è una proprietà. Se è una proprietà, invece di restituire semplicemente l'oggetto eggs (come farebbe per qualsiasi altro attributo) chiamerà __get__ metodo (dal momento che stavamo eseguendo la ricerca) e restituisce qualunque cosa restituisca quel metodo.

Ulteriori informazioni su modello di dati e descrittori di Python .

164
Ethan Furman

Con una proprietà hai il controllo completo sui suoi metodi getter, setter e deleter, che non hai (se non usi avvertimenti) con un attributo.

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
46
neurino

In termini generali, una proprietà e un attributo sono la stessa cosa. Tuttavia, esiste un decoratore di proprietà in Python che fornisce l'accesso getter/setter a un attributo (o altri dati).

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
17
six8

La proprietà ti permette di ottenere e impostare valori come faresti con gli attributi normali, ma sotto c'è un metodo che viene chiamato traducendolo in un getter e setter per te. È davvero solo una comodità ridurre la piastra di chiamata di getter e setter.

Diciamo ad esempio che avevi una classe che conteneva alcune coordinate xey per qualcosa di cui avevi bisogno. Per impostarli potresti voler fare qualcosa del tipo:

myObj.x = 5
myObj.y = 10

È molto più facile da guardare e pensare che scrivere:

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

Il problema è che cosa succede se un giorno la tua classe cambia in modo tale da dover compensare la tua xey da un valore? Ora dovresti entrare e modificare la definizione della classe e tutto il codice che lo chiama, che potrebbe richiedere molto tempo e essere soggetto a errori. La proprietà consente di utilizzare la prima sintassi offrendo la flessibilità di cambiare quest'ultima.

In Python, puoi definire getter, setter ed eliminare metodi con la funzione proprietà. Se vuoi solo la proprietà read, c'è anche un decoratore @property che puoi aggiungere sopra il tuo metodo.

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

11
falcojr

Ho imparato 2 differenze da sito di Bernd Klein, in sintesi:

1. La proprietà è un modo più conveniente per eseguire l'incapsulamento dei dati.

es: se hai una lunghezza di attributo pubblica di Object, in seguito, il tuo progetto ti richiede di incapsularlo, cioè: cambiarlo in privato e fornire getter e setter => devi cambiare molti dei codici che hai scritto prima:

#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

Se usi @property e @ lenght.setter => non devi cambiare quei vecchi codici

2. Una proprietà può incapsulare più attributi

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 questo esempio, __physic_health e __mental_health sono privati ​​e non è possibile accedervi direttamente dall'esterno, l'unico modo in cui la classe esterna interagisce con loro è attraverso la proprietà condition

4
Tin Luu

C'è anche una differenza non ovvia che uso per memorizzare nella cache o aggiornare i dati, spesso abbiamo una funzione connessa all'attributo class. Ad esempio, devo leggere il file una volta e mantenere il contenuto assegnato all'attributo in modo che il valore venga memorizzato nella cache:

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

Produzione:

func running
func value
func value

Abbiamo avuto accesso all'attributo due volte ma la nostra funzione è stata attivata una sola volta. La modifica dell'esempio precedente per utilizzare la proprietà comporterà l'aggiornamento del valore dell'attributo ogni volta che si accede ad esso:

class Misc():

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

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

Produzione:

func running
func value
func running
func value
2
brc