この記事では、主に Python のモジュール検索の原理と方法をサンプルコードを通じて詳しく紹介します。必要な方は、このエディターをフォローしてください。そして勉強。
前書き
この記事では主に Python モジュール検索の原理と方法を紹介し、参考と学習のために共有します。これ以上の苦労はせずに、詳細な紹介を見てみましょう:
基本概念
module
モジュール、インポートできるpyファイルまたはその他のファイルはモジュール
パッケージ
パッケージ、__init__ファイルを含むフォルダー
相対パス
相対パス、特定のディレクトリからの相対パス
絶対パス
絶対パス、フルパス
パス検索
Pythonインタープリターはインポートされたパッケージまたはモジュールを検索します
Pythonインタープリターはどのように検索するかパッケージとモジュール
Python は、実行方法が絶対パスか相対パスかに関係なく、ファイルが配置されているディレクトリを sys.path
に追加します。このリストでは、Python は sys.path
内のパッケージとモジュールを検索し、sys.path
自体の内容は Python の環境変数によって決定されます。 sys.path
这个 list 中,Python 就是在 sys.path
中查找包和模块的,sys.path
中的内容本身又是又 Python 的环境变量决定。
code-1
#test.py import os import sys print sys.path[0] # execute python test.py python /Users/x/workspace/blog-code/p2016_05_28_python_path_find/test.py
执行表明相对路径和绝对路径都输出相同的结果,而且无论哪种执行方式,test.py 所在的文件夹都会被加入 sys.path
的首位,也就是索引为0的位置。
Python 解释器查找包的顺序是什么
解释器查找包,首先搜索 built-in module,其次搜索 sys.path
,这样的查找顺序将会导致同名包或模块被遮蔽。
code-2
#ls ├── os.py ├── test2.py ├── redis.py #test2.py import os from redis import Redis #execute test2.py Traceback (most recent call last): File "/Users/x/workspace/blog-code/p2016_05_28_python_path_find/test2.py", line 1, in <module> from redis import Redis ImportError: cannot import name Redis
由于 os 是 built-in module,即使在同目录下有同名模块,解释器依然可以找到正确的 os 模块,可以证实 built-in module 不会被遮蔽,而 redis 属于第三方模块,默认安装位置是 Python 环境变量中的 site-packages,解释器启动之后会将此目录中的内容加入 sys.path
,由于当前目录会在 sys.path
的首位,当前目录的 redis 优先被找到,site-packages 中的 redis 模块被遮蔽了。
交互式执行环境的查找顺序
进入交互式执行环境,解释器会自动把当前目录加入 sys.path
, 这时当前目录是以相对路径的形式出现在 sys.path
中:
>>> import os.path >>> import sys >>> os.path.abspath(sys.path[0]) '/Users/x/workspace/blog-code' >>>
除此之外,其他与执行一个文件是相同的。
模块中的 __file__ 变量
__file__ is the pathname of the file from which the module was loaded, if it was loaded from a file. 如果一个模块是从文件加载的,__file__ 就是该模块的路径名–Python Doc:
顾名思义,当模块以文件的形式出现 __file__ 指的是模块文件的路径名,以相对路径执行 __file__ 是相对路径,以绝对路径执行 __file__ 是绝对路径。
#test3.py print __file__ #相对路径执行 python test3.py test3.py #绝对路径执行 python /Users/x/workspace/blog-code/p2016_05_28_python_path_find/test3.py /Users/x/workspace/blog-code/p2016_05_28_python_path_find/test3.py
为了保证__file__ 每次都能准确得到模块的正确位置,最好对其再取一次绝对路径 os.path.abspath(__file__)
。
交互式 shell 中的 __file__
>>> __file__ Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name '__file__' is not defined
这是因为当前交互式shell的执行并不是以文件的形式加载,所以不存在__file__ 这样的属性。
sys.argv[0] 变量
sys.argv[0]
是它用来获取主入口执行文件。
#test.py import sys print __file__ print sys.argv[0]
以上 print 输出相同的结果,因为主执行文件和__file__所属的模块是同一个,当我们改变入口文件,区别就出现了。
#test.py import sys print __file__ print sys.argv[0] #test2.py import test #execute test2.py /Users/x/workspace/blog-code/p2016_05_28_python_path_find/child/test.py #__file__ test2.py #sys.argv[0]
总的来说,sys.argv[0]
是获得入口执行文件路径,__file__ 是获得任意模块文件的路径。
sys.modules 的作用
既然 Python 是在 sys.path
中搜索模块的,那载入的模块存放在何处?答案就是 sys.modules
。模块一经载入,Python 会把这个模块加入 sys.modules
中供下次载入使用,这样可以加速模块的引入,起到缓存的作用。
>>> import sys >>> sys.modules['tornado'] Traceback (most recent call last): File "<input>", line 1, in <module> KeyError: 'tornado' >>> import tornado >>> sys.modules['tornado'] <module 'tornado' from '/Users/x/python_dev/lib/python2.7/site-packages/tornado/__init__.pyc'>
前面说过 Python 解释器启动之后,会把预先载入 built-in module,可以通过 sys.modules
>>> sys.modules['os'] <module 'os' from '/Users/x/python_dev/lib/python2.7/os.pyc'> >>>
に追加されることがわかります。 sys.path</code > 最初の位置、つまりインデックス 0 の位置です。 🎜🎜🎜🎜 Python インタープリターがパッケージを検索する順序は何ですか? 🎜🎜🎜🎜🎜 インタープリターは最初にパッケージを検索し、次に <code>sys.path
を検索します。同じ名前のパッケージまたはモジュールは隠されます。 🎜🎜code-2🎜🎜🎜🎜>>> import os >>> os.path.realpath(sys.modules['os'].__file__) '/Users/x/python_dev/lib/python2.7/os.pyc' >>> import tornado >>> os.path.realpath(sys.modules['tornado'].__file__) '/Users/x/python_dev/lib/python2.7/site-packages/tornado/__init__.pyc'
にあるため) sys.path
の先頭では、現在のディレクトリ内の redis が最初に検出され、site-packages 内の redis モジュールは隠蔽されます。 🎜🎜🎜🎜対話型実行環境の検索シーケンス🎜🎜🎜🎜🎜対話型実行環境に入ると、インタプリタは現在のディレクトリを sys.path
に自動的に追加します。現在のディレクトリは相対パスになります。 path フォームは sys.path
に表示されます: 🎜🎜🎜🎜def get_module_dir(name): path = getattr(sys.modules[name], '__file__', None) if not path raise AttributeError('module %s has not attribute __file__'%name) return os.path.dirname(os.path.abspath(path))
os.path.abspath(__file__)
を使用するのが最善です。 🎜🎜__file__ インタラクティブ シェル🎜🎜🎜🎜rrreee🎜これは、インタラクティブ シェルの現在の実行がファイルの形式でロードされていないため、__file__ などの属性が存在しないためです。 🎜🎜🎜🎜sys.argv[0] 変数 🎜🎜🎜🎜🎜sys.argv[0]
は、メインエントリの実行可能ファイルを取得するために使用されます。 🎜🎜🎜🎜rrreee🎜 上記の print は、メインの実行ファイルと __file__ が属するモジュールが同じなので、エントリ ファイルを変更すると違いが現れます。 🎜🎜🎜🎜rrreee🎜 一般に、sys.argv[0]
はエントリ実行ファイルを取得するパスであり、__file__ はモジュール ファイルを取得するパスです。 🎜🎜🎜🎜sys.modulesの役割🎜🎜🎜🎜🎜Pythonはsys.path
でモジュールを検索するので、ロードされたモジュールはどこに保存されているのでしょうか?答えは sys.modules
です。モジュールが読み込まれると、Python は次回の読み込みのためにモジュールを sys.modules
に追加します。これにより、モジュールの導入が高速化され、キャッシュとして機能します。 🎜🎜🎜🎜rrreee🎜 前に述べたように、Python インタープリターの開始後、組み込みモジュールがプリロードされ、sys.modules
で確認できます。 🎜🎜🎜🎜>>> sys.modules['os'] <module 'os' from '/Users/x/python_dev/lib/python2.7/os.pyc'> >>>
借助 sys.modules
和 __file__,可以动态获取所有已加载模块目录和路径。
>>> import os >>> os.path.realpath(sys.modules['os'].__file__) '/Users/x/python_dev/lib/python2.7/os.pyc' >>> import tornado >>> os.path.realpath(sys.modules['tornado'].__file__) '/Users/x/python_dev/lib/python2.7/site-packages/tornado/__init__.pyc'
def get_module_dir(name): path = getattr(sys.modules[name], '__file__', None) if not path raise AttributeError('module %s has not attribute __file__'%name) return os.path.dirname(os.path.abspath(path))
summary
总的来说,Python 是通过查找 sys.path
来决定包的导入,并且系统包优先级>同目录>sys.path
,Python 中的特有属性 __file__ 以及 sys.argv[0]
,sys.modules
都能帮助我们理解包的查找和导入概念,只要能正确理解 sys.path
的作用和行为,理解包的查找就不是难题了。
以上がPythonモジュール検索の原理と方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。