在某些情况下,我们需要在一个函数内定义另一个函数,并且内部函数需要访问外部函数的局部变量。例如,以下代码尝试在 DNPClass 类的 handleResponseEvent() 方法中执行额外的 C1 类方法。但是,如果 handleResponseEvent() 方法定义在 main() 函数内,它才能正常工作。问题是,我们希望了解在函数内定义函数的其他方法,以及在 main() 函数内定义事件处理函数是否为最佳方法。
def main():
C1 = DNPClass()
C1.method1(arg1, arg2, arg3, arg4, arg5)
# subscribing to event
C1.method2.RequestEvent += handleResponseEvent
...
def handleResponseEvent( request, response):
#code to execute when event handler is called
#code references additional method from C1 instance
....
2. 解决方案
- 将事件处理函数定义在外部函数内
第一种方法是将 handleResponseEvent() 方法定义在 DNPClass 类中,而不是在 main() 函数内。这样,内部函数就可以访问 DNPClass 类的实例变量。以下代码展示了这种方法:
class DNPClass:
def __init__(self):
self.method2 = Method2()
def method1(self, arg1, arg2, arg3, arg4, arg5):
# code
def handleResponseEvent(self, request, response):
# code to execute when event handler is called
# code references additional method from self instance
...
class Method2:
def __init__(self):
self.RequestEvent = Event()
def main():
C1 = DNPClass()
C1.method1(arg1, arg2, arg3, arg4, arg5)
# subscribing to event
C1.method2.RequestEvent += C1.handleResponseEvent # will call C1.method3
...
- 使用闭包来访问外部函数的局部变量
第二种方法是使用闭包来访问外部函数的局部变量。闭包是指一个可以访问另一个函数作用域变量的函数。在以下代码中,我们使用闭包将 C1 对象传递给 handleResponseEvent() 函数:
def main():
C1 = DNPClass()
C1.method1(arg1, arg2, arg3, arg4, arg5)
# subscribing to event
C1.method2.RequestEvent += lambda request, response: handleResponseEvent(request, response, C1)
...
def handleResponseEvent(request, response, dnp):
# code to execute when event handler is called
# code references additional method from dnp instance
dnp.method3()
...
- 使用 functools.partial() 函数来创建闭包
第三种方法是使用 functools.partial() 函数来创建闭包。partial() 函数可以创建一个新的函数,该函数可以将参数部分预先绑定到另一个函数。在以下代码中,我们使用 partial() 函数将 C1 对象作为参数绑定到 handleResponseEvent() 函数:
from functools import partial
def main():
C1 = DNPClass()
C1.method1(arg1, arg2, arg3, arg4, arg5)
# subscribing to event
C1.method2.RequestEvent += partial(handleResponseEvent, C1)
...
def handleResponseEvent(dnp, request, response):
# code to execute when event handler is called
# code references additional method from dnp instance
dnp.method3()
...
三种方法各有优缺点,可以根据具体情况选择使用哪种方法。