2013-02-28 2 views
2

У меня есть локальный модуль с именем tokenize.py, который маскирует стандартный библиотечный модуль с тем же именем. Я только обнаружил это, когда пытался импортировать внешний модуль (sklearn.linear_model), который, в свою очередь, import tokenize и ожидает получить стандартный библиотечный модуль, но вместо этого получит мой локальный модуль.Как импортировать внешний модуль, когда локальный модуль маскирует стандартный библиотечный модуль, импортированный внешним модулем?

Это связано с How to access a standard-library module in Python when there is a local module with the same name?, но настройка отличается, потому что для применения вышеуказанного решения потребуется изменить внешний модуль.

Опцией было бы переименовать локальный tokenize.py, но я бы предпочел не делать этого, так как «tokenize» лучше всего выражает роль модуля.

Чтобы проиллюстрировать эту проблему, вот эскиз конструкции модуля:

 
    \my_module 
     \__init__.py 
     \tokenize.py 
     \use_tokenize.py 

В use_tokenize.py, есть следующий импорт:

import sklearn.linear_model 

что приводит к следующей ошибке, когда ссылаясь на python my_module/use_tokenize.py:

Traceback (most recent call last): 
    File "use_tokenize.py", line 1, in <module> 
    import sklearn.linear_model 
    <...> 
    File "<EDITED>/lib/python2.7/site-packages/sklearn/externals/joblib/format_stack.py", line 35, in <module> 
    generate_tokens = tokenize.tokenize 
AttributeError: 'module' object has no attribute 'tokenize' 

есть ли способ подавить местную ПБУ les при импорте внешнего модуля?

изменения: Добавлена ​​python2.7 как тег из-за комментариев, что решение зависит от версии Python

+0

Какую версию Python вы используете? Правила и обходные пути разные. – abarnert

+2

Но действительно, вы должны переименовать свой локальный 'tokenize.py'. Скрипт, который автоматически фиксирует все «импорт tokenize» и «tokenize.» во всех ваших сотнях скриптов и модулей, должен занять несколько минут для записи и несколько секунд для запуска ... – abarnert

+0

Если вы создадите модуль с тем же именем как стандартный библиотечный модуль, никто не может установить вашу библиотеку без маскировки стандартного модуля lib. Решение состоит в том, чтобы не дать вашему модулю это имя. (У вас все равно есть 'tokenize.py', если он является частью пакета, потому что в этом случае простой' import tokenize' его не увидит.) – BrenBarn

ответ

3

Проблема не столько имя модуля, но вы работаете модуль как это было a сценарий. Когда Python запускает скрипт, он добавляет директорию, содержащую скрипт, в качестве первого элемента в sys.path, поэтому все поисковые запросы модуля из любого места будут сначала искать этот каталог.

Чтобы избежать этого, попросите Python, чтобы выполнить его как модуль вместо:

python -m my_module.use_tokenize 

Или, конечно, вы можете просто сохранить исполняемые скрипты из иерархии модулей.

0

Пути, в которых интерпретатор ищет модули, перечислены в sys.path. Чтобы модуль стороннего модуля не видел локальный модуль при импорте, удалим . с пути. Это может быть достигнуто за счет:

import sys 
sys.path = sys.path[1:] 
import sklearn.linear_model #using the original example. 

Однако, это не будет работать, если локальная tokenize уже импортирован, и это также будет препятствовать местной tokenize от импортируемого, даже если мы восстанавливаем старую sys.path следующим образом:

import sys 
old_path = sys.path 
sys.path = sys.path[1:] 
import sklearn.linear_model #using the original example. 
sys.path = old_path 

Это происходит потому, что интерпретатор Python поддерживает внутреннее отображение импортируемых модулей, так что последующие запросы на ту же модулу, выполнены из этого отображения. Это сопоставление является глобальным для интерпретатора, поэтому import tokenize возвращает тот же модуль из любого кода, который его запускает - это именно то поведение, которое мы пытаемся изменить. Для этого нам нужно изменить это отображение. Самый простой способ сделать это - просто удалить соответствующую запись с sys.modules.

import sys 
old_path = sys.path 
sys.path = sys.path[1:] 
import sklearn.linear_model #using the original example. 
sys.path = old_path 
del sys.modules['tokenize'] #get of the mapping to the standard library tokenize 
import tokenize #cause our local tokenize to be imported  
Смежные вопросы