2013-10-10 83 views
0

另一个给我提出问题的简单问题。Python中的名称空间和模块

假设我有以下几点:

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

一方面这是方便我的目的,迄今为止的是,(我想)裁判作为一个全局变量处理由函数˚F,等等不需要被指定为f的参数。

不过,我得到的问题时,我想存储˚F在一个单独的模块,说myfunctions

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

其中myfunctions包含如上˚F定义。当试图运行这个时,我得到NameError,“全局名称ref'没有被定义。”

我猜测,这是因为主模块和“myfunctions”模块有不同的全局命名空间,但有一个很好的办法解决这 - 而不一定必须包括裁判˚F的说法?

+4

但是,为什么你不显式传递变量作为函数的参数?显式通常比隐式更好(并且更清晰)... –

+0

问题不在于'myfunctions' *模块*具有不同的全局名称空间。问题是*函数*'f'具有不同的全局名称空间,它是'myfunctions'模块的'__dict__'。检查“f.func_globals”属性与“myfunctions .__ dict__”相同。这是非常明智的,否则每次使用函数时都必须知道它们所需的所有全局变量。这可能意味着你有*阅读源代码,或者所有功能的文档都会很长。 – Bakuriu

+0

谢谢大家 - 在我的情况下,问题是f实际上是一个相当长的函数,使用大约20个来自主命名空间的变量 - 只要在主模块中定义了f,我就可以避免(繁琐的)列表任务所有这些都是论据。这是否意味着如果在单独的模块中定义了f,则无法做到这一点? – user2383521

回答

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的情况下会发生什么情况。那么使用哪个ref?它可能更复杂一些,some_other_caller可以在our_caller中调用函数,然后调用myfunctions.f - 所以我们使用our_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,为其提供一个新值以用于模块中的全局副本。

同样,同样的规则适用 - 您已将全局状态添加到您的模块,这可能受外部模块影响。你需要非常小心谁在改变它,一个更好的架构会首先尝试避免这种情况。

相关问题