2010-05-30 3 views
6

Я пытаюсь импортировать модуль, проходя некоторые глобальные переменные, но это не похоже на работу:Python __import__ параметр спутанность

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 

Что я делаю неправильно?

EDIT:

Как я заметил позже, это попытка заменить функции в библиотеке графики. Вот пример программа (что мой учитель написал) с помощью этой библиотеки:

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) 

Обратите внимание, что этот код разработан таким образом, чтобы люди, которые никогда (или почти никогда) видели какую-либо коду до (а не только питона) будет способный понять с минимальными усилиями.

Пример для перезаписи функции:

Оригинальный код:

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)) 

Я думаю, мой вопрос: как бы я впрыснуть глобальные функции/переменные в импортированный модуль перед запуском модуля ...?

+0

Является ли библиотека, запускающая код инициализации сразу после ее импорта, или вам нужно запустить makeGraphicsWindow(), прежде чем что-либо сделать? – computergeek6

+0

Он запускает некоторый код инициализации сразу после его импорта и запускает еще несколько при вызове makeGraphicsWindow. – skeggse

+0

Итак, вы намерены превратить код в своего учителя, который экзогенно изменяет свой модуль, для которого вы «не можете изменить код в модуле, который я импортирую»? Я думаю, возможно, что она будет впечатлена, но я предполагаю, что это не самый вероятный ответ. – msw

ответ

3

Я столкнулся с теми же проблема ... И я убедил себя следующей техникой ... Я donno whtr это будет полезно для вас или нет!

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 и что тоже передается по ссылке.

+0

Несмотря на то, что я с тех пор перешел, это, вероятно, лучший ответ, характерный для моего дела. Конечно, это потребует определения многочисленных функций как глобальных, и будет загромождать глобальное пространство имен, но тем не менее ... – skeggse

0

Вы пытаетесь слишком трудно вам просто нужно простой импорт Определить переменную в одном модуле, скажем test1

testvar = 1 

в test2 поставил

import test1 
print test1.testvar 
+0

Одна проблема: test2 должен оставаться как есть; Я не контролирую его, и у меня нет дополнительной строки кода. Кроме того, мне нужно импортировать его из test1. – skeggse

7

Как the docs объяснить, то globals параметр __import__ делает не «вводит» дополнительные глобалы в импортированный модуль, как вы, кажется, верите - действительно, что обычно проходит, есть globals(), импортируя модуль, поэтому такая инъекция была бы очень проблематичной, если бы это произошло. Действительно, документы __import__ «s определенно сказать:

Стандартной реализация не использовать его местные житель аргумента вообще и использует его Глобал только определить контекст пакета ввозной заявления.

Редактировать: если вам нужна инъекция, например.в пустой импортируемого модуля, как ОП предложил в комментарии, что это легко, если вы хорошо с делать это сразу после импорта:

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

тело импортируемого модуля не будет знать о еще инъекции, но это явно неважно, если тело все равно пусто ;-). Правильно после импорта вы можете вводить содержимое вашего сердца, и все последующие его применения будут видеть ваши инъекции, как если бы они были добросовестными именами на уровне модуля (потому что они - ;-).

Вы могли бы даже, если угодно, за исключением необходимости для пустого .py модуля, чтобы начать с ...:

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

Edit: ОП пытается прояснить в правке на Q. ..:

Я предполагаю, что мой реальный вопрос: как бы я впрыснуть глобальные функции/переменные в импортируемом модуль перед запуском модуля ...?

«Модуль работает» не имеет особого смысла - модули загружаются (который выполняет свое тело), ​​только один раз (если не повторно -loaded явно позже) ... они никогда не «бежать» за как таковые. Учитывая пустой модуль, вы сначала импортируете его (который ничего не выполняет с момента пустого модуля), тогда вы можете, если хотите, использовать сочетание themodule.__dict__.update и присвоение атрибута для заполнения модуля - функции: не автоматически вызывается, когда только что упоминалось (поскольку OP выражает опасения, что они будут в комментарии), поэтому к ним можно относиться так же, как к любой другой переменной в этом отношении (и к большинству других, поэтому Python имеет функции первого класса).

+0

Это помогает, но как это сделать? – skeggse

+1

Я подозреваю, что это может помочь объяснить на более высоких уровнях то, что вы пытаетесь сделать. – Mark

+0

Хорошо. Я пытаюсь заменить модуль, написанный моим учителем, так что файл, который обычно будет импортироваться, пуст, и я предоставляю функции, специфичные для среды, для их замены, но при этом позволяя программе работать. Более конкретно, он написал графическую библиотеку (дублированный graphics.py), и я пытаюсь создать систему искусственных окон, которая имеет те же функции, что и его библиотека. EDIT: эта библиотека «упрощает» PyGame. – skeggse

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 с пользовательской функцией баром.

+0

Это не сработало: поскольку я уже прокомментировал другое сообщение, я не могу изменить код в модуле, который я импортирую. – skeggse

+0

Вовлечение EDIT: Это сработает, за исключением того, что к этому моменту я уже достиг NameError с помощью runGraphics. – skeggse

0

Похоже, вы хотите ввести код в графическую библиотеку и запустить примеры программ, используя это. Если это так, то вы можете сделать это следующим образом:

import graphics 
graphics.drawPoint = myDrawPoint 

Вы также можете написать программу, которая принимает имя файла, например в качестве аргумента и выполняет следующее:

import sys 
import graphics 

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

, когда мне нужно передать глобал к модулю на нагрузке (что довольно часто), я просто просто создать новый ModuleType, впрыснуть глобал, в этом пространстве имен, и, наконец, EXEC моего исходного модуля в этом пространстве имен.

Вот мой код для базового импорта суб-модуля:
(для пакета, вы будете нуждаться в __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 или я получу a NameError, потому что lenText используется при построении определений хитов классов узлов в этом модуле.

Советы: будьте осторожны, когда вы используете это!
Для моего случая lenText работает с ссылкой на список отображения каждого символа, поэтому мне нужно импортировать его непосредственно после подготовки моего контекста GL.

Смежные вопросы