2014-11-28 32 views
5

Bir sistemi temsil eden bir durum nesnesine sahibim. Durum nesnesi içindeki özellikler [büyük] metin dosyalarından doldurulur. her özellik bir devlet örneği oluşturulur her zaman erişilir gibi, duyu lazily bunları yüklemek için yapar .: tekrarlayan Demirbaş kodu bir sürü var buradaAşırı yüklenmiş dekoratörler kullanan tembel yükleme değişkenleri

class State: 
    def import_positions(self): 
     self._positions = {} 
     # Code which populates self._positions 

    @property 
    def positions(self): 
     try: 
      return self._positions 
     except AttributeError: 
      self.import_positions() 
      return self._positions 

    def import_forces(self): 
     self._forces = {} 
     # Code which populates self._forces 

    @property 
    def forces(self): 
     try: 
      return self._forces 
     except AttributeError: 
      self.import_forces() 
      return self._forces 

. Üstelik, bir import_abc bazen bir kaç değişkene nüfuz edebilir (yani, zaten açıksa küçük bir veri dosyasından birkaç değişken içe aktarın). Ben tam olarak ne yöntemini izlemek için bir yol bulmak gibi olamaz, ancak

class State: 
    def import_positions(self): 
     self._positions = {} 
     # Code which populates self._positions 

    @lazyproperty(import_positions) 
    def positions(self): 
     pass 

    def import_forces(self): 
     self._forces = {} 
     # Code which populates self._forces and self._strain 

    @lazyproperty(import_forces) 
    def forces(self): 
     pass 

    @lazyproperty(import_forces) 
    def strain(self): 
     pass 

:

O anlamda o değişken, viz "sağlamak" üzere bir fonksiyon kabul öyle ki @property aşırı kolaylaştırır Özellik dekoratöründe çağrılıyor. Bu nedenle, @property'ın kendi @lazyproperty'mize nasıl yükleneceğini bilmiyorum.

Herhangi bir düşünce?

cevap

3

Belki de böyle bir şey istiyorsun. Bu @property ile birlikte bir tür basit bir not alma işlevi. yazdırır

def lazyproperty(func): 
    values = {} 
    def wrapper(self): 
     if not self in values: 
      values[self] = func(self) 
     return values[self] 
    wrapper.__name__ = func.__name__ 
    return property(wrapper) 

class State: 
    @lazyproperty 
    def positions(self): 
     print 'loading positions' 
     return {1, 2, 3} 

s = State() 
print s.positions 
print s.positions 

:

loading positions 
set([1, 2, 3]) 
set([1, 2, 3]) 

Uyarı: bu uzun süren programlar için uygun değildir bu yüzden değerleri sözlükte girişleri çöp toplandı edilmeyecektir.

Ancak
try: 
    return func.value 
except AttributeError: 
    func.value = func(self) 
    return func.value 
+0

Birden fazla State of State örneği oluşturursanız, bu çalışmayacaktır. yöntemin işlev nesnesi, ancak yöntem yalnızca sınıf düzeyinde bir kez bulunur, bu nedenle ne yaparsanız yapın tüm örnekleri etkileyecektir. Eğer ikinci bir 'Devlet' yaparsanız ve pozisyonlarını değiştirirseniz, değişikliklerin her iki durumda da göründüğünü görürsünüz. – BrenBarn

+0

Haklısınız, düzeltildiniz. – lunixbochs

1

, ben tam olarak ne yöntem izlemek için bir yol bulmak gibi olamaz: Yüklenen değer tüm sınıflara değişmez ise, daha iyi hız ve hafıza kullanımı için fonksiyon nesnenin kendisinde depolanabilir Özellik dekoratöründe çağrılıyor.

propertydescriptor protocol (https://docs.python.org/2/howto/descriptor.html) uygular, (eğer ortogonal olduğu değil dekoratör sözdizimi ile kullanmak olsun) aslında bir türüdür.

class property(object): 
    def __init__(self, fget=None, fset=None): 
     self.fget = fget 
     self.fset = fset 

    def setter(self, func): 
     self.fset = func 
     return func 

    def __get__(self, obj, type=None): 
     return self.fget(obj) 

    def __set__(self, obj, value): 
     if self.fset: 
      self.fset(obj, value) 
     else: 
      raise AttributeError("Attribute is read-only") 

Şimdi property aşırı mutlaka basit çözüm değildir: Çok fazla basitleştirilmiş bir saf-piton uygulaması şu şekilde görünecektir (ı deleter, doc ve epeyce başka şeyler ... atlanır). Aslında (bu konuda daha fazla için cf http://ericplumb.com/blog/understanding-djangos-cached_property-decorator.html) Django'nın "cached_property" ve pydanny yönettiği "önbelleğe-mülk" paket (https://pypi.python.org/pypi/cached-property/0.1.5)

2

seni daha da fazla klişe kaldırabilir düşünüyorum dahil oldukça birkaç varolan uygulamaları orada aslında var yükleyici metodunu süsleyen bir özel tanımlayıcı sınıfının yazılması. Buradaki amaç, tanımlayıcının kendisinin tembel yükleme mantığını kodlamasını sağlamaktır, yani gerçek bir yöntemle tanımladığınız tek şey yükleyicinin kendisi olmasıdır (ki bu, görünüşe göre, gerçekten farklı değerler için değişmek zorunda olan tek şeydir).İşte bir örnek: Sonra

class LazyDesc(object): 
    def __init__(self, func): 
     self.loader = func 
     self.secretAttr = '_' + func.__name__ 

    def __get__(self, obj, cls): 
     try: 
      return getattr(obj, self.secretAttr) 
     except AttributeError: 
      print("Lazily loading", self.secretAttr) 
      self.loader(obj) 
      return getattr(obj, self.secretAttr) 

class State(object): 
    @LazyDesc 
    def positions(self): 
     self._positions = {'some': 'positions'} 

    @LazyDesc 
    def forces(self): 
     self._forces = {'some': 'forces'} 

: "geç yükleme" mesajı sadece her bir özellik için ilk erişime üzerinde yazılı olduğu

>>> x = State() 
>>> x.forces 
Lazily loading _forces 
{'some': 'forces'} 
>>> x.forces 
{'some': 'forces'} 
>>> x.positions 
Lazily loading _positions 
{'some': 'positions'} 
>>> x.positions 
{'some': 'positions'} 

dikkat edin. Bu sürüm aynı zamanda, yani positions verileri _positions saklanır yöntemi adı (bir alt çizgi ekleyerek bu gerçek verileri tutmak için "gizli" özelliğini otomatik oluşturur. Eğer x.positions = blah yapamaz bu nedenle bu örnekte, hiçbir ayarlayıcı, orada (hala x.positions['key'] = val ile pozisyonları mutasyona rağmen), ancak yaklaşım de ayar izin için uzun olabilir.

bu yaklaşımının iyi tembel mantık şeffaf bunun anlamı, açıklayıcısında __get__ kodlanmış olmasıdır Benzer şekilde soyutlamak isteyebileceğiniz başka türdeki boilerplate'lere de kolayca genelleştirilebilir

İlgili konular