2016-04-27 19 views
0

Ich verwende die WX-Bibliothek, um eine GUI zu erstellen. Ich habe ein Panel initialisiert und einige Drucktasten initialisiert und binde eine Funktion, die beim Drücken ausgeführt wird. Die Funktion benötigt eine Liste von Argumenten, von denen eines eine Callback-Funktion ist. Was ich versuche, ist die Callback-Funktion während der Laufzeit neu zu definieren, aber ich versäume es.Neudefinieren eines aufrufbaren Objekts während der Laufzeit

Mein Versuch, so weit ist:

self.UpdateCurrent = None 
    self.GetCurrent = None 
    self.UpdateCellVoltage = None 
    self.GetCellVoltage = None 
    self.UpdateCellTemperature = None 
    self.GetCellTemperature = None 
    self.battery_control_d = OrderedDict([('Current',[self.UpdateCurrent, self.GetCurrent, None, 1]), 
              ('Cell Voltage',[self.UpdateCellVoltage, self.GetCellVoltage, 0, 24]), 
              ('Cell Temperature',[self.UpdateCellTemperature, self.GetCellTemperature, 0, 24])]) 
    . 
    . 
    . 
    submit_btn_l[-1].Bind(wx.EVT_BUTTON, 
          lambda evt, 
          io_name = io_name, 
          callback_fn = self.battery_control_d[io_name][0], 
          ctrl_textbox = ctrl_textbox, 
          dim_combobox = self.dim_combobox_l[-1]: 
          self._send_control_value(evt, 
                io_name, 
                callback_fn, 
                ctrl_textbox, 
                dim_combobox)) 
    . 
    . 
    . 
    def init_battery_intf(self): 
     self.battery_intf = self.simulator_main_panel.battery_intf 

     self.UpdateCurrent = self.battery_intf.UpdateCurrent 
     self.GetCurrent = self.battery_intf.GetCurrent 

     self.UpdateCellVoltage = self.battery_intf.UpdateCellVoltage 
     self.GetCellVoltage = self.battery_intf.GetCellVoltage 

     self.UpdateCellTemperature = self.battery_intf.UpdateCellTemperature 
     self.GetCellTemperature = self.battery_intf.GetCellTemperature 
    . 
    . 
    . 
    def _send_control_value(self, 
          evt, 
          io_name, 
          callback_fn, 
          ctrl_textbox, 
          dim_combobox): 
     io_value = float(ctrl_textbox.Value) 
     if ("Temperature" in io_name): 
      io_value -= self.simulator_main_gui.temperature_unit_converter 
     callback_fn(io_value, int(dim_combobox.Value)) 
    def update(self, 
       evt): 

     for io_name, io_info in self.battery_control_d.iteritems(): 
      io_value = float(io_info[1](io_info[2])) 

      self.reading_text_l[self.io_indexer.index(io_name)].SetLabel(" %.4f " % (io_value)) 

ich vordefinieren einige Aktualisierung/Objekte bekommen.

Ich binde die Funktion zu den Tasten

Während der Laufzeit ich init_battery_intf nennen diese Objekte

Die Linie, die Fehler aus zu initialisieren ist, wenn ich versuche, die Callback-Funktion aufzurufen. Es scheint immer noch auf Keine eingestellt zu sein.

Traceback (most recent call last): 
    File "C:\Users\Sam\Desktop\work\simulator\src\simulate.py", line 1185, in updat 
    self.control_notebook.update(evt) 
    File "C:\Users\Sam\Desktop\work\simulator\src\simulate.py", line 869, in update 
    self.battery_control_panel.update(evt) 
    File "C:\Users\Sam\Desktop\work\simulator\src\simulate.py", line 591, in update 
    io_value = float(io_info[1](io_info[2])) 
TypeError: 'NoneType' object is not callable 

Ich weiß, ich könnte die binden und Futtermittel in den Werten direkt neu zu definieren, aber ich wollte meinen Code sauber und einfach zu halten, und ich fühle mich wie Python eine Art und Weise hat die neu definierte Callback-Funktion auf alle Instanzen zu verteilen das Objekt.

Ich benutze Python 2.7.

+1

bitte zeigen der gesamte Traceback, hilft es wirklich zu wissen, welche Zeilen im Code zu einem Problem führen. –

+0

@ TadhgMcDonald-Jensen Hinzugefügt Tracelog und die Funktion, wo der Fehler auftritt. – Sam

+0

Ist 'io_info [1]' was Sie erwarten, um eine Rückruffunktion zu sein? Das ist der Ausdruck, der zu "None" führt und nicht aufgerufen werden kann. – dsh

Antwort

0

Sie haben ein paar Optionen:

A: Haben self.UpdateCurrent und die anderen von self.battery_control_d verwendeten Methoden bereits initialisiert. (niemals initialisieren auf Keine)

B: wenn self.UpdateCurrent und/oder die anderen aktualisiert werden, erstellen/aktualisieren Sie self.battery_control_d.

C: Verwenden Sie eine Namensreferenz, und rufen Sie den Wert dieses Attributs ab, wenn Sie auf self.battery_control_d zugreifen.


Die ersten beiden sind ziemlich selbsterklärend, aber es scheint, dass Sie in Option C interessiert sind, so werde ich mich auf diese erweitern:

Sie können eine Klasse mit mehreren property (n) erstellen, die von einem Attribut abrufen Ihr ursprüngliches Objekt, wenn Sie darauf zugreifen.

class VarReference(object): 
    def __init__(self, inst, update_name, get_name, value1, value2): 
     self.inst = inst 
     self.update_attr_name = update_name 
     self.getter_attr_name = get_name 
     self.value1 = value1 
     self.value2 = value2 

    @property 
    def get(self): 
     return getattr(self.inst, self.getter_attr_name) 

    @property 
    def update(self): 
     return getattr(self.inst, self.update_attr_name) 


class Test(object):pass #dummy class for my demo 
self = Test() 

self.UpdateCurrent = self.GetCurrent = None 

ref_obj = VarReference(self,"UpdateCurrent","GetCurrent",None,1) 

>>> print(ref_obj.get) 
None 
>>> self.GetCurrent = lambda:5 
>>> ref_obj.get 
<function <lambda> at 0x1057d5488> 
>>> ref_obj.get() 
5 

Wenn Sie mit property nicht vertraut sind im Grunde die Funktion, die es verziert wird aufgerufen, wenn der Attributname auf einer Instanz zugegriffen wird (und damit ein Attribut der ursprünglichen Instanz zu erhalten)

so würden Sie in diesem Fall schreiben die Initialisierung für self.battery_control_d wie folgt aus:

self.battery_control_d = OrderedDict([('Current',VarReference(self, "UpdateCurrent", "GetCurrent", None, 1)), 
             ('Cell Voltage',VarReference(self, "UpdateCellVoltage", "GetCellVoltage", 0, 24)), 
             ('Cell Temperature',VarReference(self, "UpdateCellTemperature", "GetCellTemperature", 0, 24)) 
            ]) 

dann self.battery_control_d["current"].get das Ergebnis getattr(self,"GetCurrent") sein würde, die zuentsprichtdynamisch.

Wenn Sie wirklich wollen VALUE[0] und VALUE[1] verwenden, anstatt VALUE.update und VALUE.get dann können Sie nur __getitem__ der Klasse außer Kraft setzen und, obwohl ich sehr zu ausführlicheren Switching-Lösungen würde empfehlen:

class VarReference(object): 
    ... 
    def __getitem__(self,item): 
     if item==0: 
      return self.update 
     elif item == 1: 
      return self.get 
     elif item ==2: 
      return self.value1 
     elif item == 3: 
      return self.value2 
     else: 
      raise IndexError("Can only get indices from 0 to 3") 
+0

Ich würde auch gerne hinzufügen, dass das Erstellen von Eigenschaften, die einfach die Get-Funktion ** aufrufen und Setter, die das Update aufrufen, hier sehr sinnvoll sind, obwohl Ihre get-Funktion ein Argument zu nehmen scheint, also bin ich nicht wirklich sicher, wie es in Ihre Implementierung passen würde. –

+0

Vielen Dank. Ich war eine Weile auf dieser Sache, und es scheint, dass Eigentum das Schlüsselkonzept war, das ich vermisste. Sehr cooler Trick/Werkzeug. Wie für meine Funktionen Argumente zu nehmen scheint, wenn ich Instanz der VarReference Methode Get aufrufen, können Sie Argumente in seine Signatur einspeisen, wenn es eine Funktion ist, die Signaturen hat. ref_get.get (arg1, arg2, arg3 ...). Vielleicht könnten Sie Ihre Antwort so bearbeiten, dass sie eine vollständige Lösung darstellt. Ich habe es getestet, indem ich eine einfache Funktion übergeben habe. – Sam

+0

mein Verständnis war, dass Sie eine Möglichkeit suchten, dynamisch den Wert von "self.UpdateCurrent" und "self.GetCurrent", die ich zur Verfügung gestellt habe, abzurufen. Wenn Sie 'ref_Var.get' ausführen, wird die Methode (aufrufbar oder nicht) von self aufgerufen und Sie rufen sie dann so auf, als würden Sie' self.GetCurrent (ARG) 'schreiben. Wenn Ihr Getter keine Argumente angenommen hat und das Update ein einzelnes Argument verwendet hat, könnte die Eigenschaft "value" genannt werden, die die Getter-Methode aufruft, so dass Sie einfach 'ref_var.value' verwenden können, um den Wert zu erhalten und' ref_var.value = NEW_VALUE' um es zu aktualisieren. –