2016-04-18 11 views
2

Wenn ich eine Klasse erstellen, die Eigenschaften speichern muss, wann ist es angebracht, einen Dekorator zu verwenden und wann sollte ich sie einfach in __init__ definieren?Klassenattribute in __init__ vs mit @property deklarieren

Die Gründe, warum ich mir vorstellen kann:

sagen, dass ich eine Klasse wie

class Apple: 
    def __init__(self): 
     self.foodType = "fruit" 
     self.edible = True 
     self.color = "red" 

fein Das funktioniert haben. In diesem Fall ist es mir ziemlich klar, dass ich nicht die Klasse schreiben soll:

class Apple: 
    @property 
    def foodType(self): 
     return "fruit" 
    @property 
    def edible(self): 
     return True 
    @property 
    def color(self): 
     return "red" 

aber sage, dass ich eine kompliziertere Klasse, die langsame Methoden hat (zum Beispiel Daten über das Internet zu holen).

konnte ich diese Zuordnung von Attributen in __init__ implementieren:

class Apple: 
    def __init__(self): 
     self.wikipedia_url = "https://en.wikipedia.org/wiki/Apple" 
     self.wikipedia_article_content = requests.get(self.wikipedia_url).text 

oder ich könnte dies implementieren mit @property:

class Apple: 
    def __init__(self): 
     self.wikipedia_url = "https://en.wikipedia.org/wiki/Apple" 

    @property 
    def wikipedia_article_content(self): 
     return requests.get(self.wikipedia_url).text 

In diesem Fall wird die letztere etwa 50.000-mal schneller ist zu instanziiert. Ich konnte jedoch argumentieren, dass, wenn ich wikipedia_article_content mehrere Male wurde holen, ersteres ist schneller:

a = Apple() 
a.wikipedia_article_content 
a.wikipedia_article_content 
a.wikipedia_article_content 

In diesem Fall ist die ehemalige ~ 3-mal schneller, weil es ein Drittel der Anzahl der Anfragen hat.

Meine Frage

ist der einzige Unterschied zwischen Zuweisung Eigenschaften in diesen beiden Möglichkeiten, die, die ich gedacht habe? Was erlaubt mir sonst noch außer Zeit zu sparen (in einigen Fällen)? Für Eigenschaften, die einige Zeit benötigen, um sie zuzuweisen, gibt es einen "richtigen Weg", um sie zuzuweisen?

Antwort

1

Ja, ich würde vorschlagen, property für diese Argumente zu verwenden. Wenn Sie es faul oder zwischengespeichert machen möchten, können Sie die Eigenschaft subclass entfernen.

Dies ist nur eine Implementierung einer faulen Eigenschaft. Es führt einige Operationen in der Eigenschaft aus und gibt das Ergebnis zurück. Dieses Ergebnis wird in der Klasse unter einem anderen Namen gespeichert, und jeder nachfolgende Aufruf der Eigenschaft gibt nur das gespeicherte Ergebnis zurück.

class LazyProperty(property): 
    def __init__(self, *args, **kwargs): 
     # Let property set everything up 
     super(LazyProperty, self).__init__(*args, **kwargs) 
     # We need a name to save the cached result. If the property is called 
     # "test" save the result as "_test". 
     self._key = '_{0}'.format(self.fget.__name__) 


    def __get__(self, obj, owner=None): 
     # Called on the class not the instance 
     if obj is None: 
      return self 

     # Value is already fetched so just return the stored value 
     elif self._key in obj.__dict__: 
      return obj.__dict__[self._key] 

     # Value is not fetched, so fetch, save and return it 
     else: 
      val = self.fget(obj) 
      obj.__dict__[self._key] = val 
      return val 

Auf diese Weise können Sie den Wert einmal berechnen und sie dann immer zurück:

class Test: 
    def __init__(self): 
     pass 

    @LazyProperty 
    def test(self): 
     print('Doing some very slow stuff.') 
     return 100 

Dies ist, wie es (natürlich Sie es für Ihren Fall anpassen müssen) funktionieren würde:

>>> a = Test() 
>>> a._test # The property hasn't been called so there is no result saved yet. 
AttributeError: 'Test' object has no attribute '_test' 
>>> a.test # First property access will evaluate the code you have in your property 
Doing some very slow stuff. 
100 
>>> a.test # Accessing the property again will give you the saved result 
100 
>>> a._test # Or access the saved result directly 
100 
1

Die Verwendung einer Eigenschaft ermöglicht komplexeres Verhalten. So wie den Artikelinhalt nur dann abrufen, wenn er sich geändert hat und erst nach Ablauf einer bestimmten Zeitspanne.

Verwandte Themen