Question

Ci-dessous, j'ai un exemple très simple de ce que j'essaie de faire.Je veux pouvoir utiliser HTMLDecorator avec n'importe quelle autre classe.Ignorez le fait que ça s'appelle décorateur, c'est juste un nom.

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

Sortir:

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

Est-ce que ce que j'essaie de faire est possible ?Si oui, qu'est-ce que je fais de mal ?

Était-ce utile?

La solution

Très proche, mais ensuite je perds tout de ClassX.Ci-dessous, vous trouverez quelque chose qu'un collègue m'a donné et qui fait l'affaire, mais c'est hideux.Il doit y avoir une meilleure façon.

On dirait que vous essayez de configurer une sorte de schéma d'objet proxy.C'est faisable, et il existe de meilleures solutions que celles de votre collègue, mais demandez-vous d'abord s'il ne serait pas plus facile d'ajouter simplement des méthodes supplémentaires.Cela ne fonctionnera pas pour les classes intégrées comme bool, mais ce sera le cas pour vos classes définies par l'utilisateur :

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

Et voici la version proxy :

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)

Autres conseils

Les deux solutions de John fonctionneraient.Une autre option qui permet à HTMLDecorator de rester très simple et propre consiste à le patcher en tant que classe de base.Cela fonctionne également uniquement pour les classes définies par l'utilisateur, pas pour les types intégrés :

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

Soyez averti, cependant : un patch de singe comme celui-ci a un prix élevé en termes de lisibilité et de maintenabilité de votre code.Lorsque vous revenez à ce code un an plus tard, il peut devenir très difficile de comprendre comment votre ClassX a obtenu cette méthode html(), surtout si ClassX est défini dans une autre bibliothèque.

Est-ce que ce que j'essaie de faire est possible ?Si oui, qu'est-ce que je fais de mal ?

C'est certainement possible.Ce qui ne va pas c'est que HTMLDecorator.__init__() n'accepte pas les paramètres.

Voici un exemple simple :

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

@Jean (37448) :

Désolé, je vous ai peut-être induit en erreur avec le nom (mauvais choix).Je ne recherche pas vraiment une fonction de décorateur, ni quoi que ce soit à voir avec les décorateurs.Ce que je recherche, c'est que la définition html(self) utilise ClassX ou ClassY. __repr__.Je veux que cela fonctionne sans modifier ClassX ou ClassY.

Ah, dans ce cas, peut-être qu'un code comme celui-ci sera utile ?Cela n'a pas vraiment quelque chose à voir avec les décorateurs, mais montre comment transmettre des arguments à la fonction d'initialisation d'une classe et récupérer ces arguments pour plus tard.

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

@Jean (37479) :

Très proche, mais ensuite je perds tout de ClassX.Ci-dessous, vous trouverez quelque chose qu'un collègue m'a donné et qui fait l'affaire, mais c'est hideux.Il doit y avoir une meilleure façon.

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

Sortir:

<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>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top