2010-11-20 17 views
6

Comment écrire une fonction qui ajoute une méthode à une classe? J'ai:Métaprogrammation Python: générer automatiquement des fonctions membres

class A: 
    def method(self): 
     def add_member(name): 
      self.new_method = def name...? 

     add_member("f1") 
     add_member("f2") 

Afin de répondre à ce que je suis en train de faire. J'essaie de prendre en compte certaines machines à sous pyqt. Je veux être en mesure d'appeler une fonction create_slider qui va créer un QSlider et un QLabel et créer le code de gestion de curseur, et faire le curseur-gestionnaire mettre à jour le texte dans le QLabel. Voici l'emplacement qui doit être refactorisée:

def on_sample_slider(self, value): 
     self.samples = pow(4, value) 
     self.sample_label.setText('%d' % self.samples) 

est ici une méthode qui génère une interface utilisateur, mais ce serait bien d'avoir aussi générer la méthode on_sample_slider chaque fois qu'il est appelé:

def insert_labeled_slider(hbox, name, slider_target): 
     # name 
     hbox.addWidget(QLabel(name)) 

     # label 
     label = QLabel() 
     label.setMinimumSize(40, 0) 
     hbox.addWidget(self.sample_label) 

     #slider 
     slider = QSlider(Qt.Horizontal) 
     slider.setRange(0, 6) 
     slider.setTracking(True) 
     slider.setPageStep(1) 
     hbox.addWidget(slider) 

     self.connect(self.sample_slider, SIGNAL('valueChanged(int)'), 
        self.on_sample_slider) 
     self.sample_slider.setValue(0) 
     return (label, slider) 

Code final:

def attach_on_slider(obj, name, variable, label, base): 
    def on_slider(self, value): 
     variable = base**value 
     label.setText('%d' % variable) 

    # This next line creates a method from the function 
    # The first arg is the function and the second arg is the object 
    # upon which you want it to be a method. 
    method = types.MethodType(on_slider, obj) 
    obj.__dict__["on_slider_" + name] = method 
    return method 

class A: 
    def insert_labeled_slider(hbox, name, label_name, variable): 
     # name 
     hbox.addWidget(QLabel(label_name)) 

     # label 
     label = QLabel() 
     label.setMinimumSize(40, 0) 
     hbox.addWidget(label) 

     #slider 
     slider = QSlider(Qt.Horizontal) 
     slider.setRange(0, 6) 
     slider.setTracking(True) 
     slider.setPageStep(1) 
     hbox.addWidget(slider) 

     on_slider_method = attach_on_slider(self, name, variable, label, 4) 

     self.connect(slider, SIGNAL('valueChanged(int)'), 
        on_slider_method) 
     slider.setValue(0) 
     return (label, slider) 
+1

Les méthodes 'f1' et' f2' sont-elles déjà définies quelque part? – BudgieInWA

+0

non, j'essaie de les générer à l'intérieur de la fonction d'aide. –

+0

(J'essaie de factoriser certaines fonctions membres identiques. –

Répondre

7

Voici un exemple réel de votre nouveau code affiché:

import types 

def attach_on_sample_slider(obj, base): 
    def on_sample_slider(self, value): 
     self.samples = base**value 
     self.sample_label.setText('%d' % self.samples) 

    # This next line creates a method from the function 
    # The first arg is the function and the second arg is the object 
    # upon which you want it to be a method. 
    obj.on_sample_slider = types.MethodType(on_sample_slider, obj) 

Vous pouvez l'appeler comme

def some_method(self, foo): 
    attach_on_sample_slider(self, 4) 

message original

Puisque vous dites que les fonctions membres sont identiques, je le ferais quelque chose comme ça

def make_method(name): 
    def method(self, whatever, args, go, here): 
     #whatever code goes here 
    method.__name__ = name 
    return method 


class A(object): 
    method1 = make_method('method1') 
    method2 = make_method('method2') 

Strictement parlant, en passant le nom et en réglant le __name__ attribut sur la nouvelle fonction n'est pas nécessaire, mais il peut aider avec le débogage. C'est un peu de duplication et peut payer pour lui-même. Si vous allez ignorer cela, vous pourriez aussi bien le faire

class A(object): 
    def method1(self, arg1, arg2): 
     #code goes here 

    method2 = method1 
    method3 = method1 

Cela crée des méthodes identiques. Appeler l'un ou l'autre donnera la même méthode.

La première forme est plus puissante parce que vous pouvez passer d'autres arguments à côté du nom dans make_method et que les différentes versions de la méthode retournée accèdent à ces paramètres en fermeture afin qu'ils fonctionnent différemment. Voici un exemple stupide avec des fonctions (fonctionne même avec des méthodes):

def make_opener(filename): 
    def opener(): 
     return open(filename) 
    return opener 

open_config = make_opener('config.cfg') 
open_log = make_opener('log.log') 

Ici, ils sont tous essentiellement la même fonction, mais faire des choses un peu différentes parce qu'ils ont accès à la valeur de filename qu'ils ont été créés avec . Les fermetures sont certainement quelque chose à regarder si vous allez faire beaucoup de ce genre de chose.

Il peut y avoir beaucoup plus à ce sujet, donc si vous avez des questions particulières que cela ne répond pas, vous devriez mettre à jour votre question.

+0

Ceci est totalement incroyable, et l'une des raisons pour lesquelles j'utilise python au lieu de C++. –

+0

J'ai remarqué que vous faites les méthodes dans la portée principale de la classe. Est-ce que les méthodes peuvent être faites dans une fonction membre de la classe, puis liées à ce moment-là. Par exemple, en écrivant 'self.method1 = make_method ...'? –

+0

Wow, je ne savais pas que vous pouviez faire ça avec Python! – helpermethod

Questions connexes