2011-09-10 10 views

risposta

116

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

spam = SomeObject() 
print(spam.eggs) 

si guarda eggs in spam, e poi esamina eggs per vedere se ha un __get__, __set__ o __delete__ metodo & thinsp; — e thinsp; se lo fa, è una proprietà. Se è una proprietà, invece di restituire l'oggetto eggs (come si farebbe per qualsiasi altro attributo) che chiamerà il metodo __get__ (dal momento che stavamo facendo ricerca) e tornare qualunque cosa metodo restituisce.

Maggiori informazioni su Python's data model and descriptors.

+8

Migliore risposta dell'intero set, non ultimo perché fornisce dettagli concreti e concreti su come Python stesso gestisce questo nel back-end. +1. :) –

17

In termini di lingua generale una proprietà e un attributo sono la stessa cosa. Tuttavia, esiste un decoratore di proprietà in Python che fornisce accesso getter/setter a un attributo (o ad 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 
+0

la prego di citare anche il risultato atteso di questo codice? –

+0

Cosa intendi? Non è quello in fondo al codice? – six8

28

Con una proprietà che ha il controllo completo sulle sue getter, setter e deleter metodi, cosa che non hanno (se non si utilizza caveat) 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 
+0

Questo ("controllo completo") può essere eseguito anche con attributi "non di proprietà", anche se senza decoratori semplici. –

+1

quello che ho chiamato un avvertimento ... – neurino

+3

Mi piace che questa risposta fornisce un esempio realistico e utile. Ritengo che troppe risposte su questo sito spieghino inutilmente come funzionano le cose sul back-end senza chiarire come l'utente debba interagire con loro. Se uno non capisce perché/quando utilizzare alcune funzionalità, non ha senso sapere come funziona dietro le quinte. – Tom

11

La struttura consente di ottenere valori impostati e come si farebbe normali attributi, ma sotto c'è un metodo essere chiamato traducendola in un getter e setter per voi. In realtà è solo una comodità ridurre il numero di gettatori e setter.

consente di dire, per esempio, si ha una classe che ha tenuto alcune coordinate x e y per qualcosa di cui avete bisogno. Per impostare li si potrebbe desiderare di fare qualcosa di simile:

myObj.x = 5 
myObj.y = 10 

Questo è molto più facile da guardare e pensare che scrivere:

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

Il problema è, che cosa se un giorno le modifiche classe come che devi compensare il tuo xey con un certo valore? Ora è necessario entrare e modificare la definizione della classe e tutto il codice che la chiama, il che potrebbe richiedere molto tempo e essere soggetto a errori. La proprietà consente di utilizzare la sintassi precedente pur offrendo la flessibilità del cambiamento di quest'ultima.

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

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

1

ho imparato 2 differenze da site di Bernd Klein, in sintesi:

1. proprietà è un modo più conveniente per fare incapsulamento dei dati.

ex: Se hai una lunghezza di attributo pubblico di Object, in seguito, il tuo progetto richiede di incapsularlo, i.e: cambiare a privati ​​e fornire getter e setter => è necessario 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 si utilizza @property e @ lenght.setter => non è necessario per cambiano i 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 accedere direttamente da fuori sid e, l'unico modo al di fuori della classe di interagire con loro è attraverso la proprietà condition

0

C'è anche una differenza non ovvia che uso per memorizzare o aggiornare i dati, spesso abbiamo una funzione collegata all'attributo di classe. Per esempio ho bisogno di leggere il file una volta e tenere aggiornati i contenuti assegnato all'attributo modo che il valore viene 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 

uscita:

func running 
func value 
func value 

Abbiamo accede l'attributo di due volte, ma la nostra funzione è stato licenziato solo una volta. Cambiare l'esempio precedente di utilizzare la proprietà causerà il valore dell'attributo di aggiornamento ogni volta che si accede:

class Misc(): 

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

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

uscita:

func running 
func value 
func running 
func value 
Problemi correlati