2010-11-20 28 views
6

Come si scrive una funzione che aggiunge un metodo a una classe? Ho:Metaprogrammazione Python: generazione automatica delle funzioni membro

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

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

Per rispondere a quello che sto cercando di fare. Sto cercando di calcolare alcune slot Pyqt. Voglio essere in grado di chiamare una funzione create_slider che creerà un QSlider e un QLabel e creare il codice di gestione del cursore e fare in modo che il gestore di cursori aggiorni il testo nello QLabel. Ecco lo slot che deve essere fattorizzato:

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

ecco un metodo che genera un po 'di interfaccia utente, ma sarebbe bello anche averlo generare il metodo on_sample_slider ogni volta che viene chiamato:

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) 

codice finale:

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

I metodi 'f1' e' f2' sono già definiti da qualche parte? – BudgieInWA

+0

no, sto provando a generarli all'interno della funzione di supporto. –

+0

(Sto cercando di individuare alcune funzioni membro identiche.) –

risposta

7

Ecco un esempio reale dal codice appena scritto:

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) 

È ora possibile chiamare come

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

postale

originale Dal momento che dici le funzioni membro sono identiche, lo farei qualcosa di simile

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

In senso stretto, passando il nome e impostandoL'attributosulla nuova funzione non è necessario ma può essere d'aiuto con il debug. È un po 'di duplicazione e può ripagarsi. Se vuoi saltare questo, potresti anche fare

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

    method2 = method1 
    method3 = method1 

Questo crea metodi identici. Chiamare uno di questi produrrà lo stesso metodo.

Il primo modulo è più potente perché è possibile passare altri argomenti oltre al nome in make_method e fare in modo che le diverse versioni del metodo restituito accedano a tali parametri in chiusura in modo che funzionino in modo diverso. Ecco un esempio stupido con le funzioni (funziona lo stesso con i metodi):

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

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

qui, sono tutti sostanzialmente la stessa funzione, ma fare le cose un po 'diverse perché hanno accesso al valore di filename che sono stati creati con . Le chiusure sono sicuramente qualcosa da esaminare se si sta andando a fare un sacco di questo genere di cose.

Ci può essere molto di più in questo modo, quindi se avete domande particolari che questo non risolve, è necessario aggiornare la domanda.

+0

Questo è assolutamente sorprendente, e uno dei motivi per cui sto usando Python invece di C++. –

+0

Ho notato che stai realizzando i metodi nell'ambito principale della classe. I metodi possono essere realizzati in una funzione membro della classe e quindi rilegati in quel momento. Ad esempio, scrivendo 'self.method1 = make_method ...'? –

+0

Wow, non sapevo che avresti potuto farlo con Python! – helpermethod

Problemi correlati