2008-09-15 12 views
8

¿Cómo agrego un método de instancia a una clase usando una metaclase (sí, necesito usar una metaclase)? El siguiente tipo de obras, pero el func_name seguirán siendo "foo":Cómo agregar el método usando la metaclase

def bar(self): 
    print "bar" 

class MetaFoo(type): 
    def __new__(cls, name, bases, dict): 
     dict["foobar"] = bar 
     return type(name, bases, dict) 

class Foo(object): 
    __metaclass__ = MetaFoo 

>>> f = Foo() 
>>> f.foobar() 
bar 
>>> f.foobar.func_name 
'bar' 

Mi problema es que algunos código de la biblioteca en realidad utiliza el func_name y más tarde no puede encontrar el método de 'barra' de la instancia de Foo. Que podía hacer:

dict["foobar"] = types.FunctionType(bar.func_code, {}, "foobar") 

También hay types.MethodType, pero necesito una instancia que does'nt existe todavía utilizar eso. ¿Me estoy perdiendo algo aquí?

+0

Por qué estás tratando de cambiar el nombre del método? no dict [bar.func_name] = bar logra lo que quieres? –

+0

Buena pregunta ... Originalmente estaba creando nombres de métodos basados ​​en los atributos definidos en el dict, pero me doy cuenta de que esto no tiene sentido si las implementaciones de los métodos son idénticas. –

Respuesta

15

Trate de extender dinámicamente las bases de esa manera usted puede tomar ventaja de la MRO y los métodos son métodos actuales:

class Parent(object): 
    def bar(self): 
     print "bar" 

class MetaFoo(type): 
    def __new__(cls, name, bases, dict): 
     return type(name, (Parent,) + bases, dict) 

class Foo(object): 
    __metaclass__ = MetaFoo 

if __name__ == "__main__": 
    f = Foo() 
    f.bar() 
    print f.bar.func_name 
+2

¿Qué sucede si quiero crear varios métodos que hagan referencia a la implementación de 'barra'? –

+0

Hola Aaron, funciona bien, pero si intentas crear una nueva clase NewFoo que herede de Foo obtienes un error de herencia debido a problemas de MRO. He intentado resolver este problema con un enfoque similar: https://github.com/tierratelematics/pypom_form/blob/refactor/pypom_form/meta.py#L111 pero no sé si es el mejor enfoque o si hay una forma más pitonica de hacerlo. Debería funcionar bien en Python 3 también –

2

Creo que lo que quiere hacer es la siguiente:

>>> class Foo(): 
... def __init__(self, x): 
...  self.x = x 
... 
>>> def bar(self): 
... print 'bar:', self.x 
... 
>>> bar.func_name = 'foobar' 
>>> Foo.foobar = bar 
>>> f = Foo(12) 
>>> f.foobar() 
bar: 12 
>>> f.foobar.func_name 
'foobar' 

Ahora que son libres de pasar Foo s a una biblioteca que espera Foo casos disponer de un método llamado foobar.

Desafortunadamente, (1) No sé cómo usar las metaclases y (2) No estoy seguro de haber leído su pregunta correctamente, pero espero que esto ayude.

Tenga en cuenta que func_name es solo asignable en Python 2.4 y superior.

Cuestiones relacionadas