日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

native.loadlibrary获取路径不对_【Python专题(三)】Python模块导入与路径管理

發(fā)布時(shí)間:2024/7/19 python 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 native.loadlibrary获取路径不对_【Python专题(三)】Python模块导入与路径管理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?前言

Python項(xiàng)目的路徑管理是一個(gè)讓人頭疼的問題。在寫python項(xiàng)目的時(shí)候,明明 import了文件A,代碼運(yùn)行時(shí)卻收到 ModuleNotFoundError,仔細(xì)一看,是引用路徑不對,很是氣人。又或者,當(dāng)項(xiàng)目中出現(xiàn)了重名的packages時(shí),發(fā)現(xiàn)引用的函數(shù)并不是自己想要的,而是其他同名packages中的函數(shù)。這些問題歸根結(jié)底都是Python路徑管理的問題。那么今天我們一起來看看Python的路徑管理到底是怎么做的,了解原理后,以后自然不會被路徑問題所困擾了!

路徑索引順序

如我們在Python專題(二)Python二三事中講的,Python2和Python3在路徑索引的順序上有些許不同,感興趣的同學(xué)可以參考上篇專題內(nèi)容。本文僅講Python3版本的情況。首先,在Python中有內(nèi)建函數(shù)(built-in)、第三方庫(site-packages)以及自義庫三種可以 import的模塊。然后,在 import模塊時(shí),Python解釋器的搜索順序是先搜索built-in模塊,然后搜索 sys.path這個(gè)路徑列表中的模塊。那么Python的built-in模塊又有哪些呢?我們可以在Python中用如下命令查看:

import sys print(sys.builtin_module_names)

你會看到一長串builtin模塊的名字,這些模塊名稱是 import動作最先搜索到的。

我們在來看看sys.path中又有哪些東西呢?

sys.path是一個(gè)路徑列表,里面保存了解釋器可以索引的所有路徑。這個(gè)路徑列表可分為如下部分:

  • 當(dāng)前腳本路徑
  • PYTHONPATH路徑
  • 虛擬環(huán)境路徑
  • site-packages路徑

一般來說,第三方庫會安裝在site-packages路徑下,當(dāng)前腳本路徑則是一些自定義模塊,而PYTHONPATH和虛擬環(huán)境路徑則是當(dāng)前系統(tǒng)的環(huán)境變量和Python虛擬環(huán)境保存的路徑。

所以當(dāng)來了一個(gè) import命令時(shí),Python解釋器的搜索順序就是:

當(dāng)然,這個(gè)sys.path中的索引順序只是一個(gè)默認(rèn)順序,你完全可以在代碼中通過sys模塊修改這個(gè)順序,在后文中你會看到如何對這個(gè)索引順序進(jìn)行修改。當(dāng)完成 import動作后,Python會把這些模塊的名字和所在路徑保存在一個(gè)字典里,相當(dāng)于一個(gè)緩存,在后面需要運(yùn)行這個(gè)模塊代碼時(shí)可以迅速查找到該部分代碼。你可以通過 print(sys.modules)來查看當(dāng)前Python解釋器緩存(導(dǎo)入)了哪些模塊。

from 和 import

老生常談的話題了,但是很容易忽略。多數(shù)情況下,

from module import fun a = fun()

import module a = module.fun()

在效果上是等價(jià)的。區(qū)別是第一種方式只引用了 module中的 fun函數(shù),而第二種方式引用了整個(gè) module。只引用 fun函數(shù),可能造成代碼中的變量名混亂,譬如你的代碼中本來就有一個(gè)名為 fun的函數(shù),這時(shí)候用第一種方式導(dǎo)入,會悄無聲息地替換掉代碼中原本的 fun函數(shù),從而引起命名空間混亂。而引用整個(gè) module時(shí),解釋器會運(yùn)行 module中的所有代碼,如果 module中有很耗時(shí)而我們又不需要的運(yùn)算,第二種方式會存在冗余資源消耗。

還有一種導(dǎo)入模塊的方式:

from module import * a = fun()

這種導(dǎo)入模塊的方式是官方不提倡的,因?yàn)閯偛艂兲岬接?fromimport的方法會產(chǎn)生變量名混亂,但是 frommoduleimportfun畢竟還是指定了導(dǎo)入的函數(shù)名,開發(fā)者還是可以很容易地察覺到問題。而 frommoduleimport*這種方式會讓開發(fā)者導(dǎo)入 module中的所有公有類,函數(shù),變量,從而使當(dāng)前腳本中被導(dǎo)入了很多未知的變量名,讓代碼的管理變得更加復(fù)雜和不可控。不過,我們還是有辦法控制 frommoduleimport*的行為的——用 __all__屬性。如果在 module腳本中定義了 __all__屬性,那么 frommoduleimport*就只會導(dǎo)入 __all__中的變量名:

# module.py __all__ = ["fun"] # from module import * 只會導(dǎo)入fun def fun():return True def fun1(): # from module import * 不會導(dǎo)入fun1pass var1 = False # from module import * 不會導(dǎo)入var1

sys.argv[0]和_file_

sys.argv[0]用來獲取入口執(zhí)行文件的路徑。__file__用來獲取當(dāng)前腳本文件的路徑。為了加深理解,做個(gè)小試驗(yàn):

假設(shè)我的目錄:

|-Users

|--myname

|----test1.py

|----test2.py

test1.py:

import sys print(__file__) print(sys.argv[0])

test2.py:

import test1

執(zhí)行test1.py:

python test1.py

得到結(jié)果:

test1.py test1.py

執(zhí)行test2.py:

python test2.py

得到結(jié)果:

/Users/myname/test1.py test2.py

在上一級目錄執(zhí)行test1.py:

python myname/test1.py

得到結(jié)果:

myname/test1.py myname/test1.py

在上一級目錄執(zhí)行test2.py:

python myname/test2.py

得到結(jié)果:

/Users/myname/test2.py myname/test2.py

05令人困擾的自引用問題

上面介紹了很多關(guān)于Python內(nèi)部的路徑管理的規(guī)則和原理。其實(shí)介紹這些規(guī)則和原理的終極目標(biāo)就是解決令人困擾的自引用問題。在你寫一個(gè)項(xiàng)目時(shí),假設(shè)你的文件結(jié)構(gòu)如下:

|-myproject

|----tools

|--------_init_.py

|--------trainer.py

|----utils

|--------_init_.py

|--------trans.py

|----test.py

如果在 test.py中需要用到 tools/trainer.py中的函數(shù),那么在 test.py中直接引用即可:

import tools.trainer

這種方式其實(shí)是用了前面我們聊到的當(dāng)前路徑索引,解釋器從當(dāng)前目錄出發(fā),查找相對路徑為 tools/trainer的模塊。這時(shí)候我們可以完美運(yùn)行 test.py。

注意:文件夾下必須有_init_.py文件,解釋器才能夠找到模塊。

但是如果在 utils/trans.py中需要用到 tools/trainer中的函數(shù):

import tools.trainer

就會收到 ModuleNotFoundError的錯(cuò)誤信息。因?yàn)榻忉屍鞑檎耶?dāng)前腳本路徑時(shí),找不到 tools/trainer.py這個(gè)文件,正確的路徑應(yīng)該是 ../tools/trainer.py,因?yàn)楫?dāng)前的執(zhí)行腳本是 utils/trans.py。那么我們修改一下路徑:

import sys sys.path.insert(0, "../") import tools.trainer

sys.path.insert(0,"../")會把上級目錄 ../插入 sys.path列表的首位,這也就是前文說的,通過sys模塊來修改默認(rèn)的索引路徑。這樣會強(qiáng)制解釋器搜索當(dāng)前腳本路徑的上級路徑,解釋器就可以找到我們需要的模塊。

上文所述的方法是一種比較方便但是并不是很規(guī)范的方式,因?yàn)槿绻凑誔EP-8的規(guī)范, import語句要在代碼最前面, sys.path.insert(0,"../")這條語句插在兩個(gè) import語句中間,其實(shí)是違反了PEP-8規(guī)范。所以,更加規(guī)范的方式是什么呢?

筆者自己也很困惑這個(gè)問題,于是參考了一些開源的Python項(xiàng)目,發(fā)現(xiàn)他們一般用 site_packages路徑索引而非用當(dāng)前腳本路徑索引,由于 site_packages路徑索引會直接把 myproject路徑加入索引列表,所以 tools/trainer.py可以在系統(tǒng)的任何路徑下被索引到,問題自然得到解決。那么如何讓Python解釋器知道某條 import語句用哪種索引方法呢?回顧一下 路徑索引順序這一節(jié),我們提到解釋器會在sys.path這個(gè)路徑列表搜索模塊,默認(rèn)情況下,會先從當(dāng)前路徑開始搜索,然后搜索環(huán)境變量,最后搜索site-packages路徑。所以要讓解釋器用 site_packages路徑索引,我們需要確保:

  • 當(dāng)前路徑下沒有與所導(dǎo)入模塊重名的文件
  • 所導(dǎo)入的模塊(文件)在 site_packages路徑下

第一個(gè)條件很容易達(dá)成,第二個(gè)條件一般有兩種辦法實(shí)現(xiàn)。如果當(dāng)前項(xiàng)目myproject是一個(gè)純Python項(xiàng)目,可以直接把myproject文件夾復(fù)制到 site_packages目錄下,雖然可以使用,不過這種方式非常不規(guī)范。更規(guī)范的方式是用 setup.py把項(xiàng)目安裝在本地,關(guān)于 setup.py的使用我會在后面的專題中詳細(xì)介紹。

到此,我們就解決了這個(gè)令人困擾的自引用問題。

結(jié)語

本專題從Python路徑管理的原理出發(fā),介紹了模塊導(dǎo)入的路徑索引順序、from和import導(dǎo)入的區(qū)別、sys.argv[0]和_file_的含義。最后為大家提供了令人困擾的自引用問題的兩種解決辦法。其實(shí)對于筆者來說,在項(xiàng)目中導(dǎo)入自己的模塊產(chǎn)生的路徑問題困擾了我很久,直到看了一些開源的項(xiàng)目以及跟大佬們交流學(xué)習(xí)才知道如何處理這類問題。希望讀者朋友們看完這篇專題后可以有所收獲,如果你對本文有任何疑問或者建議,歡迎留言交流!

【Python專題(二)】Python二三事?mp.weixin.qq.com【Python專題(一)】python環(huán)境搭建?mp.weixin.qq.com

總結(jié)

以上是生活随笔為你收集整理的native.loadlibrary获取路径不对_【Python专题(三)】Python模块导入与路径管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。