Python中的命名空间和模块

时间:2013-10-10 12:29:46

标签: python namespaces global

另一个给我带来问题的简单问题。

假设我有以下内容:

#!/usr/bin/python 
ref = 30
def f(x):
   print x + ref
f(50)

到目前为止,方便我的目的的一个方面是(我猜) ref 被函数 f 视为全局变量,因此不需要被指定为 f 的参数。

但是,当我想将 f 存储在一个单独的模块中时,我会遇到问题,例如 myfunctions

#!/usr/bin/python 
import myfunctions
ref = 30
myfunctions.f(50)

其中 myfunctions 包含 f 的定义,如上所述。尝试运行时,我得到的NameError是“未定义全局名称'ref'。”

我猜这是因为主模块和'myfunctions'模块有不同的全局命名空间,但有一个很好的方法围绕这个 - 不必包含 ref 作为参数˚F

1 个答案:

答案 0 :(得分:2)

正如您所发现的那样,全局变量不能像那样工作 - 它们也不应该。以下是您可以做的一些事情,但不应该这样做。

myfunctions.py

ref = 30
def f(x):
    print x + ref

our_caller.py

import myfunctions
myfunctions.f(10) # prints 40
myfunctions.ref = 50
myfunctions.f(10) # prints 60

但那么some_other_caller.py呢?

import myfunctions
myfunctions.f(20) # prints 50? prints 70?

这取决于你何时使用myfunctions模块中的全局变量搞砸了。

此外,作为一个思想实验,假设您上面发布的代码确实按预期工作(在某些语言中会有效)。在some_other_caller导入导入myfunctions的our_caller的情况下会发生什么。那么使用哪个参考?它可能更复杂,some_other_caller可以在our_caller中调用一个函数,而函数又调用myfunctions.f - 所以我们使用from_caller中的ref?所以如果some_other_caller直接调用myfunctions,行为可能会有所不同吗?

这不是一个任何人都想住的世界。

更好的方法更像是:

myfunctions.py

def f(x, ref=30):
    print x + ref

our_caller.py

import myfunctions
myfunctions.f(10) # prints 40
myfunctions.f(10, ref=50) # prints 60

然后人们可以看到发生了什么 - 没有奇怪的状态在变化。全球国家真的最好避免。你会一次又一次地听到。在你自己的危险中忽略这个建议(以及后来必须支持你的代码的任何可怜的灵魂)。

编辑:除了您上面关于您的用例的评论之外,看到以下模式的情况并不罕见。

REF = 30
ref_count = 0

def f(x, ref=REF, other_thing=None):
    if not other_thing:
        other_thing = ref_count
    print x + ref + other_thing

def add_ref(current_count=None):
    global ref_count
    if current_count is not None:
        ref_count = current_count
    ref_count += 1

您可以保留全局变量(REF更像是一个全局常量)。当您从外部调用f时,您可以选择为它们提供值或允许它们作为默认值。此外,您可以调用add_ref,为其提供一个新值,以用于模块中的全局副本。

同样,同样的规则适用 - 您已经为模块添加了可以由外部模块实现的全局状态。你需要非常小心谁在改变它,一个更好的架构会试图在第一时间避免这种情况。