Neville Dempsey a écrit :
What do I need to add to HTMLDecorator?

A simpler example:

import cgi

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

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

inst_x=ClassX()

Why do you need to prefix your variables with 'inst_' ?

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

<ot>
uppercase tags are so 1990...
</ot>

More seriously, your code would be more readable (and more maintainable) using string formatting, ie:

   def html(self): # an "enhanced" version of __repr__
       return cgi.escape("<h1>%r</h1>" % self)


print HTMLDecorator(inst_x).html()

(snip unexecuted code)

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

Can I simply decorate an existing instance?

For which definitions of "simply" and "decorate", and for instances of what ?

Some classes will let you add arbitrary attributes to either themselves of their instances. Some (hint: mostly builtin types) wont, because they've been implemented otherwise, usually for performances reasons.

If all you need is a simple enhanced "html" __repr__, just use a generic function - being OO doesn't mean you have to use classes everywhere (hint : OO stands for "object oriented", not "class oriented"). All you need here is:

def html(obj, tag="h1"):
    return "<%s>%s</%s>" % (tag, cgi.escape(repr(obj)), tag)


If you have more responsabilities to add, and want something generic, then you'll have to use composition/delegation instead of inheritance, ie:

class HTMLDecorator(object):
    def __init__(self, obj):
        # use name mangling to avoid possible name clash
        self.__obj = obj
    def html(self):
        # reuse the above generic html() func
        return html(self.__obj)
    def __getattr__(self, name):
        # trivial, always delegate - __getattr__ is
        # only called when evrything else failed
        return getattr(self.__obj, name)
    def __setattr__(self, name, value):
        # tricky : __setattr__ is *always* called
        if name == "_HTMLDecorator__obj" or name in type(self).__dict__:
            super(HTMLDecorator, self).__setattr__(name, value)
        else:
            setattr(self.__obj, name, value)

But be warned that this might be tricky (I wouldn't bet a truly generic implementation of the class decorator pattern is something doable), and that you'll have to pay the price (wrt/ perfs) for overriding __setattr__. As a general rule, it's better to avoid overridding __getattribute__ and __setattr__ whenever possible.

HTH
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to