2010-06-29 3 views
8

Этот фрагмент из более раннего ответа здесь, на SO. Это около года (и ответ не был принят). Я новичок в Python, и я нахожу системный путь настоящей болью. У меня есть несколько функций, написанных в сценариях в разных каталогах, и я хотел бы иметь возможность импортировать их в новые проекты, не перепрыгивая через обручи.Это правильный способ импорта скриптов python, находящихся в произвольных папках?

Это фрагмент кода:

def import_path(fullpath): 
""" Import a file with full path specification. Allows one to 
    import from anywhere, something __import__ does not do. 
""" 
path, filename = os.path.split(fullpath) 
filename, ext = os.path.splitext(filename) 
sys.path.append(path) 
module = __import__(filename) 
reload(module) # Might be out of date 
del sys.path[-1] 
return module 

Его отсюда: How to do relative imports in Python?

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

я намерен использовать это что-то вроде этого:

import_path(/home/pydev/path1/script1.py) 

script1.func1() 

и т.д.

Является ли это безопасно ", чтобы использовать функцию в пути я намереваюсь?

ответ

8

«Официальный» и полностью безопасный подход - это модуль стандартной библиотеки Python imp.

Использование imp.find_module найти модуль на вашем точно оговоренном список допустимых каталогов - она ​​возвращает 3-кортеж (file, pathname, description) - в случае неудачи, file на самом деле None (но она может также повысить ImportError, так что вы должны использовать try/except для этого, а также проверка if file is None:).

Если поиск успешен, звоните imp.load_moduletry/finally, чтобы убедиться, что вы закроете файл!) С указанными выше тремя аргументами после первого, который должен быть одинаковым name вы прошли в find_module - она ​​возвращает объект модуля (phew ;-).

+0

В версии 3.3 имп устарел в пользу importlib. Тем не менее, в 3.2, похоже, нет никакого эквивалентного использования importlib, поэтому, если вам нужно работать в обеих средах, спасите себя головной болью и придерживайтесь imp. – Yourpalal

0

Это действительно немного взломанно, но на данный момент я не могу думать о каких-либо непредвиденных побочных эффектах, которые могут произойти, по крайней мере, до тех пор, пока вы просто используете это для своих собственных скрипты. В основном, это временное добавление родительского каталога указанного файла (в вашем примере, /home/pydev/path1/) в список путей, которые Python проверяет, когда он ищет импортируемый модуль.

Единственный риск, который я могу сейчас подумать, возникнет в многопоточной среде, где одновременно работают две или несколько потоков (или процессов). Если нить A хочет импортировать модуль A с пути dirA/A.py, а нить B хочет импортировать модуль B с пути dirB/B.py, вы бы натолкнулись на dirA и dirB в sys.path на короткое время. И если есть файл с именем B.py в dirA, возможно, что поток B найдет, что (dirA/B.py) вместо файла, который он ищет (dirB/B.py), тем самым импортируя неправильный модуль. По этой причине я бы не использовал его в производственном коде или код, который вы собираетесь распространять другим людям (по крайней мере, не предупредив их, что этот хак здесь!). В подобной ситуации вы можете написать более сложную функцию, которая позволяет указать файл для импорта без использования стандартного набора путей. (Например, это делает mod_python)

0

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

0

Как уже упоминалось, обратите внимание на безопасность потоков, если это необходимо. Я предпочитаю что-то ближе к решению, размещенному в аналогичной должности. Основные отличия ниже: использование вставки для указания приоритета импорта, правильное восстановление sys.path с использованием try ... наконец, и установка глобального пространства имен.

# inspired by Alex Martelli's solution to 
# http://stackoverflow.com/questions/1096216/override-namespace-in-python/1096247#1096247 
def import_from_absolute_path(fullpath, global_name=None): 
    """Dynamic script import using full path.""" 
    import os 
    import sys 

    script_dir, filename = os.path.split(fullpath) 
    script, ext = os.path.splitext(filename) 

    sys.path.insert(0, script_dir) 
    try: 
     module = __import__(script) 
     if global_name is None: 
      global_name = script 
     globals()[global_name] = module 
     sys.modules[global_name] = module 
    finally: 
     del sys.path[0] 
Смежные вопросы