2009-11-03 3 views
4

(Важно: См обновление ниже.)Python: импортировать через функцию основного пространства имен

Я пытаюсь написать функцию, import_something, это будет важно некоторые модули. (Неважно, для чего это относится.) Дело в том, что я хотел бы, чтобы эти модули были импортированы на уровне, из которого вызывается функция. Например:

import_something() # Let's say this imports my_module 
my_module.do_stuff() # 

Возможно ли это?

Update:

К сожалению, моя оригинальная фразировка и пример вводят в заблуждение. Я попытаюсь объяснить всю мою проблему. У меня есть пакет, в котором есть несколько модулей и пакетов. В своем __init__.py я хочу импортировать все модули и пакеты. Поэтому в другом месте программы я импортирую весь пакет и перебираю модули/пакеты, которые он импортировал.

(Почему? Пакет называется crunchers, и внутри нее определяются все виды Crunchers, как CruncherThread, CruncherProcess, и в будущем, возможно, MicroThreadCruncher. Я хочу, чтобы пакет Crunchers автоматически иметь все Crunchers, которые размещаются в нем, так что позже в программе, когда я использую crunchers, я знаю, что он может точно сказать, какие ящики определил.)

Я знаю, что могу решить эту проблему, если я вообще не буду использовать какие-либо функции и сделаю весь импорт на основной уровень с for петлями и т. д. Но это уродливо, и я хочу посмотреть, смогу ли я избежать этого.

Если что-то еще неясно, пожалуйста, спросите в комментариях.

ответ

4

Функции имеют возможность вернуть что-то туда, где они были вызваны. Его называют возвращаемым значением: p

def import_something(): 
    # decide what to import 
    # ... 
    mod = __import__(something) 
    return mod 
my_module = import_something() 
my_module.do_stuff() 

хороший стиль, без хлопот.

Об обновлении, я думаю, добавив что-то вроде этого к вам __init__.py делает то, что вы хотите:

import os 

# make a list of all .py files in the same dir that dont start with _ 
__all__ = installed = [ name for (name,ext) in (os.path.splitext(fn) for fn in os.listdir(os.path.dirname(__file__))) if ext=='.py' and not name.startswith('_') ] 
for name in installed: 
    # import them all 
    __import__(name, globals(), locals()) 

где-нибудь еще:

import crunchers 
crunchers.installed # all names 
crunchers.cruncherA # actual module object, but you can't use it since you don't know the name when you write the code 
# turns out the be pretty much the same as the first solution :p 
mycruncher = getattr(crunchers, crunchers.installed[0]) 
+0

Почему обойти импорта логики интерпретатора? –

+0

@ THC4k: Одна из причин, по которой я использую настраиваемую функцию для импорта, заключается в том, что я не знаю имя модуля, который я импортирую, и хочу, чтобы он был импортирован под своим именем. –

+0

Например, если вы хотите решить, какой механизм шаблонов (mako/cheetah/etc) использовать во время выполнения, вам понадобится '__import__'. –

0

Согласно помощи __import__ «s:

__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module 

Import a module. The globals are only used to determine the context; 
they are not modified. ... 

Таким образом, вы можете просто получить глобалы родительского фрейма и использовать его для звонок __import__.

def import_something(s): 
    return __import__(s, sys._getframe(1).f_globals) 

Примечание: Pre-2,6, подпись __import__ «s отличался тем, что он просто имел дополнительные параметры вместо использования kwargs. Поскольку globals является вторым аргументом в обоих случаях, то, как он называется, работает отлично. Только что нужно знать, если вы решили использовать любой из других аргументов.

+1

Вы все еще просто возвращаете модуль, и я думаю, что OP хочет нечто более магическое, чем это. (Так как в противном случае вы могли бы просто вызвать __import__ напрямую, а не обернуть его). –

1

Вы можете обезьяна с родительским фреймом в CPython для установки модулей в локали для этого фрейма (и только для этого фрейма). Недостатком является то, что a) это действительно довольно хакерское и b) sys._getframe() не гарантируется в других реализациях python.

def importer(): 
    f = sys._getframe(1) # Get the parent frame 
    f.f_locals["some_name"] = __import__(module_name, f.f_globals, f.f_locals) 

Вы все еще должны установить модуль в f_locals, поскольку импорт не будет на самом деле сделать это для вас - вы просто поставить родительский фрейм местных жителей и глобалам для надлежащего контекста.

Затем в вызывающей функции вы можете:

def foo(): 
    importer() # Magically makes 'some_name' available to the calling function 
    some_name.some_func() 
1

Вы ищете что-то вроде этого?

def my_import(*names): 
    for name in names: 
     sys._getframe(1).f_locals[name] = __import__(name) 

, то вы можете назвать это так:

my_import("os", "re") 

или

namelist = ["os", "re"] 
my_import(*namelist) 
+0

Будет ли 'globals' импортировать его на один уровень или на верхний уровень? Он должен быть только на одном уровне, поэтому он будет вести себя как оператор 'import'. –

+0

Вы правы, я изменил код соответственно. Ну, глядя на другие решения, теперь это похоже на то, что jamessan и Nick уже опубликовали некоторое время назад. – RedGlyph

+0

(How) Могу ли я использовать это для дублирования операторов импорта, например: «от модуля import fun как F» и «import mod.submod as S»? – David

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