导入声明全局变量的函数

时间:2016-10-20 03:44:02

标签: python python-2.7 import global-variables python-import

编辑:好吧,我几乎把它弄清楚了(尽管它不是我想要的100%,它仍然有效)。这是execfile()函数,我无法相信我不知道那里有。

我真的不确定如何说出这个问题(这就是我的谷歌搜索几乎没有发现这个问题的原因)......但是这里有。我将简要介绍一下我正在尝试做的事情。我们假设我有两个文件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,除了导入声明之外顶部,以使此代码工作。)如果这是不可能的,我还会考虑使用不同的导入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__()

3 个答案:

答案 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.foo42。好吧,其他模块命名空间不知道这一点,所以在另一个模块中,foo仍然是5extra.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
>>>