В 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: мы считаем, что есливсе, что нам нужно для утки, это крякать, мы можем просто попросить ее крякать, и если это так, нам все равно, действительно ли это * утка или нет.(Это называется утка набрав; -)