Python 中的 import 與 from import 到底啥意思?

2021-02-13 TOP程式設計師

對不少 Python 初學者來說,Python 導入其他模塊的方式讓他們很難理解。什麼時候用import xxx?什麼時候用from xxx import yyy?什麼時候用from xxx.yyy import zzz?什麼時候用from xxx import *?

這篇文章,我們來徹底搞懂這個問題。

系統自帶的模塊

以正則表達式模塊為例,我們經常這樣寫代碼:

import re

target = 'abc1234xyz'
re.search('(\d+)', target)

但有時候,你可能會看到某些人這樣寫代碼:

from re import search
target = 'abc1234xyz'
search('(\d+)', target)

那麼這兩種導入方式有什麼區別呢?

我們分別使用type函數來看看他們的類型:

>>> import re
>>> type(re)
<class 'module'>
>>> from re import search
>>> type(search)
<class 'function'>

如下圖所示:

可以看到,直接使用import re導入的re它是一個module類,也就是模塊。我們把它成為正則表達式模塊。而當我們from re import search時,這個search是一個function類,我們稱呼它為search 函數。

一個模塊裡面可以包含多個函數。

如果在你的代碼裡面,你已經確定只使用search函數,不會再使用正則表達式裡面的其他函數了,那麼你使用兩種方法都可以,沒什麼區別。

但是,如果你要使用正則表達式下面的多個函數,或者是一些常量,那麼用第一種方案會更加簡潔清晰。

例如:

import re

re.search('c(.*?)x', flags=re.S)
re.sub('[a-zA-Z0-9]', '***', target, flags=re.I)

在這個例子中,你分別使用了re.search,re.sub,re.S和re.I。後兩者是常量,用於忽略換行符和大小寫。

但是,如果你使用from re import search, sub, S, I來寫代碼,那麼代碼就會變成這樣:

import re

search('c(.*?)x', flags=S)
sub('[a-zA-Z0-9]', '***', target, flags=I)

看起來雖然簡潔了,但是,一旦你的代碼行數多了以後,你很容易忘記S和I這兩個變量是什麼東西。而且我們自己定義的函數,也很有可能取名為sub或者search,從而覆蓋正則表達式模塊下面的這兩個同名函數。這就會導致很多難以覺察的潛在 bug。

再舉一個例子。Python 的 datetime模塊,我們可以直接import datetime,此時我們導入的是一個datetime模塊,如下圖所示:

但是如果你寫為from datetime import datetime,那麼你導入的datetime是一個type類:

因為這種方式導入的datetime,它就是Python 中的一種類型,用於表示包含日期和時間的數據。

這兩種導入方式導入的datetime,雖然名字一樣,但是他們的意義完全不一樣,請大家觀察下面兩種寫法:

import datetime

now = datetime.datetime.now()
one_hour_ago = now - datetime.timedelta(hours=1)

from datetime import datetime, timedelta
now = datetime.now()
one_hour_ago = now - timedelta(hours=1)

第二種寫法看似簡單,但實則改動起來卻更為麻煩。例如我還需要增加一個變量today用於記錄今日的日期。

對於第一段代碼,我們只需要增加一行即可:

today = datetime.date.today()

但對於第二行來說,我們需要首先修改導入部分的代碼:

from datetime import datetime, timedelta, date

然後才能改代碼:today = date.today()

這樣一來你就要修改兩個地方,反倒增加了負擔。

第三方庫

在使用某些第三方庫的代碼裡面,我們會看到類似這樣的寫法:

 from lxml.html import fromstring

selector = fromstring(HTML)

但是我們還可以寫為:

from lxml import html

selector = html.fromstring(HTML)

但是,下面這種寫法會導致報錯:

import lxml
selector = lxml.html.fromstring(HTML)

那麼這裡的lxml.html又是什麼東西呢?

這種情況多常見於一些特別大型的第三方庫中,這種庫能處理多種類型的數據。例如lxml它既能處理xml的數據,又能處理html的數據,於是這種庫會劃分子模塊,lxml.html模塊專門負責html相關的數據。

自己來實現多種導入方法

我們現在自己來寫代碼,實現這多種導入方法。

我們創建一個文件夾DocParser,在裡面分別創建兩個文件main.py和util.py,他們的內容如下:

util.py文件:

def write():
print('write 函數被調用!')

main.py文件:

import util

util.write()

運行效果如下圖所示:

現在我們把main.py的導入方式修改一下:

from util import write

write()

依然正常運行,如下圖所示

當兩個文件在同一個文件夾下面,並且該文件夾裡面沒有__init__.py 文件時,兩種導入方式等價。

現在,我們來創建一個文件夾microsoft,裡面再添加一個文件parse.py:

def read():
print('我是 microsoft 文件夾下面的 parse.py 中的 read函數')

如下圖所示:

此時我們在 main.py中對它進行調用:

from microsoft import parse

parse.read()

運行效果如下圖所示:

我們也可以用另一種方法:

from microsoft.parse import read

read()

運行效果如下圖所示:

但是,你不能直接導入microsoft,如下圖所示:

你只能導入一個模塊或者導入一個函數或者類,你不能導入一個文件夾

無論你使用的是import xxx還是from xxx.yyy.zzz.www import qqq,你導入進來的東西,要不就是一個模塊(對應到.py 文件的文件名),或者是某個.py 文件中的函數名、類名、變量名。

無論是import xxx還是from xxx import yyy,你導入進來的都不能是一個文件夾的名字。

可能有這樣一種情況,就是某個函數名與文件的名字相同,例如:

在 microsoft文件夾裡面有一個microsoft.py文件,這個文件裡面有一個函數叫做microsoft,那麼你的代碼可以寫為:

from microsoft import microsoft`
microsoft.microsoft()

但請注意分辨,這裡你導入的還是模塊,只不過microsoft.py文件名與它所在的文件夾名恰好相同而已。

總結

無論是使用import還是from import,第一個要求是代碼能夠正常運行,其次,根據代碼維護性,團隊編碼風格來確定選擇哪一種方案。

如果我們只會使用到某個模塊下面的一個函數(或者常量、類)並且名字不會產生混淆,可識別性高,那麼from 模塊名 import 函數名這沒有什麼問題。

如果我們會用到一個模塊下面的多個函數,或者是我們將要使用的函數名、常量名、類名可能會讓人產生混淆(例如 re.S、re.I),那麼這種情況下,import 模塊名然後再 模塊名.xxx來調用會讓代碼更加清晰,更好維護。

但無論什麼情況下,都禁止使用from xxx import *這種寫法,它會給你帶來無窮無盡的噩夢。

未完待續

在明天的文章中,我們來講講還有一種寫法from . import xxx,以及當文件夾中存在__init__.py時,導入方式又有什麼變化。

相關焦點

  • python基礎--自定義模塊、import、from......import......
    3)import使用1.import使用import 翻譯過來是一個導入的意思。這裡一定要給同學強調那個文件執行文件,和哪個文件是被執行模塊。與import對比唯一的區別就是:使用from...import...則是將spam中的名字直接導入到當前的名稱空間中,所以在當前名稱空間中,直接使用名字就可以了、無需加前綴:tbjx.
  • Python中from import和import的區別?沒有比這更好的回答了
    from import 和 import有什麼區別?問題解答import Module # 引入模塊from Module import Other # 引入模塊中的類、函數或者變量from Module import * # 引入模塊中的所有
  • 徹底搞懂Python 中的 import 與 from import
    什麼時候用import xxx?什麼時候用from xxx import yyy?什麼時候用from xxx.yyy import zzz?什麼時候用from xxx import *?這篇文章,我們來徹底搞懂這個問題。
  • 詳解Python中的import的用法
    在Tree目錄下新建一個目錄Branch,在Branch中新建文件m3.py,m3.py的內容如下:defprintSelf(): print('In m3')如何在m1中導入m3.py呢,請看更改後的m1.py:from Branch import m3m3.
  • Python入門基礎之導入問題:from import 與import 詳解
    在python中導入模塊絕對是我們最最常用的功能,基本每個py文件中都會有import或者是from import語句。可是,這兩種導入方法有什麼不同,又該怎麼用呢?今天就好好來分析一下。Import 和from是賦值語句像def一樣,import和from是可執行的語句,他們可以出現在if中,可以出現在函數中,執行到這些語句的時候才會進行解析,也就是說,被導入的模塊和變量名只有在對應的import或from語句執行後才可以使用。
  • python 模塊相互import
    這個在Python列表中由RobertChen給出了詳細解釋,抄錄如下:[A.py]  from B import D  class C:pass  [B.py]  from A import C  class D:pass為什麼執行A的時候不能加載D呢?
  • 詳解Python import機制(上):import中的基本概念
    作者 |  ayuliao來源 | hackpython(ID: hackpython)簡介簡單來看,import機制可以導入我們需要使用的庫,避免代碼重複,使用方便,可謂是編寫Python時最常使用寫法,但我們了解import嗎?
  • 學了半天,import 到底在幹啥?
    查找是否已導入同名模塊首先,Python會按照import xxx中指定的包名,到sys.modules中查找當前環境中是否已經存在相應的包——不要奇怪為什麼都沒有導入sys這個模塊就有sys.modules了。
  • 深入探討 Python 的 import 機制
    1.2 相對/絕對對導入當我們 import 導入模塊或包時,Python 提供兩種導入方式:相對導入(relative import ):import foo.bar 或者 form foo import bar絕對導入(absolute import):from . import B 或 from ..A import B,其中.表示當前模塊,..表示上層模塊
  • Python import 導入上一級模塊
    1.導入同級模塊python導入同級模塊(在同一個文件夾中的py文件)直接導入即可。import xxx如在file1.py中想導入file2.py,注意無需加後綴".py":import file2# 使用file2中函數時需加上前綴"file2."
  • 你對Python裡的import一無所知
    from ... import ... as ...一般情況下,使用 import 語句導入模塊已經夠用的。但是在一些特殊場景中,可能還需要其他的導入方式。下面我會一一地給你介紹。2. 使用 __import__ __import__ 函數可用於導入模塊,import 語句也會調用函數。
  • 詳解Python import機制(一):import中的基本概念
    Python 版本中實現,此前只有「常規包」這一種包。imp_SixMetaPathImporter at 0x10f43e860>]import形式import 主要有兩種形式1.import xxx2.from xxx import xxx可以看到下面的例子:In [1]: import osIn [2]: from os.path import
  • 初窺 Python 的 import 機制
    作者:pwwang一、前言 本文基於開源項目:https://github.com/pwwang/python-import-system補充擴展講解,希望能夠讓讀者一文搞懂 Python 的 import
  • 如何 Import 自定義的 Python 模塊?
    經常要用的功能能不能像導入python模塊一樣,通過import導入呢?背景在實際的工作過程中,經常會用到一個功能,如果每次編寫代碼的時候都進行重新編寫或者打開已經編寫好的函數進行複製粘貼,這樣就顯得很麻煩,有沒有什麼方法可以像導入python模塊的那樣,直接把要用的函數以模塊名+方法的形式調用呢?
  • Python Import 機制與拓展——劉暢@PyCon 2015 China
    在真正的將python應用到實際的項目中,你會遇到一些無法避免的問題。最讓人困惑不解的問題有二類,一個 編碼問題,另一個則是引用問題。本文主要討論關於Python中import的機制、實現、以及介紹一些有意思的Python Hooks。
  • Python 的 import 居然這麼有料
    一、前言 本文基於開源項目:https://github.com/pwwang/python-import-system補充擴展講解,希望能夠讓讀者一文搞懂 Python 的 import 機制。1.1 什麼是 import 機制?
  • 1 小時逼瘋面試者:聊聊 Python Import System?
    os  import pandas    print(os)  # <module 'os' from 'C:\\python38\\lib\\os.py'>  print(pandas)  # <module 'pandas' from 'C:\\python38\\lib\\site-packages\\pandas\\__init__.py'
  • Python ImportError 解決思路
    辛辛苦苦安裝完了python3.8,最後再運行的時候會出現ImportError: No module named configparser的報錯,參考了很多資料,未能解決問題,後來突然想到原來之前安裝過python2.7版本,對於python來說2.x版本與3.x版本中模塊的名稱是不一樣的
  • 《面試官一個小時逼瘋面試者》之聊聊Python Import System?
    import pandasprint(os)  # <module 'os' from 'C:\\python38\\lib\\os.py'>print(pandas)  # <module 'pandas' from 'C:\\python38\\lib\\site-packages\\pandas\\__init__.py'>
  • Python模塊import本質是什麼?
    如果你寫過自定義的模塊或包,你應該會發現import只會在第一次發生,如果修改代碼需要通過reload來強制加載模塊,這其中可以理解為Python在import的時候進行了動態加載機制將模塊加載到內存當中,我們可以通過sys.modules來查看當前執行環境的內存中已經存在的模塊,那如果理解成只要在sys.modules中已經加載過的模塊是否就不需要import了呢?