导入声明全局变量的函数

Importing functions that declare global variables

编辑: 好吧,我差不多明白了(虽然它不是我想要的 100%,但它仍然有效)。这是 execfile() 函数,我不敢相信我不知道它在那里。

我不太确定如何表达这个问题(这就是我的 Google 搜索在这方面几乎没有任何结果的原因)......但现在开始了。我将给出我正在尝试做的事情的简化版本。假设我有两个文件,main.pyextra.py。后者看起来像这样:

# extra.py

def setfoo(): # sets "foo" to 5 even if it is unassigned
    global foo
    foo = 5

如果我在控制台中 运行 这非常简单:

>>> setfoo()
>>> foo
5

现在让我们回到 main.py。我将设置一个导入语句,从 extra.py:

导入所有内容
# main.py

from extra import *

setfoo()
print foo

直到最后一行,一切正常;但是,当 main.py 尝试访问 foo 时,它无法识别它,因为 foo 实际上存储在文件 extra.py 下。如果我在 运行 setfoo() 之后再次导入所有内容,将导入 foo 并且一切正常。像这样:

# main.py

from extra import *

setfoo()
from extra import *
print foo

或者,如果我使用标准 import 语句而不是 from...import 语句,则无需重新导入所有内容,因为来自 extra.py 的数据是直接访问的,而不是比复制过来。所以这也适用:

# main.py

import extra

extra.setfoo()
print extra.foo

但是,我真的不想每次都输入extra.setfoo() 运行 setfoo(),也不想重新输入extra.py每次我使用上述功能。我想知道是否有解决方法。理想情况下,应该有一种方法可以修改 extra.py 以便我在 main.py 的原始版本中设置的代码可以正常工作。 (编辑: 似乎很多人都误解了这一点——我愿意修改 extra.py,我不想改变的是 main.py,除了import 语句在顶部,让这段代码工作。)如果这不可能,我也会考虑使用不同的导入方法 extra.py (我在想类似于 PHP 的方法includerequire 语句,其中导入的代码实际上只是复制并粘贴到文件中),但我非常希望这个修改后的导入语句仍然只是一行代码,而且不是很冗长。所以换句话说,使用文件处理加上 exec 语句可能不会很方便用于此目的。

说到 exec 语句,我真的一点都不在乎我使用的编码实践有多糟糕。我真的只需要一种方法来让它工作,因为这个 extra.py 文件的真实版本是我计划从现在开始在几乎所有项目中使用的东西,我不想占用太多每次导入此文件时,我的代码中都会有额外的 space。任何帮助将不胜感激。

编辑: 似乎很多阅读这篇文章的人都不太清楚我要完成什么,所以这是我的代码的真实版本。这是我为实现 "inline variable assignment" 而组合的语法 hack。这是代码(如果您不尝试将其导入另一个文件,它可以正常工作):

class use_obj(object):
    def __rshift__(self, other): return other

def use(**kwargs):
    for var in kwargs: exec 'global ' + var + '; ' + var + ' = kwargs[var]'
    return use_obj()

语法如下所示:

print use(x = 5, y = 8) >> str(x) + " times " + str(y) + " equals " + str(x*y)

代码本身很粗糙,但我一直想要一种方法来执行内联变量赋值,因为我非常喜欢内联 if 语句、列表理解、lambdas + reduce() 等。我不能简单地使用函数 return 分配变量的原因是因为 use(x = 5, y = 8) 是一个表达式(而不是语句),return 是一个奇怪的对象,然后我将它推入代码中使用>> 运算符,以及 use() 函数 return 编辑的奇怪对象由于我设置 __rshift__() 函数的方式而神奇地消失了。

我认为如果代码看起来像这样,它会失去很多美感和新颖性:

print use(x = 5, y = 8) >> str(extras.x) + " times " + str(extras.y) + " equals " + str(extras.x*extras.y)

模块具有命名空间,这些命名空间是绑定到对象的变量名。当您执行 from extra import * 时,您获取在 extra 的命名空间中找到的对象并将它们绑定到新模块中的新变量。如果从未调用过 setfoo,则 extra 没有名为 foo 的变量,并且在新模块命名空间中没有任何内容可以绑定。

如果 setfoo 被调用,那么 from extra import * 就会找到它。但事情仍然很奇怪。假设一些赋值集 extra.foo42。好吧,另一个模块命名空间不知道这一点,所以在另一个模块中,foo 仍然是 5extra.foo 将是 42.

始终牢记对象与在任何给定时间可能引用该对象的事物之间的区别。对象不知道哪些变量或容器碰巧引用了它们(尽管它们确实对引用的数量进行了计数)。如果一个变量或容器被重新绑定到一个不同的对象,它不会改变其他变量或容器的绑定。

在不知道细节的情况下,一种可能的解决方案是在 extra.py setfoo() 函数中 return foo 而不是声明为全局变量。

然后在 main.py 中声明全局 foo 并从外部函数中输入值 setfoo()

这是设置

#extra.py

def setfoo(): # sets "foo" to 5 even if it is unassigned
    #global foo
    foo = 5
    return foo

#main.py

from extra import setfoo

global foo

foo = setfoo()
print foo

结果:

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
5
>>> 

编辑 - 1
好的,在这个问题上采取-2。

我不赞同,但如果有特定需要,如果您将变量添加到 __builtin__ 模块,只要它包含,它就可以作为全局变量从任何其他模块访问__builtin__.

#extra.py

import __builtin__

def setfoo(): # sets "foo" to 5 even if it is unassigned
    global foo
    __builtin__.foo = 5


#main.py

from extra import *
setfoo()
print foo

输出:

>>> 
5
>>> 

首先,如何在不修改的情况下导入变量 extra.py,如果真的想要的话, 您必须借助 sys 模块才能在额外模块中获取对 foo 的引用。

import sys
from extra import *

print('1. Foo in globals ? {0}'.format('foo' in globals()))
setfoo()
print('2. Foo in globals ? {0}'.format('foo' in globals()))
# Check if extra has foo in it
print('2. Foo in extra ? {0}'.format(hasattr(sys.modules['extra'], 'foo')))
# Getting foo explicitly from extra module
foo = sys.modules['extra'].foo
print('3. Foo in globals ? {0}'.format('foo' in globals()))
print("Foo={0}".format(foo))

输出:

1. Foo in globals ? False
2. Foo in globals ? False
2. Foo in extra ? True
3. Foo in globals ? True
Foo=5

更新后的用例: 修改获取导入器并更新其全局变量的 extra.py,

# extra.py
import sys

def use(**kwargs):
    _mod = sys.modules['__main__']
    for k, v in kwargs.items():
        setattr(_mod, k, v)

现在导入任何文件都保持不变,

#myfile.py
from extra import *
print use(x = 5, y = 8), str(x) + " times " + str(y) + " equals " + str(x*y)

输出:

None 5 times 8 equals 40

None 显示为使用函数 returns 没有。

注意:如果你为你的用例选择更好的 pythonic 解决方案会更好,除非你想从 python.

中找点乐子

参考python范围规则: Short Description of the Scoping Rules?