Vra

Hier het ek 'n baie eenvoudige voorbeeld van wat ek probeer om te doen. Ek wil in staat wees om HTMLDecorator gebruik met enige ander klas. Ignoreer die feit dit is bekend as versierder, dit is net 'n naam.

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

Uitgawe:

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

Is dit wat ek probeer om moontlike doen? So ja, wat doen ek verkeerd?

Was dit nuttig?

Oplossing

  

Baie naby, maar dan alles verloor ek uit ClassX. Hieronder is iets wat 'n kollega het my vertel dat doen doen die truuk, maar dit is afskuwelik. Daar moet 'n beter manier wees.

Dit lyk asof jy probeer om op te rig 'n soort van 'n gevolmagtigde voorwerp skema. Dit is uitvoerbaar, en daar is 'n beter oplossing as jou kollega se, maar eers oorweeg of dit makliker sou wees om net te lap in 'n paar ekstra metodes. Dit sal nie werk vir ingeboude klasse soos bool, maar dit sal vir jou gebruiker-gedefinieerde klasse:

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

En hier is die volmag weergawe:

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)

Ander wenke

Beide van John se oplossings sal werk. Nog 'n opsie wat jou toelaat HTMLDecorator om baie eenvoudig en skoon bly is om aap-kol dit in as 'n basis klas. Dit werk ook net vir die gebruiker-gedefinieerde klasse, nie ingeboude tipes:

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

Wees gewaarsku, maar - aap-lap soos hierdie kom met 'n hoë prys in leesbaarheid en instandhouding van jou kode. Wanneer jy 'n jaar later terug te gaan na hierdie kode, kan dit baie moeilik geword om uit te vind hoe jou ClassX het dat html metode (), veral as ClassX word gedefinieer in 'n ander biblioteek.

  

Is dit wat ek probeer om moontlike doen? So ja, wat doen ek verkeerd?

Dit is seker moontlik. Wat is fout is dat HTMLDecorator.__init__() nie parameters aanvaar nie.

Hier is 'n eenvoudige voorbeeld:

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

Jammer, ek kan julle mislei met die naam (slegte keuse). Ek is nie regtig op soek na 'n versierder funksie, of niks te doen met ontwerpers at all. Wat ek is nadat is vir die html (self) def om ClassX of classy se __repr__ gebruik. Ek wil hierdie om te werk sonder wysiging ClassX of classy.

Ag, in daardie geval, miskien kode soos hierdie sal nuttig wees? Dit maak nie regtig iets te doen met ontwerpers, maar toon hoe om argumente te slaag om inisialisering funksie 'n klas en aan dié argumente te haal vir later.

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

Baie naby, maar dan alles verloor ek uit ClassX. Hieronder is iets wat 'n kollega het my vertel dat doen doen die truuk, maar dit is afskuwelik. Daar moet 'n beter manier wees.

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

Uitgawe:

<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>
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top