2008-09-01 15 views
0

Aşağıda Yapmaya çalıştığım şeyin çok basit bir örneğim var. HTMLDecorator'ı başka bir sınıfla birlikte kullanabilmek istiyorum. Dekoratör denilen şeyi görmezden gel, sadece bir isim.Varolan bir örnekten yöntemleri nasıl basitçe alabilirim?

import cgi 

class ClassX(object): 
    pass # ... with own __repr__ 

class ClassY(object): 
    pass # ... with own __repr__ 

inst_x=ClassX() 

inst_y=ClassY() 

inst_z=[ i*i for i in range(25) ] 

inst_b=True 

class HTMLDecorator(object): 
    def html(self): # an "enhanced" version of __repr__ 
     return cgi.escape(self.__repr__()).join(("<H1>","</H1>")) 

print HTMLDecorator(inst_x).html() 
print HTMLDecorator(inst_y).html() 
wrapped_z = HTMLDecorator(inst_z) 
inst_z[0] += 70 
wrapped_z[0] += 71 
print wrapped_z.html() 
print HTMLDecorator(inst_b).html() 

Çıktı:

Traceback (most recent call last): 
    File "html.py", line 21, in 
    print HTMLDecorator(inst_x).html() 
TypeError: default __new__ takes no parameters

Mümkün yapmaya çalıştığım şey var mı? Eğer öyleyse, ne yapıyorum yanlış?

cevap

2

çok yakın, ama sonra ClassX her şeyi kaybeder. Aşağıda, bir kolej bana hile yapan bir şey verdi, ama çok çirkin. Daha iyi bir yolu olmalı.

Bir çeşit proxy nesne şeması oluşturmaya çalışıyorsunuz gibi görünüyor. Bu mümkün ve meslektaşlarınızdan daha iyi çözümler var, ancak önce bazı ekstra yöntemlerle daha kolay yamalamanın kolay olup olmayacağını düşünün. Bu bool gibi yerleşik sınıflar için çalışmaz, ama o kitabın kullanıcı tanımlı sınıflar için:

def HTMLDecorator (obj): 
    def html(): 
     sep = cgi.escape (repr (obj)) 
     return sep.join (("<H1>", "</H1>")) 
    obj.html = html 
    return obj 

Ve burada vekil sürümü:

class HTMLDecorator(object): 
    def __init__ (self, wrapped): 
     self.__wrapped = wrapped 

    def html (self): 
     sep = cgi.escape (repr (self.__wrapped)) 
     return sep.join (("<H1>", "</H1>")) 

    def __getattr__ (self, name): 
     return getattr (self.__wrapped, name) 

    def __setattr__ (self, name, value): 
     if not name.startswith ('_HTMLDecorator__'): 
      setattr (self.__wrapped, name, value) 
      return 
     super (HTMLDecorator, self).__setattr__ (name, value) 

    def __delattr__ (self, name): 
     delattr (self.__wraped, name) 
0

Yapmaya çalıştığım şey bu mu? Eğer öyleyse, ne yapıyorum yanlış?

Kesinlikle mümkündür. Sorun nedir, HTMLDecorator.__init__() parametresi kabul etmiyor.

def decorator (func): 
    def new_func(): 
     return "new_func %s" % func() 
    return new_func 

@decorator 
def a(): 
    return "a" 

def b(): 
    return "b" 

print a() # new_func a 
print decorator (b)() # new_func b 
0

@John (37448):

İşte basit bir örnek

Üzgünüm, adı (kötü bir seçim) ile yanıltılmış olabilir. Bir dekoratör işlevi veya dekoratörlerle ilgisi olmayan bir şey arıyorum. Ben sonra html (self) def ClassX veya ClassY __repr__ kullanmak için. Bunun ClassX veya ClassY'yi değiştirmeden çalışmasını istiyorum.

0

Ah, bu durumda, belki de böyle bir kod yararlı olabilir mi? Dekoratörlerle gerçekten bir ilgisi yoktur, ancak argümanların bir sınıfın başlatma işlevine nasıl geçeceğini ve bu argümanların daha sonra nasıl alınacağını gösterir.

import cgi 

class ClassX(object): 
    def __repr__ (self): 
     return "<class X>" 

class HTMLDecorator(object): 
    def __init__ (self, wrapped): 
     self.__wrapped = wrapped 

    def html (self): 
     sep = cgi.escape (repr (self.__wrapped)) 
     return sep.join (("<H1>", "</H1>")) 

inst_x=ClassX() 
inst_b=True 

print HTMLDecorator(inst_x).html() 
print HTMLDecorator(inst_b).html() 
0

@John (37479):

çok yakın, ama sonra ClassX her şeyi kaybeder. Aşağıda, bir kolej bana hile yapan bir şey verdi, ama çok çirkin. Daha iyi bir yolu olmalı.

import cgi 
from math import sqrt 

class ClassX(object): 
    def __repr__(self): 
    return "Best Guess" 

class ClassY(object): 
    pass # ... with own __repr__ 

inst_x=ClassX() 

inst_y=ClassY() 

inst_z=[ i*i for i in range(25) ] 

inst_b=True 

avoid="__class__ __init__ __dict__ __weakref__" 

class HTMLDecorator(object): 
    def __init__(self,master): 
     self.master = master 
     for attr in dir(self.master): 
      if (not attr.startswith("__") or 
       attr not in avoid.split() and "attr" not in attr): 
       self.__setattr__(attr, self.master.__getattribute__(attr)) 

    def html(self): # an "enhanced" version of __repr__ 
     return cgi.escape(self.__repr__()).join(("<H1>","</H1>")) 

    def length(self): 
     return sqrt(sum(self.__iter__())) 

print HTMLDecorator(inst_x).html() 
print HTMLDecorator(inst_y).html() 
wrapped_z = HTMLDecorator(inst_z) 
print wrapped_z.length() 
inst_z[0] += 70 
#wrapped_z[0] += 71 
wrapped_z.__setitem__(0,wrapped_z.__getitem__(0)+ 71) 
print wrapped_z.html() 
print HTMLDecorator(inst_b).html() 

Çıktı:

<H1>Best Guess</H1> 
<H1><__main__.ClassY object at 0x891df0c></H1> 
70.0 
<H1>[141, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576]</H1> 
<H1>True</H1>
2

John'un çözümlerinin Hem çalışacak . HTMLDecorator'ın çok basit ve temiz kalmasını sağlayan bir başka seçenek de, bir temel sınıf olarak onu maymun-yama haline getirmektir.maymun yama bu gibi bir kod yüksek okunabilirliği fiyatın ve bakımı ile gelir -

import cgi 

class ClassX(object): 
    pass # ... with own __repr__ 

class ClassY(object): 
    pass # ... with own __repr__ 

inst_x=ClassX() 
inst_y=ClassY() 

class HTMLDecorator: 
    def html(self): # an "enhanced" version of __repr__ 
     return cgi.escape(self.__repr__()).join(("<H1>","</H1>")) 

ClassX.__bases__ += (HTMLDecorator,) 
ClassY.__bases__ += (HTMLDecorator,) 

print inst_x.html() 
print inst_y.html() 

Uyardı, gerçi: Bu aynı zamanda kullanıcı tanımlı sınıflar değil, yerleşik türleri için çalışır. Bir sene sonra bu sınıfa geri döndüğünüzde, ClassX'in html() yöntemini, özellikle de başka bir kitaplıkta ClassX tanımlanmışsa nasıl bulduğunu anlamak çok zor olabilir.

İlgili konular