2008-09-15 7 views
8

Comment ajouter une méthode d'instance à une classe en utilisant une métaclasse (oui, je dois utiliser une métaclasse)? Le genre suivant des travaux, mais le func_name seront toujours « foo »:Comment ajouter une méthode en utilisant la métaclasse

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' 

Mon problème est que du code de bibliothèque utilise en fait la func_name et ne parvient plus tard à trouver la méthode du « bar » de l'instance Foo. Je pouvais faire:

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

Il y a aussi types.MethodType, mais je besoin d'une instance qui does'nt existe encore utiliser. Est-ce que je manque quelque chose ici?

+0

Pourquoi vous essayez de changer le nom de la méthode? does not dict [bar.func_name] = barre accomplir ce que vous voulez? –

+0

Bonne question ... À l'origine, je créais des noms de méthodes basés sur des attributs définis dans le dict, mais je réalise que cela est inutile si les implémentations des méthodes sont identiques. –

Répondre

15

Essayez dynamiquement les bases étendre cette façon, vous pouvez profiter de la MRO et les méthodes sont des méthodes réelles:

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

Que se passe-t-il si je veux créer plusieurs méthodes faisant référence à l'implémentation de la barre? –

+0

Salut Aaron, ça marche bien mais si vous essayez de créer une nouvelle classe NewFoo qui hérite de Foo, vous obtenez une erreur d'héritage due aux problèmes MRO. J'ai essayé de résoudre ce problème avec une approche similaire: https://github.com/tierratelematics/pypom_form/blob/refactor/pypom_form/meta.py#L111 mais je ne sais pas si c'est la meilleure approche ou si il y a une façon plus pythonique de le faire. Cela devrait aussi fonctionner sur Python 3 –

2

Je pense que ce que vous voulez faire est la suivante:

>>> 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' 

Maintenant, vous êtes libre de passer Foo s à une bibliothèque qui attend des instances Foo d'avoir une méthode nommée foobar.

Malheureusement, (1) je ne sais pas comment utiliser les métaclasses et (2) je ne suis pas sûr d'avoir lu votre question correctement, mais j'espère que cela aide.

Notez que func_name est uniquement assignable dans Python 2.4 et supérieur.

Questions connexes