Como posso simplesmente herdar métodos de uma instância existente?

votos
0

Abaixo eu tenho um exemplo muito simples do que estou tentando fazer. Eu quero ser capaz de usar HTMLDecorator com qualquer outra classe. Ignorar o fato de que é chamado de decorador, é apenas um nome.

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

Saída:

Traceback (chamada mais recente passada):
  File html.py, linha 21, em 
    HTMLDecorator impressão (inst_x) .html ()
TypeError: __new__ padrão não tem parâmetros

É o que eu estou tentando fazer possível? Se assim for, o que estou fazendo de errado?

Publicado 01/09/2008 em 06:17
fonte usuário
Em outras línguas...                            


6 respostas

votos
2

Ambas as soluções de João iria funcionar. Outra opção que permite HTMLDecorator permanecer muito simples e limpo é macaco patch-lo em como uma classe base. Isso também funciona apenas para classes definidas pelo usuário, tipos não embutidas:

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

Esteja avisado, embora - macaco-patch como este vem com um alto preço em legibilidade e manutenção do seu código. Quando você voltar a este código de um ano depois, ele pode se tornar muito difícil de descobrir como o seu ClassX tem esse método html (), especialmente se ClassX é definido em alguma outra biblioteca.

Respondeu 01/09/2008 em 09:30
fonte usuário

votos
2

Muito perto, mas então eu perder tudo, desde ClassX. Abaixo é algo que um colega me deu que não fazer o truque, mas é medonho. Tem que haver uma maneira melhor.

Parece que você está tentando criar algum tipo de esquema objeto proxy. Isso é factível, e há soluções melhores do que o seu colega, mas em primeiro lugar considerar se seria mais fácil simplesmente corrigir em alguns métodos extra. Isso não vai funcionar para classes internas como bool, mas vai para as suas classes definidas pelo usuário:

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

E aqui é a versão 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)
Respondeu 01/09/2008 em 08:33
fonte usuário

votos
0

@John (37479):

Muito perto, mas então eu perder tudo, desde ClassX. Abaixo é algo que um colega me deu que não fazer o truque, mas é medonho. Tem que haver uma maneira melhor.

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

Saída:

<H1> Best Guess </ H1>
<H1> <__ principal __. Objeto elegante ao 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>
Respondeu 01/09/2008 em 07:55
fonte usuário

votos
0

Ah, nesse caso, talvez um código como este será útil? Ele realmente não tem nada a ver com decoradores, mas demonstra como passar argumentos para função de inicialização de uma classe e para recuperar esses argumentos para mais tarde.

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()
Respondeu 01/09/2008 em 07:25
fonte usuário

votos
0

@John (37448):

Desculpe, eu poderia ter enganado-lo com o nome (má escolha). Eu realmente não estou procurando uma função decorador, ou qualquer coisa a ver com decoradores de todo. O que eu estou atrás é para o def html (self) para usar ClassX ou ClassY de __repr__. Eu quero que isso funcione sem modificar ClassX ou elegante.

Respondeu 01/09/2008 em 07:10
fonte usuário

votos
0

É o que eu estou tentando fazer possível? Se assim for, o que estou fazendo de errado?

É certamente possível. O que está errado é que HTMLDecorator.__init__()não aceita parâmetros.

Aqui está um exemplo simples:

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
Respondeu 01/09/2008 em 06:26
fonte usuário

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