Путаница в параметрах Python - PullRequest
7 голосов
/ 30 мая 2010

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

Файл 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)

Обратите внимание, что этот код разработан таким образом, что люди, которые никогда (или почти никогда) не видели НИКАКОГО кода раньше (не только 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 ]

7 голосов
/ 30 мая 2010

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

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

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

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

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

Вы можете даже, если хотите, сохранить необходимость в пустом модуле .py, чтобы начать с ...:

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

Редактировать : ОП пытается уточнить при редактировании Q ...:

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

"Модуль работает" не имеет особого смысла - модули загружаются (что выполняет их тело), ​​только один раз (если re не загружен явно позже) ... они никогда не "запускаются" как таковой. Имея пустой модуль, вы сначала импортируете его (который ничего не выполняет, поскольку модуль пуст), затем вы можете, если хотите, использовать сочетание themodule.__dict__.update и присвоение атрибута для заполнения модуля - функции не автоматически вызывается, когда только что упоминается (поскольку ОП выражает опасения, что они будут в комментарии), поэтому они могут рассматриваться как любая другая переменная в этом отношении (и большинство других, именно поэтому в Python сказано, что первый класс *) 1048 * функций).

3 голосов
/ 29 февраля 2012

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

Файл2: test1.py

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

Файл2: test2.py

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

Здесь переменная передается из модуля1 в модуль2 и это тоже передается по ссылке.

2 голосов
/ 30 мая 2010

Как уже говорилось, функция __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 голосов
/ 14 марта 2017

когда мне нужно передать глобальные переменные модулю при загрузке (что довольно часто), Я просто создаю новый 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.

0 голосов
/ 31 мая 2010

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

import graphics
graphics.drawPoint = myDrawPoint

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

import sys
import graphics

def main():
    graphics.drawPoint = myDrawPoint
    execfile(sys.argv[1])
0 голосов
/ 30 мая 2010

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

testvar = 1

в test2 положить

import test1
print test1.testvar
...