2012-02-03 10 views
5

Böyle bir dekoratör aracılığıyla bir sınıfa birçok kukla-özelliklerini eklemek istiyorum:Özellikleri bir argüman olarak alan bir dekoratör kullanarak bir sınıfa nasıl ekleyebilirim?

def addAttrs(attr_names): 
    def deco(cls): 
    for attr_name in attr_names: 
     def getAttr(self): 
     return getattr(self, "_" + attr_name) 
     def setAttr(self, value): 
     setattr(self, "_" + attr_name, value) 
     prop = property(getAttr, setAttr) 
     setattr(cls, attr_name, prop) 
     setattr(cls, "_" + attr_name, None) # Default value for that attribute 
    return cls 
    return deco 

@addAttrs(['x', 'y']) 
class MyClass(object): 
    pass 

Maalesef decoarator yerine içeriğinin attr_name referansını tutmak gibi görünüyor. Bu nedenle, MyClass.x ve MyClass.y erişim hem MyClass._y:

a = MyClass() 
a.x = 5 
print a._x, a._y 
>>> None, 5 
a.y = 8 
print a._x, a._y 
>>> None, 8 

Ne beklenen davranışı elde etmek değiştirmek gerekiyor?

cevap

7

Neredeyse çalışıyormuşsunuz. Sadece bir nit var. iç fonksiyonlarını oluştururken, alıcı ve ayarlayıcı işlevleri içine attr_name mevcut değerini bağlamak:

def addAttrs(attr_names): 
    def deco(cls): 
    for attr_name in attr_names: 
     def getAttr(self, attr_name=attr_name): 
     return getattr(self, "_" + attr_name) 
     def setAttr(self, value, attr_name=attr_name): 
     setattr(self, "_" + attr_name, value) 
     prop = property(getAttr, setAttr) 
     setattr(cls, attr_name, prop) 
     setattr(cls, "_" + attr_name, None) # Default value for that attribute 
    return cls 
    return deco 

@addAttrs(['x', 'y']) 
class MyClass(object): 
    pass 

Bu beklenen bir sonuç üretir: Bu yardımcı olur

>>> a = MyClass() 
>>> a.x = 5 
>>> print a._x, a._y 
5 None 
>>> a.y = 8 
>>> print a._x, a._y 
5 8 

Umut. Happy decorating :-)

2

Python, yalnızca işlev düzeyi düzeyinde blok düzeyinde kapsamlamayı desteklemez. Bu nedenle, döngü içinde atanan tüm değişkenler, döngü dışında kullanılabilir son değer olarak kullanılabilir. Aradığınız sonucu elde etmek için, döngü içinde bir kapatma kullanmak gerekir:

def addAttrs(attr_names): 
    def deco(cls): 
    for attr_name in attr_names: 
     def closure(attr): 
     def getAttr(self): 
      return getattr(self, "_" + attr) 
     def setAttr(self, value): 
      setattr(self, "_" + attr, value) 
     prop = property(getAttr, setAttr) 
     setattr(cls, attr, prop) 
     setattr(cls, "_" + attr, None) 
     closure(attr_name) 
    return cls 
    return deco 

kapatma closure, getAttr ve setAttr doğru alanına dahil edilecektir içinde atanan nitelikler kullanma. EDIT: düzeltilmiş girinti

İlgili konular