Hvordan kan jeg rett og slett arve metoder fra en eksisterende forekomst?

stemmer
0

Nedenfor har jeg et veldig enkelt eksempel på hva jeg prøver å gjøre. Jeg ønsker å kunne bruke HTMLDecorator med en annen klasse. Ignorere det faktum det heter dekoratør, det er bare et navn.

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

Produksjon:

Tilbakesporings (siste samtale sist):
  Fil html.py, linje 21, i 
    print HTMLDecorator (inst_x) HTML ()
Feiltype: Standard __new__ tar ingen parametere

Er det jeg prøver å gjøre mulig? Hvis ja, hva gjør jeg galt?

Publisert på 01/09/2008 klokken 05:17
kilden bruker
På andre språk...                            


6 svar

stemmer
2

Både Johannes 'løsninger ville fungere. Et annet alternativ som gjør at HTMLDecorator å forbli veldig enkel og ren er å ape-lapp det inn som en base klasse. Dette fungerer også bare for brukerdefinerte klasser, ikke builtin typer:

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

Bli advart, skjønt - ape-lapp som dette kommer med en høy pris i lesbarhet og vedlikehold av koden din. Når du går tilbake til denne koden et år senere, kan det bli svært vanskelig å finne ut hvordan din ClassX fikk det html () -metoden, spesielt hvis ClassX er definert på annen biblioteket.

Svarte 01/09/2008 kl. 08:30
kilden bruker

stemmer
2

Svært nær, men da mister jeg alt fra ClassX. Nedenfor er noe en kollega ga meg som gjør gjøre triks, men det er heslig. Det må være en bedre måte.

Ser ut som du prøver å sette opp en slags proxy objekt ordningen. Det er gjennomførbart, og det finnes bedre løsninger enn kollegaen din, men først vurdere om det vil være lettere å bare lappe på noen ekstra metoder. Dette vil ikke fungere for innebygde klasser som bool, men det vil for brukerdefinerte klasser:

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

Og her er den proxy-versjonen:

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)
Svarte 01/09/2008 kl. 07:33
kilden bruker

stemmer
0

@John (37479):

Svært nær, men da mister jeg alt fra ClassX. Nedenfor er noe en kollega ga meg som gjør gjøre triks, men det er heslig. Det må være en bedre måte.

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

Produksjon:

<H1> Beste gjetning </ h1>
<H1> <__ __ hoved. Classy objekt ved 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>
Svarte 01/09/2008 kl. 06:55
kilden bruker

stemmer
0

Ah, i så fall, kanskje kode som dette vil være nyttig? Det gjør egentlig ikke noe å gjøre med dekoratører, men demonstrerer hvordan å passere argumenter til en klasse er initialisering funksjon og til å hente disse argumentene for senere.

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()
Svarte 01/09/2008 kl. 06:25
kilden bruker

stemmer
0

@John (37448):

Beklager, jeg kan ha villedet deg navnet (dårlig valg). Jeg er egentlig ikke ute etter en dekoratør funksjon, eller noe å gjøre med dekoratører i det hele tatt. Hva jeg er ute etter er for html (egen-) def bruke ClassX eller stilig s __repr__. Jeg vil at dette skal fungere uten å endre ClassX eller stilig.

Svarte 01/09/2008 kl. 06:10
kilden bruker

stemmer
0

Er det jeg prøver å gjøre mulig? Hvis ja, hva gjør jeg galt?

Det er absolutt mulig. Hva er galt er at HTMLDecorator.__init__()ikke godtar parametere.

Her er et enkelt eksempel:

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
Svarte 01/09/2008 kl. 05:26
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more