Как на самом деле работает ключевое слово import в python? - PullRequest
3 голосов
/ 22 июня 2010

Допустим, у меня есть 3 файла:

a.py

from d import d

class a:
    def type(self):
        return "a"
    def test(self):
        try:
            x = b()
        except:
            print "EXCEPT IN A"
            from b import b
            x = b()
        return x.type()

b.py

import sys

class b:
    def __init__(self):
        if "a" not in sys.modules:
            print "Importing a!"
            from a import a
        pass
    def type(self):
        return "b"
    def test(self):
        for modules in sys.modules:
            print modules
        x = a()
        return x.type()

c.py

from b import b
import sys

x = b()
print x.test()

и запустить python c.py

Python возвращается с жалобой:

NameError: глобальное имя 'a' не определено

Но, aIS в sys.modules:

copy_reg
sre_compile
locale
_sre
functools
encodings
site
__builtin__
operator
__main__
types
encodings.encodings
abc
errno
encodings.codecs
sre_constants
re
_abcoll
ntpath
_codecs
nt
_warnings
genericpath
stat
zipimport
encodings.__builtin__
warnings
UserDict
encodings.cp1252
sys
a
codecs
os.path
_functools
_locale
b
d
signal
linecache
encodings.aliases
exceptions
sre_parse
os

И я могу изменить b.py так, чтобы:

x = a ()
изменилось на
x = sys.modules ["a"]. a ()

И Python с радостью выполнит это.

Из этого возникает пара вопросов:

Почему Python говорит, что не знает, чтоа есть, когда он находится в sys.modules?
Является ли использование sys.modules «правильным» способом доступа к определениям классов и функций?
Каков «правильный» способ импорта модулей?
т.е.модуль импорта x
или
модуль импорта

Ответы [ 4 ]

3 голосов
/ 22 июня 2010

Полагаю, это проблема с областью видимости, если вы импортируете модуль в свой конструктор, вы можете использовать его только в своем конструкторе после оператора import.

2 голосов
/ 22 июня 2010

Согласно документации Python ,

Операторы импорта выполняются в два этапа: (1) найти модуль и инициализировать его при необходимости;(2) определить имя или имена в локальном пространстве имен (области действия, в которой выполняется оператор импорта).

Таким образом, проблема в том, что, хотя модуль a был импортирован, имя a ограничено только областью действия метода b.__init__, а не всей областью действия b.py.Таким образом, в методе b.test такого имени нет a, и вы получите NameError.

Возможно, вы захотите прочитать эту статью об импорте модулей Python ,как это помогает объяснить лучшие практики для работы с import s.

1 голос
/ 22 июня 2010

В вашем случае a находится в sys.modules .. но не все в sys.modules находится в области действия b.Если вы хотите использовать re, вам придется импортировать и это.

Условный импорт иногда допустим, но это не один из таких случаев.С одной стороны, круговая зависимость между a и b в этом случае является неудачной, и ее следует избегать (для этого нужно множество шаблонов в рефакторинге Фаулера). При этом нет необходимости в условном импорте здесь.* б должен просто импортировать.Чего вы пытались избежать, не импортируя его непосредственно вверху файла?

0 голосов
/ 22 июня 2010

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

if (something)
  from office import desk
else
  from home import desk

... somewhere later in the code...
desk()

Даже если у вас нет проблем с областями видимости (которые у вас, скорее всего, будут), это все еще сбивает с толку.

Поставьте все своиимпортировать операторы в верхней части вашего файла.Вот где их будут искать другие кодеры.

Что касается использования стихов «из строки импорта foo» просто «import foo», компромисс - это скорее ввод текста (при необходимости ввести «foo.bar ()»или просто введите «bar ()») стихи ясности и специфики.Если вы хотите, чтобы ваш код был действительно читабельным и однозначным, просто скажите «import foo» и полностью укажите вызов везде.Помните, что читать код гораздо сложнее, чем писать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...