Eu estava lendo a documentação do Python sobre como a importação é resolvida e encontrei isso
... o interpretador primeiro procura por um módulo interno com esse nome. Esses nomes de módulo são listados em sys.builtin_module_names. Se não for encontrado, ele procura por um arquivo chamado spam.py em uma lista de diretórios dada pela variável sys.path. sys.path é inicializado a partir desses locais:
O diretório que contém o script de entrada (ou o diretório atual quando nenhum arquivo é especificado).
PYTHONPATH (uma lista de nomes de diretórios, com a mesma sintaxe da variável de shell PATH). ...
Então o python primeiro olha para dentro sys.builtin_module_names
e depois para dentro sys.path
. Então eu verifiquei sys.builtin_module_names no meu SO (Mac).
>>> sys.builtin_module_names
('_abc', '_ast', '_codecs', '_collections', '_functools', '_imp', '_io', '_locale', '_operator', '_signal', '_sre', '_stat', '_string', '_suggestions', '_symtable', '_sysconfig', '_thread', '_tokenize', '_tracemalloc', '_typing', '_warnings', '_weakref', 'atexit', 'builtins', 'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'posix', 'pwd', 'sys', 'time')
>>> 'os' in sys.builtin_module_names
False
Como os
não está em sys.builtin_module_names
, um arquivo nomeado os.py
no mesmo diretório que meu arquivo python deve ter precedência sobre o os
módulo python.
Criei um arquivo chamado os.py
em um test
diretório com o seguinte código simples:
#os.py
def fun():
print("Custom os called!")
E criei outro arquivo chamado test.py
que importaos
#test.py
import sys
print("os in sys.builtin_module_names -", 'os' in sys.builtin_module_names)
print("First directory on sys -", sys.path[0])
import os
print("source file of the imported os -", os.__file__)
print(os.fun())
Esta é a saída detest.py
> python3 test.py
os in sys.builtin_module_names - False
First directory on sys - /Users/dhruv/Documents/test
source file of the imported os - /opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/os.py
Traceback (most recent call last):
File "/Users/dhruv/Documents/test/test.py", line 9, in <module>
print(os.fun())
^^^^^^
AttributeError: module 'os' has no attribute 'fun'
Por que o módulo python os é chamado?
sys.path
é inicializado da maneira que o tutorial diz, mas o Python precisa doos
módulo antes que a inicialização possa ser totalmente concluída.os
é necessário durante a configuração do Python. Ele é importado pelosite
módulo , que é importado durante a configuração do Python, a menos que você diga manualmente para não fazer isso (com o-S
sinalizador).Essas importações acontecem tão cedo que o interpretador Python ainda não decidiu qual programa Python ele vai executar. Ele descobre isso depois. E ele não pode adicionar o diretório de script
sys.path
até decidir qual é o script.Então, neste ponto inicial da configuração, o diretório de script não está em
sys.path
, e as importações não pesquisam o diretório de script. O Python não consegue encontrar seuos.py
tão cedo.Agora, em versões mais recentes do Python, há outra coisa a considerar. No Python 3.11 e posteriores, os desenvolvedores decidiram congelar um monte de módulos escritos em Python que são necessários na inicialização do Python. Isso incorpora seu bytecode diretamente no executável do Python, o que ajuda a tornar a inicialização mais rápida.
Módulos congelados não são mencionados no tutorial - tutoriais geralmente ignoram detalhes obscuros como este. Módulos congelados são pesquisados depois de módulos integrados e antes da
sys.path
pesquisa.os
é um dos módulos que foram congelados, então no Python 3.11 e superior, a versão stdlib deos
teria prioridade sobre umos.py
no diretório de script mesmo depoissys.path
de totalmente inicializado.