2008-09-01 47 views
0

下面我有一個很簡單的例子,我正在嘗試做什麼。我希望能夠與任何其他類一起使用HTMLDecorator。忽略它被稱爲裝飾者的事實,它只是一個名字。如何簡單地從現有實例繼承方法?

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

輸出:

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

正是我試圖做可能嗎?如果是這樣,我做錯了什麼?

回答

2

非常接近,但後來我從ClassX血本無歸。下面是一個同事給了我的東西,但它確實可行,但它很可怕。一定有更好的方法。

看起來你正試圖設置某種代理對象方案。這是可行的,並且有比您的同事更好的解決方案,但首先考慮是否更容易修補一些額外的方法。這不會像bool的內置類工作,但它會爲您的用戶定義的類:

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

這裏是代理的版本:

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

是我想做的事情嗎?如果是這樣,我做錯了什麼?

這當然有可能。有什麼不對?HTMLDecorator.__init__()不接受參數。

這裏有一個簡單的例子:

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

@約翰(37448):

對不起,我可能會誤導你的名字(壞的選擇)。我並不是真的在尋找一個裝飾器函數,或者根本就不用裝飾器。我所追求的是爲html(self)def使用ClassX或ClassY的__repr__。我希望在不修改ClassX或ClassY的情況下工作。

0

啊,在這種情況下,也許這樣的代碼會有用嗎?它實際上與裝飾器沒有任何關係,但演示瞭如何將參數傳遞給類的初始化函數並稍後檢索這些參數。

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

@約翰(37479):

非常接近,但後來我失去了一切從ClassX。下面是一個同事給了我的東西,但它確實可行,但它很可怕。一定有更好的方法。

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

輸出:

<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

兩個約翰的解決方案,將工作。另一個允許HTMLDecorator保持非常簡單和乾淨的選項是將其作爲基類進行猴子修補。這也僅適用於用戶定義的類,而不是內建類型:

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

被警告,雖然 - 猴子打補丁這樣伴隨着很高的價格可讀性和可維護性的代碼。當你一年後回到這個代碼時,很難弄清楚你的ClassX如何得到這個html()方法,特別是如果ClassX是在其他庫中定義的。