如何简单地从现有实例继承方法?
-
09-06-2019 - |
题
下面我有一个非常简单的例子来说明我正在尝试做的事情。我希望能够将 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
我想做的事情可能吗?如果是这样,我做错了什么?
解决方案
非常接近,但随后我失去了 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)
其他提示
约翰的两个解决方案都有效。允许 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 是在其他库中定义的。
我想做的事情可能吗?如果是这样,我做错了什么?
这当然是可能的。问题是 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
@约翰(37448):
抱歉,我可能用这个名字误导了你(错误的选择)。我并不是真的在寻找装饰器函数,或者根本不是在寻找与装饰器有关的任何东西。我所追求的是 html(self) def 使用 ClassX 或 ClassY __repr__
. 。我希望它可以在不修改 ClassX 或 ClassY 的情况下工作。
啊,那么这样的代码也许有用吗?它实际上与装饰器没有任何关系,但演示了如何将参数传递给类的初始化函数以及如何检索这些参数以供以后使用。
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()
@约翰(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>