" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中import的用法陷阱解決盤點小結(jié)

 更新時間:2023年10月12日 09:52:17   作者:門書生  
這篇文章主要為大家介紹了Python中import的用法陷阱解決盤點小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

Python用了快兩年了吧,其中有些東西一直是稀里糊涂地用,import便是我一直沒有明白的東西。曾經(jīng)有過三次解決它的機會,我都因得過且過、一拖再拖而沒能化敵為友。今天下午,它又給了我一次機會,我想我還是從了它的心愿吧。

故事是從這篇博客(Python 的 Import 陷阱)開始的,然后又跳到了Python社區(qū)的PEP 328提案(PEP 328 -- Imports: Multi-Line and Absolute/Relative),再結(jié)合過去的經(jīng)驗以及一些測試,我想我大概懂了吧。下面是我的總結(jié),希望內(nèi)容能夠言簡意賅、易于理解。

import語句有什么用?

import語句用來導入其他python文件(稱為模塊module),使用該模塊里定義的類、方法或者變量,從而達到代碼復用的目的。為了方便說明,我們用實例來說明import的用法,讀者朋友可以跟著嘗試(嘗試時建議使用python3,python2和python3在import的表現(xiàn)有差異,之后會提到)。

將要建立文件的結(jié)構(gòu)為:

Tree
|____ m1.py
|____ m2.py
|____ Branch
     |____m3.py
     |____m4.py

首先,先建立一個文件夾Tree作為工作目錄,并在其內(nèi)建立兩個文件m1.py和m2.py,在m1.py寫入代碼:

import os
import m2
m2.printSelf()

在m2.py寫入代碼:

def printSelf():
	print('In m2')

打開命令行,進入到Tree目錄下,敲下python m1.py運行,發(fā)現(xiàn)沒有報錯,且打印出In m2,說明這樣使用import沒有問題。由此我們總結(jié)出import語句的第一種用法。

  • import module_name。即import后直接接模塊名。在這種情況下,Python會在兩個地方尋找這個模塊
  • 第一是sys.path(通過運行代碼import sys; print(sys.path)查看),os這個模塊所在的目錄就在列表sys.path中,一般安裝的Python庫的目錄都可以在sys.path中找到(前提是要將Python的安裝目錄添加到電腦的環(huán)境變量),所以對于安裝好的庫,我們直接import即可。
  • 第二個地方就是運行文件(這里是m1.py)所在的目錄,因為m2.py和運行文件在同一目錄下,所以上述寫法沒有問題。

用上述方法導入原有的sys.path中的庫沒有問題。但是,最好不要用上述方法導入同目錄下的文件!因為這可能會出錯。演示這個錯誤需要用到import語句的第二種寫法,所以先來學一學import的第二種寫法。在Tree目錄下新建一個目錄Branch,在Branch中新建文件m3.py,m3.py的內(nèi)容如下:

def printSelf():
	print('In m3')

如何在m1中導入m3.py呢,請看更改后的m1.py:

from Branch import m3
m3.printSelf()

總結(jié)import語句用法

  • from package_name import module_name。一般把模塊組成的集合稱為包(package)。與第一種寫法類似,Python會在sys.path和運行文件目錄這兩個地方尋找包,然后導入包中名為module_name的模塊。

現(xiàn)在我們來說明為什么不要用import的第一種寫法來導入同目錄下的文件。在Branch目錄下新建m4.py文件,m4.py的內(nèi)容如下:

def printSelf():
	print('In m4')

然后我們在m3.py中直接導入m4,m3.py變?yōu)椋?/p>

import m4
def printSelf():
	print('In m3')

這時候運行m1.py就會報錯了,說沒法導入m4模塊。為什么呢?我們來看一下導入流程:m1使用from Branch import m3導入m3,然后在m3.py中用import m4導入m4??闯鰡栴}了嗎?m4.py和m1.py不在同一目錄,怎么能直接使用import m4導入m4呢。(讀者可以試試直接在Tree目錄下新建另一個m4.py文件,你會發(fā)現(xiàn)再運行m1.py就不會出錯了,只不過導入的是第二個m4.py了)

面對上面的錯誤,使用python2運行m1.py就不會報錯,因為在python2中,上面提到的import的兩種寫法都屬于相對導入,而在python3中,卻屬于絕對導入。話說到了這里,就要牽扯到import中最關鍵的部分了——相對導入和絕對導入。

我們還是談論python3的import用法。上面提到的兩種寫法屬于絕對導入,即用于導入sys.path中的包和運行文件所在目錄下的包。對于sys.path中的包,這種寫法毫無問題;導入自己寫的文件,如果是非運行入口文件(上面的m1.py是運行入口文件,可以使用絕對導入),則需要相對導入。

比如對于非運行入口文件m3.py,其導入m4.py需要使用相對導入:

from . import m4
def printSelf():
	print('In m3')

這時候再運行m1.py就ok了。列舉一下相對導入的寫法:

  • from . import module_name。導入和自己同目錄下的模塊。
  • from .package_name import module_name。導入和自己同目錄的包的模塊。
  • from .. import module_name。導入上級目錄的模塊。
  • from ..package_name import module_name。導入位于上級目錄下的包的模塊。
  • 當然還可以有更多的.,每多一個點就多往上一層目錄。

不知道你有沒有留神上面的一句話——“上面的m1.py是運行入口文件,可以使用絕對導入”,這句話是沒問題的,也和我平時的做法一致。那么,運行入口文件可不可以使用相對導入呢?比如m1.py內(nèi)容改成:

from .Branch import m3
m3.printSelf()

答案是可以,但不能用python m1.py命令,而是需要進入到Tree所在的目錄,使用python -m Tree.m1來運行。為什么?關于前者,PEP 328提案中的一段文字好像給出了原因:

Relative imports use a module's _name_ attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to '__main__') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

我不太懂,但是又有一點明白。我們應該見過下面一段代碼:

if __name__ == '__main__':
	main()

意思是如果運行了當前文件,則__name__變量會置為__main__,然后會執(zhí)行main函數(shù),如果當前文件是被其他文件作為模塊導入的話,則__name__為模塊名,不等于__main__,就不會執(zhí)行main函數(shù)。比如對于上述更改后的m1.py,執(zhí)行python m1.py命令后,會報如下錯誤:

Traceback (most recent call last): File "m1.py", line 1, in from .Branch import m3 ModuleNotFoundError: No module named '_main_.Branch'; '__main__' is not a package

據(jù)此我猜測執(zhí)行python m1.py命令后,當前目錄所代表的包'.'變成了__main__。

那為什么python -m Tree.m1就可以呢?那位臺灣老師給出了解釋:

執(zhí)行指令中的-m是為了讓Python預先import你要的package或module給你,然后再執(zhí)行script。

即不把m1.py當作運行入口文件,而是也把它當作被導入的模塊,這就和非運行入口文件有一樣的表現(xiàn)了。

注意,在Tree目錄下運行python -m m1是不可以的,會報 ImportError: attempted relative import with no known parent package的錯誤。因為m1.py中的from .Branch import m3中的. ,解釋器并不知道是哪一個package。使用python -m Tree.m1,解釋器就知道.對應的是Tree這個package。

那反過來,如果m1.py使用絕對導入(from Branch import m3),能使用python -m m1運行嗎?我試了一下,如果當前目錄是Tree就可以。如果在其他目錄下運行,比如在Tree所在的目錄(使用python -m Tree.m1運行),就不可以。這可能還是與絕對導入相關。

(之前看到了一個大型項目,其運行入口文件有一大堆的相對導入,我還傻乎乎地用python直接運行它。之后看到他給的樣例運行命令是帶了-m參數(shù)的?,F(xiàn)在才恍然大悟。)

理解import的難點差不多就這樣了。下面說一說import的其他簡單但實用的用法。

  • import moudle_name as alias。有些module_name比較長,之后寫它時較為麻煩,或者module_name會出現(xiàn)名字沖突,可以用as來給它改名,如import numpy as np。
  • from module_name import function_name, variable_name, class_name。上面導入的都是整個模塊,有時候我們只想使用模塊中的某些函數(shù)、某些變量、某些類,用這種寫法就可以了。使用逗號可以導入模塊中的多個元素。
  • 有時候?qū)氲脑睾芏?,可以使用反斜杠來換行,官方推薦使用括號。
from Tkinter import Tk, Frame, Button, Entry, Canvas, Text, \
    LEFT, DISABLED, NORMAL, RIDGE, END	# 反斜杠換行
from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
    LEFT, DISABLED, NORMAL, RIDGE, END)	# 括號換行(推薦)

說到這感覺import的核心已經(jīng)說完了。再跟著上面的博客說一說使用import可能碰到的問題吧。

import可能碰到的問題

問題1描述:ValueError: attempted relative import beyond top-level package。直面問題的第一步是去了解熟悉它,最好是能復現(xiàn)它,將錯誤暴露在陽光之下。仍然是上面四個文件,稍作修改,四個文件如下:

# m1.py
from Branch import m3
m3.printSelf()
# m2.py
def printSelf():
	print('module2')
# m3.py
from .. import m2 # 復現(xiàn)的關鍵在這 #
print(__name__)
def printSelf():
	print('In m3')
# m4.py
def printSelf():
	print('In m4')

運行python m1.py,就會出現(xiàn)該問題。問題何在?我猜測,運行m1.py后,m1代表的模塊就是頂層模塊(參見上面PEP 328的引用),而m3.py中嘗試導入的m2模塊所在的包(即Tree目錄代表的包)比m1的層級更高,所以會報出這樣的錯誤。怎么解決呢?將m1.py的所有導入改為相對導入,然后進入m1.py的上層目錄,運行python -m Tree.m1即可。

對于使用import出現(xiàn)的其他問題,碰到了再接著更新,更多關于Python import用法的資料請關注腳本之家其它相關文章!

相關文章

  • python通過函數(shù)名調(diào)用函數(shù)的幾種場景

    python通過函數(shù)名調(diào)用函數(shù)的幾種場景

    這篇文章主要介紹了python通過函數(shù)名調(diào)用函數(shù)的幾種場景,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-09-09
  • Python 3.x基礎實戰(zhàn)檢查磁盤可用空間

    Python 3.x基礎實戰(zhàn)檢查磁盤可用空間

    這篇文章主要為大家介紹了Python 3.x基礎實戰(zhàn)之檢查磁盤可用空間實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 深入了解Python中frozenset的功能與用法

    深入了解Python中frozenset的功能與用法

    在Python中,frozenset是一種與set類似的數(shù)據(jù)類型,但具有不可變性,本文將詳細介紹frozenset的作用、用法以及與set的區(qū)別,感興趣的可以了解下
    2024-01-01
  • Python私有pypi源注冊自定義依賴包Windows詳解

    Python私有pypi源注冊自定義依賴包Windows詳解

    這篇文章主要介紹了Python私有pypi源注冊自定義依賴包Windows,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Python 實現(xiàn)Serial 與STM32J進行串口通訊

    Python 實現(xiàn)Serial 與STM32J進行串口通訊

    今天小編就為大家分享一篇Python 實現(xiàn)Serial 與STM32J進行串口通訊,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python初學者必備的文件讀寫指南

    Python初學者必備的文件讀寫指南

    今天給大家?guī)淼氖顷P于Python基礎的相關知識,文章圍繞著Python文件讀寫展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Pyqt5 基本界面組件之inputDialog的使用

    Pyqt5 基本界面組件之inputDialog的使用

    今天小編就為大家分享一篇Pyqt5 基本界面組件之inputDialog的使用,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Django項目中動態(tài)設置靜態(tài)文件路徑的全過程

    Django項目中動態(tài)設置靜態(tài)文件路徑的全過程

    這篇文章主要給大家介紹了關于Django項目中動態(tài)設置靜態(tài)文件路徑的相關資料,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2022-02-02
  • python中正則表達式?: ?= ?! 的用法

    python中正則表達式?: ?= ?! 的用法

    正則表達式中使用的??:、?=?和??!?是三種不同的正則表達式語法,它們分別代表非捕獲組、正向前瞻斷言和負向前瞻斷言,下面就來介紹一下這三種的方法,感興趣的可以了解一下
    2025-04-04
  • Python查找多個字典公共鍵key的方法

    Python查找多個字典公共鍵key的方法

    這篇文章主要介紹了Python查找多個字典公共鍵key案例,文章主要通過案例分享展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-04-04

最新評論