代码样式 - 在其他函数中“隐藏”函数

时间:2012-09-04 15:53:07

标签: python coding-style scoping

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

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__开始看起来很长,有很多本地函数定义。我应该使用更合适的替代方案吗?

2 个答案:

答案 0 :(得分:8)

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

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

在它的核心,这与你的第一个例子非常相似,所以如果你更喜欢第一种方式 - 去吧。我认为在这种情况下创建一个新方法通常不是惯用的(除非你实际上需要将实例传递给回调 - 在这种情况下,你应该第二种方式)

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

如果__init__没有变得杂乱无章,那么请随意将这些功能放在那里。在那里使用函数确实意味着每次创建新实例时都会创建一个新函数(与lambda相同)我认为就内存而言可能是浪费,但是它应该不是那么大的交易(特别是在gui中)。

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

答案 1 :(得分:2)

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

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

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