Использование абсолютного импорта и обработка конфликтов имен относительных модулей в python

Я действительно надеюсь, что это простой случай, когда мне не хватает понимания сложных механизмов импорта Python2. У меня есть следующая настройка:

$> ls -ltr pypackage1 
total 3
-rw-r--r-- 1 pelson pelson   0 Aug 17 19:20 io.py
-rw-r--r-- 1 pelson pelson   0 Aug 17 19:20 __init__.py
-rw-r--r-- 1 pelson pelson  57 Aug 17 19:22 code.py
$> cat pypackage1/code.py 
from __future__ import absolute_import

import zipfile

т. е. у меня нет ничего, кроме пакета заглушки с пустым __init__.py и io.py, и 2 строки .

Я могу импортировать pypackage1:

$> python -c "import pypackage1.code"

но я не могу запустить :

$> python pypackage1/code.py
Traceback (most recent call last):
  File "pypackage1/code.py", line 3, in <module>
    import zipfile
  File "python2.7/zipfile.py", line 462, in <module>
    class ZipExtFile(io.BufferedIOBase):
AttributeError: 'module' object has no attribute 'BufferedIOBase'

очевидно, что проблема связана с собирание мой родственник модуль IO над зданием io модуль, но я думал, что мой from __future__ import absolute_import исправил бы это.

заранее спасибо за любую помощь,

3 ответов


это правильное поведение. Если вы хотите исправить ошибку, просто не запускайте ее изнутри пакета.

когда вы запускаете скрипт, который находится внутри пакета, python не интерпретирует этот каталог как пакет, добавляя таким образом рабочий каталог в PYTHONPATH. Вот почему io модуль импортирован zipfile модуль-это ваш io модуль, а не внутри стандартной библиотеки.

Я бы рекомендовал создать простой сценарий запуска вне вашего пакет (или в bin/scripts папка), и запустите это. Этот скрипт может просто содержать что-то вроде:

from pypackage1 import code

code.main()

альтернативой этому является сообщить интерпретатору python, что файл, который вы хотите выполнить, является частью модуля. Вы можете сделать это с помощью командная строка. В вашем случае вам придется делать:

python -m pypackage1.code

обратите внимание, что аргумент -m должен быть имя модуля, а не имя файла.


одним из решений было бы поставить from __future__ import absolute_import на zipfile.py модуль. Хотя код модуль использует абсолютный импорт,zip-файл модуль не.

другой вариант-не запускать из каталога пакета. Вероятно, вы не должны запускать интерпретатор из каталога пакетов.


структура файла:

test.py
mylib/__init__.py
mylib/__collections.py
mylib/collections.py
mylib/mymod.py

это решение позволяет:

  • test.py чтобы вызвать оба _ _ builtin__.сборники и mylib.сборники
  • mymod.py чтобы вызвать вышеизложенное, как когда он работает как часть библиотеки и когда он запускается автономно (например, для тестового кода)

In test.py:

from collections import deque
from mylib.collections import mydict

In mylib/__init__.py:

from __future__ import absolute_import
from . import collections
from . import mymod

In mylib/__collections.py:

class MyDict (dict):
    pass

In mylib/collections.py:

from __collections import *

In mylib/mymod.py:

from __future__ import absolute_import
from collections import deque
try:
    # Module running as part of mylib
    from .collections import MyDict
except ValueError:
    # Module running independently
    from __collections import MyDict

вышеуказанное работает с Python >=2.5. Python 3 не нуждается в строках "from _ _ future_ _ import absolute_import".