导入声明全局变量的函数
Importing functions that declare global variables
编辑: 好吧,我差不多明白了(虽然它不是我想要的 100%,但它仍然有效)。这是 execfile()
函数,我不敢相信我不知道它在那里。
我不太确定如何表达这个问题(这就是我的 Google 搜索在这方面几乎没有任何结果的原因)......但现在开始了。我将给出我正在尝试做的事情的简化版本。假设我有两个文件,main.py
和 extra.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 的方法include
和 require
语句,其中导入的代码实际上只是复制并粘贴到文件中),但我非常希望这个修改后的导入语句仍然只是一行代码,而且不是很冗长。所以换句话说,使用文件处理加上 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.foo
到 42
。好吧,另一个模块命名空间不知道这一点,所以在另一个模块中,foo
仍然是 5
但 extra.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?
编辑: 好吧,我差不多明白了(虽然它不是我想要的 100%,但它仍然有效)。这是 execfile()
函数,我不敢相信我不知道它在那里。
我不太确定如何表达这个问题(这就是我的 Google 搜索在这方面几乎没有任何结果的原因)......但现在开始了。我将给出我正在尝试做的事情的简化版本。假设我有两个文件,main.py
和 extra.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 的方法include
和 require
语句,其中导入的代码实际上只是复制并粘贴到文件中),但我非常希望这个修改后的导入语句仍然只是一行代码,而且不是很冗长。所以换句话说,使用文件处理加上 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.foo
到 42
。好吧,另一个模块命名空间不知道这一点,所以在另一个模块中,foo
仍然是 5
但 extra.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?