Порядок инициализации модуля Python?

Я - новичок Python, происходящий из среды C++. В то время как я знаю, что это не Pythonic, чтобы попытаться найти принцип соответствия с помощью моего старого знания C++, я думаю, что этим вопросом является все еще общий вопрос спросить:

Под C++ существует известная проблема, названная глобальным фиаско порядка инициализации / фиаско порядка инициализации статической переменной, из-за неспособности C++ решить, какая глобальная / статическая переменная была бы инициализирована сначала через единицы компиляции, таким образом глобальная / статическая переменная в зависимости от другого в различных единицах компиляции могла бы быть инициализирована ранее, чем ее дубликаты зависимости, и когда иждивенец начал использовать услуги, предоставленные объектом зависимости, у нас будет неопределенное поведение. Здесь я не хочу идти слишком глубоко о том, как C++ решает эту проблему.:)

На мире Python я действительно вижу использование глобальных переменных, даже через различные .py файлы, и один типичный случай использования, который я видел, был: инициализируйте один глобальный объект в одном .py файле, и на других .py файлах, код просто бесстрашно начинают использовать глобальный объект, предполагая, что он, должно быть, был инициализирован где-то в другом месте, который под C++ является, определенно не принимают один, из-за проблемы, которую я указал выше.

Я не уверен, является ли вышеупомянутый вариант использования обычной практикой в Python (Pythonic), и как Python решает этот вид проблемы порядка инициализации глобальной переменной в целом?

Большое спасибо!

Lin

15
задан Lin 21 June 2010 в 03:49
поделиться

2 ответа

В C ++ существует хорошо известная проблема, называемая фиаско порядка инициализации глобальных / статических переменных, из-за неспособности C ++ решить, какая глобальная / статическая переменная будет инициализирована первой в единицах компиляции.

Я думаю, что этот оператор выделяет ключ разница между Python и C ++: в Python нет такой вещи, как разные единицы компиляции. Я имею в виду, что в C ++ (как вы знаете) два разных исходных файла могут быть скомпилированы полностью независимо друг от друга, и, таким образом, если вы сравните строку в файле A и строку в файле B, сказать нечего. вы займете первое место в программе. Это похоже на ситуацию с несколькими потоками: вы не можете сказать, будет ли конкретный оператор в потоке 1 выполняться до или после определенного оператора в потоке 2. Можно сказать, что программы на C ++ компилируются параллельно.

В отличие от этого, в Python выполнение начинается с начала одного файла и продолжается в четко определенном порядке через каждый оператор в файле, переходя к другим файлам в тех точках, где они были импортированы. Фактически, вы почти могли представить себе директиву import как #include , и таким образом вы могли бы определить порядок выполнения всех строк кода во всех исходных файлах. в программе. (Ну, это немного сложнее, поскольку модуль действительно запускается только при первом импорте и по другим причинам.) Если программы C ++ компилируются параллельно, программы Python интерпретируются последовательно.

Ваш вопрос также касается более глубокого значения модулей в Python.Модуль Python - это все, что находится в одном файле .py - это реальный объект. Все, что объявлено в «глобальной» области в одном исходном файле, на самом деле является атрибутом этого объекта модуля. В Python нет настоящей глобальной области видимости. (Программисты Python часто говорят «глобальный», и на самом деле в языке есть ключевое слово global , но оно всегда действительно относится к верхнему уровню текущего модуля.) Я мог видеть, что это немного похоже на странная концепция, чтобы привыкнуть исходить из фона C ++. Мне потребовалось некоторое время, чтобы привыкнуть к Java, и в этом отношении Java намного больше похожа на Python, чем на C ++. (В Java также нет глобальной области видимости)

Я отмечу, что в Python совершенно нормально использовать переменную, не имея представления о том, была ли она инициализирована / определена или нет. Что ж, может и не нормально, но, по крайней мере, приемлемо при соответствующих обстоятельствах. В Python при попытке использовать неопределенную переменную возникает ошибка NameError ; у вас нет произвольного поведения, как в C или C ++, поэтому вы можете легко справиться с ситуацией. Вы можете увидеть этот шаблон:

try:
    duck.quack()
except NameError:
    pass

, который ничего не делает, если duck не существует. На самом деле, вы чаще увидите

try:
    duck.quack()
except AttributeError:
    pass

, который ничего не делает, если duck не имеет метода с именем quack . ( AttributeError - это ошибка, которую вы получаете, когда пытаетесь получить доступ к атрибуту объекта, но у объекта нет атрибута с таким именем.Это то, что проходит для проверки типа в Python: мы полагаем, что если все, что нам нужно от утки, - это кряканье, мы можем просто попросить ее крякнуть, и если это так, нам все равно, действительно ли это утка или нет. (Это называется утиным набором текста; -)

11
ответ дан 1 December 2019 в 03:13
поделиться

Импорт Python выполняет новые модули Python от начала до конца. Последующий импорт приводит только к копии существующей ссылки в sys.modules , даже если он все еще находится в процессе импорта модуля из-за циклического импорта. Атрибуты модуля («глобальные переменные» фактически находятся в области видимости модуля), которые были инициализированы до того, как будет существовать циклический импорт.

main.py :

import a

a.py :

var1 = 'foo'
import b
var2 = 'bar'

b.py :

import a
print a.var1 # works
print a.var2 # fails
12
ответ дан 1 December 2019 в 03:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: