Python: почему импортированный модуль не может ссылаться на другой импортированный модуль? - PullRequest
10 голосов
/ 11 октября 2010

main.py:

import subone
import subtwo

subone.py:

a = 'abc'

subtwo.py:

print subone.a

Бег python main.py Бросает NameError: name 'subone' is not defined. Я ожидал, что это напечатает 'abc'.

Рефакторинг для использования from import и классы не помогают:

main.py:

from subone import *   # Only using from X import * for example purposes.
from subtwo import *

print 'from main.py:', a.out

subone.py:

class A:
    out = 'def'

a = A()

subtwo.py:

# This throws NameError: name 'a' is not defined
print a.out

# This throws NameError: name 'A' is not defined
b = A()
print b.out

НО будет печатать 'из main.py: def'. (Работает и при использовании import.)

Почему это так работает? Кажется, как только subone импортируется, он должен быть доступен для subtwo.

Это потому, что плохое программирование состоит в том, что импортируемые модули зависят друг от друга, не проходя через их «родительский» модуль? Есть ли другой, стандартный способ сделать это?

Обновление:

Теперь я понимаю, что первый пример не будет работать, потому что строка print subone.a не распознает имя subone, оно не входит в пространство имен subtwo * (даже если оно находится в main.py s), и он вызывается из модуля subtwo. Это можно исправить, используя import subone в верхней части subtwo.py - он не будет перезагружать модуль, но добавит его в пространство имен subtwo, чтобы subtwo мог его использовать.

А как же это:

main.py:

from subone import Nugget
from subtwo import Wrap

wrap = Wrap()
print wrap.nugget.gold

subone.py:

class Nugget:
    gold = 'def'

subtwo.py:

class Wrap:
    nugget = Nugget()

Я бы подумал, что поскольку Wrap и Nugget оба загружаются непосредственно в пространство имен main, они будут использовать пространство имен main и смогут ссылаться друг на друга, но он выдает NameError: name 'Nugget' is not defined. ОНА ЭТО, потому что Wrap оценивается / проверяется с в пределах пространства имен subtwo ПЕРЕД загрузкой в ​​пространство имен main?

Ответы [ 5 ]

6 голосов
/ 11 октября 2010

Если вы изменили ваш subtwo.py таким образом, он будет работать

import subone
print subone.a

Когда вы выполняете subone.a в subtwo.py, вы пытаетесь получить доступ к subone пространства имен в subtwo.py и вв пространстве имен «subone» должен быть атрибут «a».

Когда вы делаете - импортируете subone в subtwo.py, тогда subone добавляется в пространство имен, и у пространства имен subone есть атрибут a.так что subone.a будет работать.

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

В subtwo.py вы можете сделать следующее:

print dir()
import subone
print dir()
print subone.a

Аналогично, попробуйте добавить «print dir ()» до и после ваших операторов импорта, и идея должна стать вам понятной.

«import x» добавляет «x»в текущее пространство имен модулей, в то время как "из x import *" добавит все атрибуты уровня модуля непосредственно в текущее пространство имен модулей

Так что в приведенном выше первом примере main.py, subone.pyи subtwo.py, пространство имен в main.py будет содержать «subone» и «subtwo», тогда как subtwo.py будет иметь пустое пространство имен и не сможет получить доступ к subone.a.

[Редактировать: Некоторыедополнительные объяснения] Рассмотрим следующие файлы: main.py

print "Before importing subone : ", dir()
import subone
print "After importing subone and before importing subtwo: ",  dir()
import subtwo
print "After importing subone and subtwo: ", dir()

subone.py

a = 'abc'

subtwo.py

print dir()
import subone
print "module level print: ", subone.a
print dir()
def printX():
    print subone.a

И вывод работающей main.py:

Before importing subone :  ['__builtins__', '__doc__', '__file__', '__name__', '__package__']
After importing subone and before importing subtwo:  ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone']
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
module level print:  abc
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone']
After importing subone and subtwo:  ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone', 'subtwo']

Некоторые наблюдения

  1. Вы не будетеОбратите внимание, что при импорте модуля subtwo.py оператор print выполняется немедленно.
  2. Таким образом, когда subone и subtwo импортируются в main.py, пространство имен main.py увеличивается.
  3. Это не означает, что пространство имен subtwo будет увеличено.так что «a» доступно только в main.py через subone.a
  4. Когда мы импортируем subone в subtwo.py, тогда пространство имен subtwo увеличивается с помощью subone, а атрибут a модуля subone доступен в subtow.py через subone.a
3 голосов
/ 11 октября 2010

Можете ли вы объяснить, почему вы чувствуете, что subone должен быть доступен для subtwo, когда subone был импортирован main? Таким образом, subtwo.py можно скомпилировать, не зная, что импортировал main.py.

Также, если вторая программа импортирует subtwo.py, должно ли знание subtwo о subone зависеть от того, какая из двух основных программ импортирует subtwo? Это уменьшит возможность повторного использования subtwo.

Кажется, вы думаете о компиляции как о процессе с определенным порядком, накапливающем информацию о состоянии: compile main.py, во время которого мы компилируем / импортируем subone.py, накапливаем информацию из него, а затем мы компилируем / импортировать subtwo.py, используя информацию, которую мы уже накопили.

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

Это потому, что плохо программировать импортированные модули зависят от каждого другой, не пройдя через их «родительский» модуль?

Не как таковое ... Это просто плохое программирование, когда модуль 2 зависит от модуля 1 , не говоря так: , т.е. без модуля 2, объявляющего «Я зависим от модуля 1».

2 голосов
/ 11 октября 2010

Пространство имен subtwo будет полностью пустым, если вы не импортируете в него subone.

Что касается практики программирования, subone и subtwo могут зависеть друг от друга, если это необходимо, вам просто нужно явно связать их (с import)

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

Это потому, что импортированные модули имеют свои собственные отдельные пространства имен.То, что вы написали, очень похоже на:

def func1():
    a = 1

def func2():
    print a

func1()
func2()  # This will throw an error

a = 2

func2()  # Now this will print 2.

Модули имеют свои пространства имен локально, и когда вы используете from subone import *, вы импортируете пространство имен ТОЛЬКО в main.py пространство имен, которое не доступно для subtwo.

Тем не менее - то, что вы пытаетесь сделать, - очень плохая практика.Избегайте использования глобальных переменных и import *, просто потому, что вы будете все больше и больше путаться, как сейчас.


Подробнее об этом: https://docs.python.org/3/reference/import.html

https://bytebaker.com/2008/07/30/python-namespaces/

http://www.diveintopython.net/html_processing/locals_and_globals.html

и, возможно: http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html

0 голосов
/ 12 октября 2010

Что касается вашего второго примера, «main.py» знает о Nugget, а «subtwo.py» - нет.

Я думаю, это помогло бы думать об этом таким образом. Каждый модуль (файл) должен работать так, как если бы единственными существующими модулями были те, которые он импортировал. В этом случае «subtwo.py» не сможет работать сам по себе, потому что он не импортировал Nugget. По сути, «subtwo.py» не знает, что знает «main.py». Этого не должно быть, потому что он может быть вызван откуда угодно кем угодно, и он не может полагаться на то, что кто-то другой импортирует нужные ему материалы.

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