避免python作用域错误的策略

避免python作用域错误的策略,python,python-3.x,scope,ipython-notebook,Python,Python 3.x,Scope,Ipython Notebook,我在研究中广泛使用IPython笔记本。我发现它们是一个很棒的工具 然而,不止一次,我被来自可变范围的细微错误所困扰。例如,我将进行一些探索性分析: foo = 1 bar = 2 foo + bar 我认为foo+bar对于我来说是一种有用的算法,因此我将其封装在一个函数中,以使其更易于应用于更广泛的输入: def the_function(foo, bar): return foo + bar 不可避免地,在从头开始构建工作流之后,我会在某个地方出现一个打字错误(例如,def_函

我在研究中广泛使用IPython笔记本。我发现它们是一个很棒的工具

然而,不止一次,我被来自可变范围的细微错误所困扰。例如,我将进行一些探索性分析:

foo = 1
bar = 2
foo + bar
我认为
foo+bar
对于我来说是一种有用的算法,因此我将其封装在一个函数中,以使其更易于应用于更广泛的输入:

def the_function(foo, bar):
    return foo + bar
不可避免地,在从头开始构建工作流之后,我会在某个地方出现一个打字错误(例如,
def_函数(fooo,bar):
),导致在函数调用中使用(和/或修改)全局变量。这会导致看不见的副作用,并导致虚假的结果。但由于它通常会返回一个结果,因此很难找到问题实际发生的位置

现在,我认识到这种行为是我经常故意使用的一种特性(为了方便,或者出于必要,例如函数闭包或装饰器)。但当我不断遇到bug时,我想我需要一个更好的策略来避免这些问题(current strategy=“小心”)

例如,一种策略可能是始终在局部变量名前加上“u”。但我很好奇是否还有其他的策略——甚至是“pythonic”策略,或者是社区鼓励的策略

我知道Python2.x在范围界定方面与Python3.x有所不同——我使用Python3.x

<>也应考虑科学计算的交互性,如iPython笔记本会场所使用的。 想法


编辑:更具体地说,我正在寻找IPython笔记本战略。

我试图将这个问题标记为太宽泛,但以下内容可能会对您有所帮助

当您决定在函数中封装一些有用的代码时,请编写一些测试。如果您认为该代码很有用,那么您一定在一些示例中使用过它。先写测试,以免“忘记”

我个人对库模块的策略是在
if\u名称中运行测试__
=='\uuuuu main\uuuuu':
语句,测试代码是在同一个文件中还是在不同的文件中。我还执行该文件,以便在编程会话期间,在每一个小的更改单元(在空闲或类似IDE中微不足道)之后多次运行测试

使用一个代码检查器程序,它将捕获一些基于键入的错误。“‘fooo’设置但从未使用”

跟踪你犯下的特定类型的错误,分析它们并思考个人对策,或者至少学会识别症状


看看您的示例,在编写函数时,不要对全局对象和参数使用相同的名称。在您的示例中,删除或更改全局“foo”和“bar”或使用其他参数名称。

我建议您将关注点分开。对于您的探索性分析,请在iPython笔记本中编写代码,但当您确定有一些有用的函数时,请打开一个编辑器,将函数放入python文件中,然后导入


您可以使用iPython magics自动重新加载导入的内容。因此,一旦您在iPython中测试了它们,您就可以简单地将它们复制到您的模块中。这样,您的功能范围就与您的笔记本电脑相隔离。另一个优点是,当您准备在无头环境中运行时,您已经将整个代码库放在了一个地方。

最后,我为这个问题制定了自己的解决方案。它建立在迄今为止给出的两个答案的基础上

您可以在github上找到我的解决方案,这是一个cell magic扩展:

简而言之,此扩展使您能够在笔记本中创建%%模块单元。这些单元格保存为文件并导入回会话中。它有效地实现了@shadanan的建议,但允许您将所有工作都放在同一个位置(方便,并且符合在同一位置提供代码和结果的笔记本理念)


因为导入过程会对代码进行沙盒处理,所以它解决了引发我最初问题的所有范围跟踪错误。它还几乎不需要使用任何开销——不需要重命名变量,打开其他编辑器等等。

使用模块,避免使用全局。我非常感谢这些建议。因为我在IPython笔记本上工作,所以您提到的IDE工具不可用。我认为你是正确的,单元测试是一个很好的策略来避免我描述的错误-我会考虑。使用不同的变量名称与我的问题中的示例策略基本相同。预加“389;”可以保持变量用途明确,同时避免与全局命名空间发生冲突;然而,很容易忘记或忽略(导致最初的问题)。重命名所有变量可以避免这种情况,但缺点是,您必须为迄今为止开发的概念提供新名称-已经选择了最明显的名称(在全局名称空间中使用),因此现在您在函数中使用了模糊/一次性名称。