在运行时重新定义可调用对象

时间:2016-04-27 19:48:41

标签: python python-2.7 callable

我使用wx库来构建GUI。我初始化了一个面板并初始化了一些按钮,并绑定了一个在推送时执行的功能。该函数接受一个参数列表,一个是回调函数。我想要做的是在运行时重新定义回调函数,但我没有这样做。

到目前为止,我的尝试是:

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

我预定义了一些更新/获取对象。

我将函数绑定到按钮

在运行时,我调用init_battery_intf来初始化这些对象

当我尝试调用回调函数时出错的行。它似乎仍被设置为无。

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

我知道我可以重新定义绑定并直接输入值,但我想保持我的代码干净简单,我觉得Python有办法将重新定义的回调函数分发给对象的所有实例。 / p>

我正在使用Python 2.7。

1 个答案:

答案 0 :(得分:0)

您有几个选择:

答:self.UpdateCurrentself.battery_control_d使用的其他方法已初始化。 (从不初始化为无)

B:当self.UpdateCurrent和/或其他人更新时,重新创建/更新self.battery_control_d

C:使用名称引用并从self.battery_control_d访问时获取该属性的值。

前两个是非常自我解释但似乎你对选项C感兴趣所以我会扩展它:

您可以创建一个包含多个property的类,以便在访问时从原始对象中检索属性。

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

如果您不熟悉property,则在实例上访问属性名称时会调用它所修饰的函数(因此检索原始实例的属性)

所以在这种情况下你会像这样写self.battery_control_d的初始化:

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

然后self.battery_control_d["current"].get将是getattr(self,"GetCurrent")的结果,它相当于self.GetCurrent动态。

如果您真的想使用VALUE[0]VALUE[1]代替VALUE.updateVALUE.get,那么您也可以覆盖该类的__getitem__,尽管我强烈建议切换到更详细的解决方案:

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