1

下面我有一个非常简单的例子来说明我正在尝试做的事情。我希望能够将 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()

输出:

回溯(最近一次通话最后):
  文件“html.py”,第 21 行,在
    打印 HTMLDecorator(inst_x).html()
TypeError:默认 __new__ 不带参数

我正在尝试做的事情可能吗?如果是这样,我做错了什么?

4

6 回答 6

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)
于 2008-09-01T07:33:45.487 回答
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 是在其他库中定义的。

于 2008-09-01T08:30:41.247 回答
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
于 2008-09-01T05:26:06.170 回答
0

@约翰(37448):

对不起,我可能用这个名字误导了你(错误的选择)。我并不是真的在寻找装饰器功能,或者根本不是与装饰器有关的任何事情。我所追求的是 html(self) def 使用 ClassX 或 ClassY's __repr__。我希望它能够在不修改 ClassX 或 ClassY 的情况下工作。

于 2008-09-01T06:10:04.317 回答
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()
于 2008-09-01T06:25:43.297 回答
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>最佳猜测</H1>
<H1><__main__.ClassY 对象位于 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>正确</H1>
于 2008-09-01T06:55:13.317 回答