5

最近我一直在做这样的事情:

import Tkinter
class C(object):
    def __init__(self):
        self.root = Tkinter.Tk()
        def f():
            print 'hello'
        self.button = Tkinter.Button(master=self.root, command=f, text='say hello')

而不是这样的:

import Tkinter
class C(object):
    def __init__(self):
        self.root = Tkinter.Tk()
        self.button = Tkinter.Button(master=self.root, command=self.f, text='say hello')
    def f(self):
        print 'hello'

这个问题并不特定于 Tkinter,但它是一个很好的例子。该函数f仅用作按钮的回调,因此我选择在内部定义它__init__。这样,只有内部的代码__init__甚至知道f' 的存在——外部范围不会开始被名称弄得一团糟,用户也不需要关心大量设计为内部的方法。

我的问题是:这算是好的风格吗?我很担心,因为我有一个带有很多按钮的 GUI 类 -__init__开始看起来很长,有很多本地函数定义。我应该使用更合适的替代方案吗?

4

2 回答 2

8

在上下文中执行此类操作的典型方法Tkinter是使用lambda函数。

self.button = Tkinter.Button(master=self.root, 
                             command=lambda:sys.stdout.write("Hello!\n"),
                             text='say hello')

本质上,这与您的第一个示例实际上是相同的,因此,如果您更喜欢第一种方式,那就去吧。我认为在这种情况下创建一个新方法通常不是惯用的(除非您实际上需要将实例传递给回调——在这种情况下,您应该采用第二种方式)。

这里有两件事需要担心。首先是可读性。如果__init__太杂乱而无法阅读,那么您就有问题了。您可以将这些函数移动到模块级别(以 an 为前缀_以防止它们在from module import *上下文中导入)并lambda在必要时将局部变量作为参数绑定到这些函数。

如果__init__没有变得混乱,那么请随意将功能放在那里。将函数放在那里确实意味着每次创建新实例时都会创建一个新函数lambda(与在 gui 中)。

第二件要担心的是命名空间混乱。但是,如果您的模块太大以至于将这些本地函数移动到模块级函数会产生命名空间问题,那么您的模块太大而无法开始。只要您在函数前加上下划线(请参阅上面的建议),在其他模块中导入此模块时也不应该有命名空间问题。

于 2012-09-04T15:54:25.777 回答
2

在这种情况下,它是无害的。不过,总的来说,我会避免它有两个原因:

1)作为类成员的回调定义更具可读性(尤其是当您使用 pydoc 进行调查时)

2)在另一个内部创建函数会引入更多闭包(从调用上下文继承的变量)。

于 2012-09-04T15:59:10.140 回答