编辑:好吧,我几乎把它弄清楚了(尽管它不是我想要的100%,它仍然有效)。这是execfile()
函数,我无法相信我不知道那里有。
我真的不确定如何说出这个问题(这就是我的谷歌搜索几乎没有发现这个问题的原因)......但是这里有。我将简要介绍一下我正在尝试做的事情。我们假设我有两个文件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
,除了导入声明之外顶部,以使此代码工作。)如果这是不可能的,我还会考虑使用不同的导入extra.py
的方法(我正在考虑类似于PHP的include
和{{1其中导入的代码只是被复制并粘贴到文件中的语句),但我非常希望这个修改后的import语句仍然只是一行代码,而且不是很冗长。换句话说,使用文件处理和require
语句可能不会很方便。
说到exec语句,我真的不在乎我使用的编码实践有多糟糕。我真的只需要一种方法来使这个工作,因为这个exec
文件的真实版本是我计划在今后几乎所有项目中使用的东西,我不想占用很多每次导入此文件时,我的代码中有多余的空间。任何帮助将不胜感激。
编辑:似乎很多读这篇文章的人都不清楚我想要完成什么,所以这里是我的代码的真实版本。这是我用来实现“内联变量赋值”的语法黑客。这是代码(如果你不试图将它导入另一个文件,它可以正常工作):
extra.py
语法如下:
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()
代码本身非常严重,但我一直想要一种执行内联变量赋值的方法,因为我是内联if语句,列表推导,lambdas + print use(x = 5, y = 8) >> str(x) + " times " + str(y) + " equals " + str(x*y)
等的忠实粉丝。我不能简单地让函数返回指定的变量,因为reduce()
是一个表达式(不是语句),它返回一个奇怪的对象,然后我使用use(x = 5, y = 8)
运算符将其推入代码中,并且由于我设置>>
函数的方式,use()
函数返回的奇怪对象神奇地消失了。
我认为代码会失去很多美丽和新奇,如果它看起来像这样:
__rshift__()
答案 0 :(得分:1)
首先如何在不修改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
出现,因为use函数不返回任何内容。
注意:如果你为你的用例选择更好的pythonic解决方案会更好,除非你试图用python一点乐趣。
参考python范围规则: Short Description of the Scoping Rules?
答案 1 :(得分:0)
模块具有名称空间,这些名称空间是绑定到对象的变量名称。执行from extra import *
时,可以获取extra
命名空间中找到的对象,并将它们绑定到新模块中的新变量。如果从未调用setfoo
,则extra
没有名为foo
的变量,并且在新模块名称空间中没有任何内容可以绑定。
如果setfoo
被调用,那么from extra import *
就会找到它。但事情仍然很时髦。假设某些作业集extra.foo
为42
。好吧,其他模块命名空间不知道这一点,所以在另一个模块中,foo
仍然是5
但extra.foo
将是42
。
始终牢记对象与可能在任何给定时间引用对象的事物之间的区别。对象不知道哪些变量或容器恰好引用它们(尽管它们确实保留了引用数量的计数)。如果变量或容器被反弹到另一个对象,它不会更改其他变量或容器的绑定。
答案 2 :(得分:0)
在不知道细节的情况下,一种可能的解决方案是在foo
函数中返回extra.py setfoo()
而不是声明为全局变量。
然后在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__
模块就可以从任何其他模块作为全局变量访问它。 1}}。
#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
>>>