7

我创建了一个可以使用带有一组参数的函数的类。我想在每次事件处理程序发出信号时运行传递的函数。

我在下面附上了我的代码,当我传递一个fun2没有参数但没有参数时运行的代码fun1fun1我可以对下面的代码提出任何建议fun2吗?如果我省略了 from 的 return 语句fun1,我会得到一个错误'str' object is not callable

>>> TimerTest.main()
function 1. this function does task1
my function from init from function1
my function in start of runTimerTraceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program Files (x86)\IronPython 2.7\TimerTest.py", line 57, in main
File "C:\Program Files (x86)\IronPython 2.7\TimerTest.py", line 25, in runTime
r
TypeError: str is not callable



import System  
from System.Timers import (Timer, ElapsedEventArgs)

class timerTest:

    def __init__ (self, interval,autoreset, fun):
        self.Timer = Timer()
        self.Timer.Interval= interval
        self.Timer.AutoReset = autoreset
        self.Timer.Enabled = True
        self.myfunction = fun

    def runTimer(self):

        print 'my function in start of runTimer', self.myfunction ()

        self.Timer.Start()

        def OnTimedEvent (s, e):
                print "The Elapsed event was raised at " , e.SignalTime
                print 'printing myfunction...', self.myfunction()
                self.myfunction()

        self.Timer.Elapsed += OnTimedEvent


    def stopTimer(self):
        self.Timer.Stop()
        self.Timer.Dispose= True


def fun1(a,b):
   print 'function 1. this function does task1'
   return 'from function1'

def fun2():
   print 'Function 2. This function does something'
   print 'Test 1...2...3...'
   return 'From function 2'

def main():
    a = timerTest(1000, True, fun1(10,20))
    a.runTimer()

    b= timerTest(3000,True,fun2)
    b.runTimer()

if __name__ == '__main__':
  main()

我正在学习 Python,如果我的问题是基本的,我深表歉意。

要更改间隔,我使用添加到 timerTest 类的 stopTimer 方法停止计时器:

def stopTimer(self):
    self.Timer.Stop()

我采用新的用户输入来调用我根据 Paolo Moretti 的建议修改的 runTimer 方法:

def runTimer(self, interval,autoreset,fun,arg1, arg2, etc.):

    self.Timer.Interval= interval
    self.Timer.AutoReset = autoreset
    myfunction = fun
    my_args = args

    self.Timer.Start()

        def OnTimedEvent (s, e):
            print "The Elapsed event was raised at " , e.SignalTime
            myfunction(*my_args)

    self.Timer.Elapsed += OnTimedEvent   

每当按下命令按钮时,都会调用以下方法:

requestTimer.runTimer((self.intervalnumericUpDown.Value* 1000),True, function, *args) 

我不明白为什么停止计时器并发送请求会导致 runTimer 方法被执行多次,这似乎取决于我更改间隔的次数。我尝试了几种方法:关闭并处置但没有成功。

关于稍微不同的主题的第二个问题。

我一直在研究其他带有 Timer 类的 .NET 类。第二个问题是如何将以下 VB 示例代码转换为 Python。“作为 TimerCallback 的回调”是否等同于 myfunction(*my_args)?

Public Sub New ( _
  callback As TimerCallback, _
  state As Object, _
  dueTime As Integer, _
  period As Integer _
)  

每个 .NET 文档:回调 类型:System.Threading.TimerCallback 代表要执行的方法的 TimerCallback 委托。如果我定义一个没有参数的函数,我可以部分触发计时器事件,例如:

def fun2(stateinfo):
    # function code

适用于:

self.Timer = Timer(fun2, self.autoEvent, self.dueTime,self.period)

如果我用更通用的函数调用 myfunction(*my_args) 替换 fun2,函数调用将失败

4

2 回答 2

6

您还可以使用*语法来调用具有任意参数列表的函数:

class TimerTest:
    def __init__(self, interval, autoreset, fun, *args):
        # ...
        self.my_function = fun
        self.my_args = args
        # ...

    def run_timer(self):
        # ...
        def on_timed_event(s, e):
            # ...
            self.my_function(*self.my_args)
            # ...

用法:

>>> t1 = TimerTest(1000, True, fun1, 10, 20)
>>> t2 = TimerTest(1000, True, fun2)

并查看PEP8风格指南。Python 的首选编码约定与许多其他常见语言不同。


问题 1

每次使用加法赋值运算符 ( +=) 时,您都在为事件附加一个新的事件处理程序。例如这段代码:

timer = Timer()

def on_timed_event(s, e):
    print "Hello form my event handler"

timer.Elapsed += on_timed_event
timer.Elapsed += on_timed_event

timer.Start()

将打印该"Hello form my event handler"短语两次。

有关更多信息,您可以查看MSDN 文档,特别是订阅和取消订阅事件

因此,您可能应该将事件订阅移动到该__init__方法,并且只在您的方法中启动计时器run_timer

def run_timer(self):
     self.Timer.Start()

您还可以添加一个新方法(或使用属性)来更改间隔:

def set_interval(self, interval):
     self.Timer.Interval = interval

问题2

你是对的TimerCallback:它是一个代表要执行的方法的委托。

例如,这个Timer构造函数

public Timer(
    TimerCallback callback
)

期待一个void具有单个参数类型的函数Object

public delegate void TimerCallback(
    Object state
)

当您使用*语法调用函数时,您正在做一些完全不同的事情。如果我给你看一个例子可能会更容易:

def foo(a, b, *args):
    print a
    print b
    print args

>>> foo(1, 2, 3, 4, 5)
1
2
(3, 4, 5)

>>> args = (1, 2, 3)
>>> foo(1, 2, *args)
1
2
(1, 2, 3)

基本上在第二种情况下,您正在调用一个带有从元组中解包的附加参数的函数。

因此,如果您想将具有不同签名的函数传递给接受TimerCallback委托的构造函数,则必须创建一个新函数,就像@Lasse建议的那样。

def my_func(state, a, b):
    pass

您可以使用lambda关键字来执行此操作:

t1 = Timer(lambda state: my_func(state, 1, 2))

或者通过声明一个新函数:

def time_proc(state):
     my_func(state, 1, 2)

t2 = Timer(time_proc)
于 2013-07-06T21:40:22.213 回答
5

如果函数不带参数,只需传递它而不调用它:

b = timerTest(3000, True, fun2)

如果它带参数,则需要将其转换为不带参数的函数。你正在做的是调用它,然后你传递结果,在这种情况下是一个字符串。而是这样做:

a = timerTest(1000, True, lambda: fun1(10, 20))
于 2013-07-06T20:55:29.030 回答