2016-04-18 5 views
2

プロパティを格納する必要があるクラスを作成する場合は、@propertyデコレータを使用するのが適切な場合は、いつ__init__でそれらを定義すればよいですか?私は考えることができる__init__と@propertyでクラス属性を宣言する

理由は:

は、私はこれが正常に動作します

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

のようなクラスを持っていると言います。

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

しかし、私は遅く方法(インターネット上でデータをフェッチし、発言権を)持っているより複雑なクラスを、持っていると言う。この場合、それは私のようにクラスを記述するべきではないと私にはかなり明確です。私は__init__この割り当て属性を実装できる

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

またはI @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 

を、後者は約50,000倍高速インスタンス化することです。しかし、私はwikipedia_article_content複数回フェッチされた場合、前者の方が高速であることを主張することができます:それは三番目要求の数を持っているので、その場合には

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

、前者は〜3倍高速です。

私の質問

は、これら二つの方法私が考えたもので割り当てるプロパティの唯一の違いですか? @propertyは、時間を節約する以外に何かできますか(場合によっては)?割り当てに時間がかかるプロパティの場合、それらを割り当てる「正しい方法」がありますか?

答えて

1

はい、これらの引数にはpropertyを使用することをおすすめします。あなたが怠惰な、またはキャッシュされたものにしたい場合は、プロパティをサブクラス化することができます。

これは単なるレイジープロパティの実装です。プロパティ内でいくつかの操作を行い、結果を返します。この結果は別の名前でクラスに保存され、プロパティの後続の呼び出しで保存された結果が返されます。

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 

これは、あなたが一度値を計算して、常にそれを返すことができます:

class Test: 
    def __init__(self): 
     pass 

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

これは、それがどのように動作するかである(明らかにあなたは、あなたのケースのためにそれを適応させる必要があります):

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

プロパティを使用すると、より複雑な動作が可能になります。記事コンテンツが変更されたときにのみ、一定の期間が経過した後にのみ、記事コンテンツを取得するなど。

関連する問題