Импорт Python переопределяется стандартной библиотекой (Python 2.4) - PullRequest
6 голосов
/ 19 декабря 2011

У меня есть пакет python, который я пишу, и у меня возникла проблема, когда из-за конфликта имен импортируется стандартная библиотека вместо моих файлов.

Например, структура файла, как показано ниже:

package/__init__.py

# No data in this file

package / module.py

#!/usr/bin/env python
print 'Loading module.py'
import signal

package / signal.py

#!/usr/bin/env python
print 'Loading signal.py'

Я получаюследующие результаты, когда я запускаю это:

$ ./module.py
Loading module.py

Я хотел бы получить:

$ ./module.py
Loading module.py
Loading signal.py

Фактический вопрос:

Итак, когда я запускаю модуль.py , это import signal идет к версии stdlib.Как я могу заставить module.py импортировать signal.py вместо этого?

Как отмечено в тегах, это должно быть в состоянии работать на python-2.4.3.Хотя это старая версия, это то, что включено в RHEL 5.


Некоторая дополнительная информация

Просто для большей информации, у меня явно есть следующая настройка:

[10:30pm][~/test] tree .
.
|-- package
|   |-- __init__.py
|   |-- module.py
|   `-- signal.py
`-- script

[10:30pm][~/test] cat script
#!/usr/bin/env python
from package import signal

[10:30pm][~/test] cat package/__init__.py

[10:30pm][~/test] cat package/module.py 
#!/usr/bin/env python
print "Loading module.py"
import signal

[10:30pm][~/test] cat package/signal.py 
#!/usr/bin/env python
print "Loading signal.py"

[10:30pm][~/test] python ./script
Loading signal.py

[10:32pm][~/test] python ./package/module.py 
Loading module.py

[10:32pm][~/test] python -m package.module
python: module package.module not found

Обратите внимание, что, когда я запустил . / Package / module.py , оператор print в . / Package / signal.py не был запущен.Это означает, что сигнал, который был загружен, является сигналом от stdlib.

Ответы [ 3 ]

6 голосов
/ 19 декабря 2011

Проблема в этом случае заключается в том, что встроенный модуль signal импортируется как часть процесса запуска интерпретатора. Таким образом, к моменту запуска вашего кода в module.py в sys.modules уже есть запись в *1005* с именем signal со встроенным модулем в качестве значения. Поскольку sys.modules - это первое место, которое смотрит оператор import, он вернет этот встроенный модуль и остановится на этом. Даже не стоит искать свой собственный signal.py.

Я могу придумать три решения:

  1. Переименуйте ваш модуль. Это самое простое решение. Вам не нужно беспокоиться о конфликтах имен ваших модулей с установленными пакетами (яиц), поскольку обычно оператор import будет искать каталоги в порядке, указанном sys.path, и текущий рабочий каталог, когда вы запускаете переводчик первым в этом списке. signal является своего рода особым случаем, потому что он импортируется автоматически перед выполнением вашего кода, но существует ограниченное количество модулей, для которых это правда, и это единственные, с которыми вы должны избегать столкновений имен.
  2. Вы можете del sys.modules['signal'] и заменить запись своим собственным signal модулем. На самом деле не делайте этого , если только ваш модуль не предназначен для замены встроенного signal. Если вы это сделаете, то любой код, который запускается с этого момента import signal, получит вашу версию, а не встроенную, и это может нанести ущерб любому внутреннему коду, для которого требуется модуль signal функционировать.
  3. Вы можете использовать модуль imp , чтобы получить доступ к внутренним компонентам функции import или, по крайней мере, к эквивалентному коду, который позволит вам обойти проверку sys.modules.

    Если вам действительно нужно это сделать, вот пример кода, который вы можете использовать:

    import imp, sys
    
    f, path, desc = imp.find_module('signal', sys.path)
    if f:
        f.close()
        signal = imp.new_module('signal')
        execfile(path, signal.__dict__)
    else:
        raise ImportError('signal.py not found')
    # signal is your module
    

    Этот фрагмент кода примерно эквивалентен import signal, за исключением того, что он не вставляет найденный модуль в sys.modules и не ищет встроенные модули перед поиском пути.

0 голосов
/ 19 декабря 2011

Из каталога проекта (родительский каталог package directory):

python -mpackage.state # Python 2.6+
python2.4 -c'from package.state import test; test()'
  • всегда использует абсолютный импорт в ваших модулях, т.е. import package.signal вместо import signal, если вы не знаете, что делаете
  • убедитесь, что родительский каталог package находится в sys.path. unittest2, nose, pytest бегуны могут сделать это за вас
  • избегать имен модулей, конфликтующих с модулями stdlib. Многие организаторы тестов, анализаторы кода не работают и добавляют каталоги с обрабатываемым модулем в sys.path
  • python package/stat.py добавляет package к sys.path (см. http://bugs.python.org/issue13475). Вы не хотите этого в этом случае
0 голосов
/ 19 декабря 2011

Файловая иерархия

.
|-- package
|   |-- __init__.py
|   |-- module.py
|   `-- signal.py
`-- script
`-- __init__.py

script.py

#!/usr/bin/env python
from package import module

пакет / module.py

#!/usr/bin/env python
print 'Loading module.py'
from package import signal

пакет / signal.py

#!/usr/bin/env python
print 'Loading signal.py'

Выход:

$ ./script 
Loading module.py
Loading signal.py

Редактировать

Только что протестировал это с модификацией для module.py, на python 2.4.3

...