Python __import__参数混乱

时间:2010-05-30 18:45:25

标签: python import global

我正在尝试导入一个模块,同时传递一些全局变量,但它似乎不起作用:

文件test_1:

test_2 = __import__("test_2", {"testvar": 1})

文件test_2:

print testvar

这似乎应该可行,并打印1,但是当我运行test_1时出现以下错误:

Traceback (most recent call last):
  File ".../test_1.py", line 1, in <module>
    print testvar
NameError: name 'testvar' is not defined

我做错了什么?

修改

正如我稍后评论的那样,这是尝试替换图形库中的函数。这是一个使用该库的示例程序(我的老师写的):

from graphics import *
makeGraphicsWindow(800, 600)

############################################################
# this function is called once to initialize your new world

def startWorld(world):
    world.ballX = 50
    world.ballY = 300
    return world

############################################################
# this function is called every frame to update your world

def updateWorld(world):
     world.ballX = world.ballX + 3
     return world

############################################################
# this function is called every frame to draw your world

def drawWorld(world):
    fillCircle(world.ballX, world.ballY, 50, "red")

############################################################

runGraphics(startWorld, updateWorld, drawWorld)

请注意,此代码的设计使得之前(或几乎从未)看过任何代码的人(不仅仅是python)能够轻松理解。

重写函数的示例:

原始代码:

def drawPoint(x, y, color=GLI.foreground):
    GLI.screen.set_at((int(x),int(y)), lookupColor(color))

注入的代码:

# Where self is a window (class I created) instance.
def drawPoint(x, y, color = self.foreground):
  self.surface.set_at((int(x), int(y)), lookupColor(color))

我想我真正的问题是:在模块运行之前,如何将全局函数/变量注入导入的模块中??

6 个答案:

答案 0 :(得分:7)

正如the docs解释的那样,globals __import__参数向 “注入”额外的全局变量到导入的模块中,正如您所认为的那样 - 实际上,通常传递的是导入模块的globals(),因此如果发生这样的注入会很成问题。的确,__import__的文档具体说:

  

标准实施没有   完全使用它的locals参数,和   仅使用其全局变量来确定   导入的包上下文   言。

修改:如果您确实需要注射,例如进入一个空的导入模块,正如OP在评论中建议的那样,只要你在强导入后就可以了,这很容易:

themod = __import__(themodname)
themod.__dict__.update(thedict)

导入的模块的身体将不会注意到仍然发生的注射,但无论如何,这显然无论身体是否为空;-)。在导入之后,您可以注入您心中的内容,并且该模块的所有后续使用都会看到您的注射,就好像它们是真正的模块级绑定名称一样(因为它们是< / em>的; - 。)

如果你愿意的话,你甚至可以节省空的.py模块的开头......:

import new, sys
themod = new.module(themodname)
sys.modules[themodname] = themod
themod.__dict__.update(thedict)

编辑:OP尝试在Q的编辑中澄清...:

  

我想我真正的问题是:怎么会   我注入全局函数/变量   进入之前的导入模块   模块运行......?

“模块运行”没有多大意义 - 模块被加载(执行它们的主体),只需一次(除非重新 - 稍后明确加载)......它们永远不会“运行” “本身。给定一个空模块,首先导入它(由于模块为空,因此不执行任何操作),如果您希望使用themodule.__dict__.update和属性赋值的混合来填充模块,则可以使用 < / strong>刚刚提到时自动调用(因为OP表示担心他们会在评论中),所以他们可以被视为在这方面的任何其他变量(和大多数其他变量,这就是为什么Python说第一类功能)。

答案 1 :(得分:3)

我遇到了同样的问题...... 我用下面的技巧说服了自己...... 我不知道这对你有用还是有用的!

File2:test1.py

global myvar
myvar = "some initial value"
print myvar
test = __import__("test2")
print myvar

File2:test2.py

import inspect
stk = inspect.stack()[1]
myvar = inspect.getmodule(frm[0]).myvar
print myvar
myvar = "i am changing its value."

此变量从module1传递到module2 它也是通过引用传递的。

答案 2 :(得分:2)

如上所述,__import__函数不会将全局变量添加到新模块中。如果你想这样做,我建议添加一些initialize()函数,为预先声明的全局表赋值,如下所示:

gTable = {}
gInited = False

def initialize(table):
    if(not gInited):
        gTable = table
        gInited = True

def getGlobal(name):
    if(name in gTable):
        return gTable[name]
    else:
        throw NameError("name '"+name+"' is not defined")

def setGlobal(name, value):
    gTable[name] = value

def mod_main():
    print getGlobal("testvar")

并像这样导入:

import modGlobalsTest
modGlobalsTest.initialize({"testvar": 1})
modGlobalsTest.mod_main()

如果要更改导入库中的功能,可以执行以下操作:

import foobar
def bar(x):
    return x+1
foobar.foo = bar

用自定义功能栏替换foobar.foo。

答案 3 :(得分:0)

你太努力了,你只需要简单的进口 在一个模块中定义变量,比如test1

testvar = 1

在test2中

import test1
print test1.testvar

答案 4 :(得分:0)

看起来您想要将代码注入图形库并使用它运行示例程序。如果是这样,你可以这样做:

import graphics
graphics.drawPoint = myDrawPoint

您还可以编写一个程序,将示例的文件名作为参数并执行:

import sys
import graphics

def main():
    graphics.drawPoint = myDrawPoint
    execfile(sys.argv[1])

答案 5 :(得分:0)

当我需要在加载时将全局变量传递给模块(这经常是), 我只需创建一个新的ModuleType,将全局变量注入其命名空间,最后在该命名空间中执行我的源模块。

这是我的基本子模块导入代码:
(对于包,您需要__package____path__全局变量)

# such a headache to initialize a module requiring globals >_<
import sys,os, types.ModuleType as ModuleType
globals()['nodes'] = sys.modules['nodes'] = ModuleType('nodes') # set the namespace
nodes.__dict__.update(dict(
    __name__ = 'nodes',
    __file__ = __file__.replace(__name__,'nodes'),
    # the globals I need in particular
    GL = GL, # prevents a ghost (duplicate) import
    drawText = drawText,
    lenText = lenText ))
with open('nodes.py','rb') as src: exec( src.read(), nodes.__dict__ )

我不能只是import nodes或者我会得到一个NameError,因为lenText用于构建该模块中节点类的命中定义。

小贴士:在使用它时要小心!
对于我的情况,lenText对每个字符的显示列表引用进行操作,因此我需要在准备GL上下文后专门导入。