Неожиданное поведение относительного импорта в Python - PullRequest
7 голосов
/ 04 мая 2011

Сегодня я столкнулся с очень удивительным отношением к импорту (к сожалению, после почти 4 часов выдергивания волос).

У меня всегда было впечатление, что если у вас есть "Класс А" внутриимя модуля "module_a.py" в пакете с именем "package", который вы могли бы эквивалентно использовать:

from package.module_a import ClassA

или

from module_a import ClassA

, если вы импортировали из модуля в«пакет».Я понял, что это относительный импорт.

У меня никогда не было проблем до сегодняшнего дня, когда мне нужно было проверить экземпляр объекта по классу A, и я был удивлен, обнаружив очень необычное поведение.

Обратите внимание на следующее:

package / module_a.py

class ClassA(object):
    pass

def check_from_module_a(obj):
    print 'from module_a'
    print '-------------'
    print 'class is:', ClassA
    print 'object is', type(obj) 
    print 'is obj a ClassA:', isinstance(obj, ClassA)

package / module_b.py

from package.module_a import ClassA
from module_a import check_from_module_a

a = ClassA()
check_from_module_a(a)

print ' '
print 'from module_b'
print '-------------'
print 'class is:', ClassA
print 'object is', type(a) 
print 'is obj a ClassA:', isinstance(a, ClassA)

Теперь при выполнении module_b.py вы получаете:

from module_a
-------------
class is: <class 'module_a.ClassA'>
object is <class 'package.module_a.ClassA'>
is obj a ClassA: False

from module_b
-------------
class is: <class 'package.module_a.ClassA'>
object is <class 'package.module_a.ClassA'>
is obj a ClassA: True

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

Мои вопросы:

  1. Можно ли ожидать такого поведения?

  2. Если это логический способ, которым он должен работать - тогда мне не ясно, почему я бы использовал относительный импорт, если он не совместим (в вышеприведенном смысле) с абсолютным импортом,Есть ли хорошее объяснение здесь, которого я пропускаю?

  3. Я всегда предполагаю, что относительный импорт обеспечил дополнительную простоту в больших рефакторах, когда структура субпакета могла бы быть перемещена.Это главное преимущество относительного импорта?

Ответы [ 2 ]

4 голосов
/ 04 мая 2011

Поскольку неявный относительный импорт вызвал проблемы, они были удалены в Python 3. Зачастую вы не получаете ожидаемого поведения с ними.См. PEP-328 для обсуждения.Это особенно верно, если вы определяете имя подпакета с тем же именем, что и базовый (стандартный) модуль.

0 голосов
/ 04 мая 2011

(1) Да, это ожидаемое поведение.

(2) Явный относительный импорт -

from .module_a import ClassA

, а не

from module_a import ClassA

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

(3) Да, это одно из преимуществ относительного импорта.Основным преимуществом, вероятно, является необходимость печатать меньше:)

...