Контекст выполнения другой. В рамках REPL мы работаем построчно ( R ead, E val, P rint, L oop), что позволяет изменять глобальную область выполнения между каждым шагом. Но среда выполнения, выполняющая модуль, должна загрузить код модулей, а затем выполнить его в области видимости.
В CPython пространство имен встроенных файлов, связанное с выполнением блока кода, определяется путем поиска имени __builtins__
в глобальном пространстве имен; это должно быть связано со словарем или модулем (в последнем случае используется словарь модуля). Когда в модуле __main__
, __builtins__
является встроенным модулем builtins
, в противном случае __builtins__
связан со словарем самого модуля builtins
. В обоих контекстах вашего вопроса мы находимся в модуле __main__
.
Важно то, что CPython просматривает встроенные только один раз , прямо перед тем, как он начнет выполнять ваш код. В REPL это происходит каждый раз, когда выполняется новый оператор. Но при выполнении скрипта Python все содержимое скрипта представляет собой одну единицу. Вот почему удаление встроенных элементов в середине скрипта не имеет никакого эффекта.
Чтобы более точно воспроизвести этот контекст внутри REPL, вы не должны вводить код модуля построчно, а вместо этого использовать составной оператор:
>>> if 1:
... del __builtins__
... print(123)
...
123
>>> print(123)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'print' is not defined
Естественно, вы, вероятно, теперь задаетесь вопросом, как удалить встроенные функции из скрипта. Ответ должен быть очевидным: вы не можете сделать это, связав имя, но вы можете сделать это с помощью мутации:
# foo2.py
__builtins__.__dict__.clear()
print(int) # <- NameError: name 'print' is not defined
В качестве последнего замечания, тот факт, что имя __builtins__
связано вообще, является подробностью реализации CPython, и это явно задокументировано:
Пользователи не должны трогать __builtins__
; это строго деталь реализации.
Не полагайтесь на __builtins__
в отношении чего-либо серьезного, если вам нужен доступ к этой области, правильный путь к import builtins
и идти оттуда.