Python

2010-10-05 11 views
7

ile sınıf tanımına uygulanan dekoratörler Bir işleve uygulanan dekoratörlerle karşılaştırıldığında, bir sınıfa uygulanan dekoratörlerin anlaşılması kolay değildir.Python

@foo 
class Bar(object): 
    def __init__(self, x): 
     self.x = x 
    def spam(self): 
     statements 

Dekoratörlerin bir sınıf için kullanım durumu nedir? Bu nasıl kullanılır?

cevap

23

Özel meta sınıflar için klasik iyi kullanımların büyük çoğunluğunu çok daha basit bir şekilde değiştirir.

Bunu şu şekilde düşünün: sınıf nesnesinde doğrudan olan hiçbir şey sınıf nesnesine başvurabilir; çünkü sınıf nesnesi, vücudun tamamlanmasından sonra iyi olana kadar var olmaz (sınıf nesnesini oluşturmak için metaclassın görevidir) - Özel bir metaclass olmadan tüm sınıflar için genellikle type 's.

Fakat, sınıf dekoratör kod sınıf nesnesi gayet iyi (yani sınıf nesnesine başvurabilir böylece (bir argüman! Olarak sınıf nesnesi ile gerçekten) oluşturuldu ve sonra çalışır ve genellikle bunu yapması gereken). normalde yapmak bile daha fazla işlevsellik eklemek istiyorum, Color.green yerine 0 daha & c, 1 vb (Tabi

def enum(cls): 
    names = getattr(cls, 'names', None) 
    if names is None: 
    raise TypeError('%r must have a class field `names` to be an `enum`!', 
        cls.__name__) 
    for i, n in enumerate(names): 
    setattr(cls, n, i) 
    return cls 

@enum 
class Color(object): 
    names = 'red green blue'.split() 

ve şimdi Color.red başvurabilirsiniz:

Örneğin, düşünün "bir enum", ama burada sadece özel bir metaclass gerek yerine bir sınıf dekoratör, böyle bir işlevselliği eklemek için basit bir yol gösteriyorum! -)

+0

@Manoj, bunu beğendiğinize sevindim, tx bana haber verdiğiniz için! –

6

Eğer düşünebilirim bir kullanım durumu bir sınıfın tüm yöntemlerini sarmak tek fonksiyonlu dekoratör ile.

def logit(f): 
    def res(*args, **kwargs): 
     print "Calling %s" % f.__name__ 
     return f(*args, **kwargs) 
    return res 

Ve aşağıdaki sınıf:

>>> class Pointless: 
    def foo(self): print 'foo' 
    def bar(self): print 'bar' 
    def baz(self): print 'baz' 

>>> p = Pointless() 
>>> p.foo(); p.bar(); p.baz() 
foo 
bar 
baz 

Tüm yöntemler dekore edebilirsiniz:

>>> class Pointless: 
    @logit 
    def foo(self): print 'foo' 
    @logit 
    def bar(self): print 'bar' 
    @logit 
    def baz(self): print 'baz' 

>>> p = Pointless() 
>>> p.foo(); p.bar(); p.baz() 
Calling foo 
foo 
Calling bar 
bar 
Calling baz 
baz 

Ama bu AKSIYOR aşağıdaki dekoratör olduğunu düşünelim!

>>> def logall(cls): 
for a in dir(cls): 
    if callable(getattr(cls, a)): 
     setattr(cls, a, logit(getattr(cls, a))) 
return cls 

>>> @logall 
class Pointless: 
    def foo(self): print 'foo' 
    def bar(self): print 'bar' 
    def baz(self): print 'baz' 

>>> p = Pointless() 
>>> p.foo(); p.bar(); p.baz() 
Calling foo 
foo 
Calling bar 
bar 
Calling baz 
baz 

GÜNCELLEME: logall ilişkin daha genel bir versiyonu:

>>> def wrapall(method): 
    def dec(cls): 
     for a in dir(cls): 
      if callable(getattr(cls, a)): 
       setattr(cls, a, method(getattr(cls, a))) 
     return cls 
    return dec 

>>> @wrapall(logit) 
class Pointless: 
     def foo(self): print 'foo' 
     def bar(self): print 'bar' 
     def baz(self): print 'baz' 

>>> p = Pointless() 
>>> p.foo(); p.bar(); p.baz() 
Calling foo 
foo 
Calling bar 
bar 
Calling baz 
baz 
>>> 

Tam açıklanmasını: Bunun yerine bunu yapabilirsiniz bunu yapmak hiç olmadı ve ben sadece bu örnek uydurdum.