Frage

Unten habe ich ein sehr einfaches Beispiel dafür, was ich versuche.Ich möchte HTMLDecorator mit jeder anderen Klasse verwenden können.Ignorieren Sie die Tatsache, dass es Decorator heißt, es ist nur ein Name.

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

Ausgabe:

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

Ist das, was ich versuche, möglich?Wenn ja, was mache ich falsch?

War es hilfreich?

Lösung

Sehr knapp, aber dann verliere ich alles von ClassX.Unten ist etwas, das mir ein Kollege gegeben hat und das zwar funktioniert, aber abscheulich ist.Es muss einen besseren Weg geben.

Sieht so aus, als würden Sie versuchen, eine Art Proxy-Objektschema einzurichten.Das ist machbar und es gibt bessere Lösungen als die Ihres Kollegen, aber überlegen Sie zunächst, ob es einfacher wäre, einfach ein paar zusätzliche Methoden einzubinden.Dies funktioniert nicht für integrierte Klassen wie bool, aber für Ihre benutzerdefinierten Klassen gilt Folgendes:

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

Und hier ist die Proxy-Version:

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)

Andere Tipps

Beide Lösungen von John würden funktionieren.Eine weitere Option, die es HTMLDecorator ermöglicht, sehr einfach und sauber zu bleiben, besteht darin, es als Basisklasse einzubinden.Dies funktioniert auch nur für benutzerdefinierte Klassen, nicht für integrierte Typen:

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

Seien Sie jedoch gewarnt – ein derartiges Monkey-Patching geht mit einem hohen Preis für die Lesbarkeit und Wartbarkeit Ihres Codes einher.Wenn Sie ein Jahr später zu diesem Code zurückkehren, kann es sehr schwierig werden herauszufinden, wie Ihr ClassX zu dieser html()-Methode gelangt ist, insbesondere wenn ClassX in einer anderen Bibliothek definiert ist.

Ist das, was ich versuche, möglich?Wenn ja, was mache ich falsch?

Es ist sicherlich möglich.Was falsch ist, ist das HTMLDecorator.__init__() akzeptiert keine Parameter.

Hier ist ein einfaches Beispiel:

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

@John (37448):

Entschuldigung, ich habe Sie möglicherweise mit dem Namen in die Irre geführt (schlechte Wahl).Ich bin nicht wirklich auf der Suche nach einer Funktion als Dekorateur oder irgendetwas, das überhaupt etwas mit Dekorateuren zu tun hat.Ich möchte, dass die HTML-Definition (selbst) ClassX oder ClassY verwendet __repr__.Ich möchte, dass dies funktioniert, ohne ClassX oder ClassY zu ändern.

Ah, in diesem Fall ist Code wie dieser vielleicht nützlich?Es hat nicht wirklich etwas mit Dekoratoren zu tun, sondern zeigt, wie man Argumente an die Initialisierungsfunktion einer Klasse übergibt und diese Argumente für später abruft.

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

@John (37479):

Sehr knapp, aber dann verliere ich alles von ClassX.Unten ist etwas, das mir ein Kollege gegeben hat und das zwar funktioniert, aber abscheulich ist.Es muss einen besseren Weg geben.

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

Ausgabe:

<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>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top