Различение импорта между родным и питоном и импортом функции / класса - PullRequest
0 голосов
/ 28 августа 2018

Я пишу средство проверки Pylint, и мне нужно провести различие между импортом, который является импортом пакета одного уровня, и импортом функции или класса.

Пример импорта родного брата:

from . import sibling_package

Пример импорта функции:

from numpy import array

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

Я сейчас использую:

modspec = importlib.util.find_spec('numpy', 'array')

Это возвращает ModuleSpec, но мне неясно, как я могу достичь цели идентификации импорта array как модуля по сравнению с функцией / классом. В этом примере это импорт функции, и поэтому он должен быть помечен.

1 Ответ

0 голосов
/ 29 августа 2018

Это не то, что вы легко можете обнаружить только из строки импорта . Python очень динамичен, и только во время выполнения вы можете узнать, к какому типу объектов относится импорт. Спецификация модуля не может сообщить вам эту информацию, потому что атрибут модуля может разрешать что угодно (включая другой модуль).

Альтернативы, которые я вижу:

  • , чтобы выполнить фактический импорт, затем протестируйте тип объекта.

    Это не без риска, импорт может иметь побочные эффекты. Импорт модуля включает в себя выполнение операторов верхнего уровня. Эти побочные эффекты могут быть слабыми, как замена одного объекта другим, когда зависимость не встречается (try: from itertools import zip_longest, except ImportError: from itertools import izip_longest as ziplongest - это тривиальная проверка зависимостей Python 2 против Python 3), но, возможно, импорт может внести изменения в файловую систему!

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

  • Хранить список известных модулей. Для тех модулей, о которых вы знаете, жалуйтесь, если они импортируют имена из модуля, а не сам модуль. Это быстро, и поймает большинство распространенных случаев. Вы можете дополнить список тем, что можете почерпнуть из файловой системы вокруг подсвечиваемого модуля. Иными словами, стремитесь к быстро и достаточно хорошо и примите несколько промахов для нового импорта.

  • Жаловаться, только если импортированные имена вызываются напрямую. Зарегистрируйте все импортируемые имена, и если AST содержит узел Call для этого имени, то вы знаете, что они импортировали функцию или класс. from foo import bar, затем spam = bar('baz') - это четкий индикатор того, что bar не является модулем.

...