如何简单地从现有实例继承方法?
下面我有一个非常简单的例子,想给大家展示我想做的事情。我希望能够把HTMLDecorator和其他任何类一起使用。别在意它叫做decorator,这只是个名字。
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
我想做的事情可能吗?如果可以的话,我哪里做错了呢?
6 个回答
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
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是在其他库中定义的时候。
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)