深度之眼 - Python學習筆記——第八章 文件、異常和模塊

第八章 文件、異常和模塊

實際應用中,我們絕大多數的數據都是通過文件的交互完成的

8.1 文件的讀寫

8.1.1 文件的打開

  • 文件的打開通用格式
with open("文件路徑", "打開模式", encoding = "操作文件的字符編碼") as f:
    "對文件進行相應的讀寫操作"
使用with 塊的好處:執行完畢後,自動對文件進行close操作。

【例1】一個簡單的文件讀取

with open("E:\ipython\測試文件.txt", "r", encoding = "gbk") as f:     # 第一步:打開文件
    text = f.read()                                                   # 第二步:讀取文件
    print(text)
我是一個測試文件

1、文件路徑

  • 完整路徑,如上例所示

  • 程序與文件在同一文件夾,可簡化成文件名

with open("測試文件.txt", "r", encoding = "gbk") as f:     # 第一步:打開文件
    text = f.read()                                        # 第二步:讀取文件
    print(text)
我是一個測試文件

2、打開模式

  • “r”  只讀模式,如文件不存在,報錯

  • “w” 覆蓋寫模式,如文件不存在,則創建;如文件存在,則完全覆蓋原文件

  • “x” 創建寫模式,如文件不存在,則創建;如文件存在,報錯

  • “a”  追加寫模式,如文件不存在,則創建;如文件存在,則在原文件後追加內容

  • “b” 二進制文件模式,不能單獨使用,需要配合使用如"rb",“wb”,“ab”,該模式不需指定encoding

  • “t” 文本文件模式,默認值,需配合使用 如"rt",“wt”,“at”,一般省略,簡寫成如"r",“w”,“a”

  • “+”,與"r",“w”,“x”,"a"配合使用,在原功能基礎上,增加讀寫功能

  • 打開模式缺省,默認爲只讀模式

3、字符編碼

  • 萬國碼 utf-8

包含全世界所有國家需要用到的字符

  • 中文編碼 gbk

專門解決中文編碼問題

  • windows系統下,如果缺省,則默認爲gbk(所在區域的編碼)

  • 爲清楚起見,除了處理二進制文件,建議不要缺省encoding

8.1.2 文件的讀取

1、讀取整個內容——f.read()

with open("三國演義片頭曲_utf.txt", "r", encoding="utf-8") as f:       # 第一步:打開文件
    text = f.read()                                                    # 第二步:讀取文件
    print(text)
臨江仙·滾滾長江東逝水
滾滾長江東逝水,浪花淘盡英雄。
是非成敗轉頭空。
青山依舊在,幾度夕陽紅。
白髮漁樵江渚上,慣看秋月春風。
一壺濁酒喜相逢。
古今多少事,都付笑談中。

with open("三國演義片頭曲_utf.txt", encoding="utf-8") as f:     # "r",可缺省,爲清晰起見,最好寫上
    text = f.read()                                                   
    print(text)
臨江仙·滾滾長江東逝水
滾滾長江東逝水,浪花淘盡英雄。
是非成敗轉頭空。
青山依舊在,幾度夕陽紅。
白髮漁樵江渚上,慣看秋月春風。
一壺濁酒喜相逢。
古今多少事,都付笑談中。

  • 解碼模式不匹配
with open("三國演義片頭曲_utf.txt", "r", encoding="gbk") as f:     
    text = f.read()                                                    
    print(text)
---------------------------------------------------------------------------

UnicodeDecodeError                        Traceback (most recent call last)

<ipython-input-6-8e9ea685585d> in <module>
      1 with open("三國演義片頭曲_utf.txt", "r", encoding="gbk") as f:
----> 2     text = f.read()
      3     print(text)
UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 50: illegal multibyte sequence      
with open("三國演義片頭曲_utf.txt", "r") as f:     # encoding缺省,windows系統默認爲"gbk"
    text = f.read()                                                    
    print(text)
---------------------------------------------------------------------------

UnicodeDecodeError                        Traceback (most recent call last)

<ipython-input-7-480622bc01aa> in <module>
      1 with open("三國演義片頭曲_utf.txt", "r") as f:     # encoding缺省,windows系統默認爲"gbk"
----> 2     text = f.read()
      3     print(text)
UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 50: illegal multibyte sequence

2、逐行進行讀取——f.readline()

with open("三國演義片頭曲_gbk.txt", "r", encoding="gbk") as f:     
    for i in range(3):
        text = f.readline()                                                   # 每次只讀取一行
        print(text)
臨江仙·滾滾長江東逝水

滾滾長江東逝水,浪花淘盡英雄。

是非成敗轉頭空。

with open("三國演義片頭曲_gbk.txt", "r", encoding="gbk") as f:     
    while True:
        text = f.readline()
        if not text:
            # print(text is "")
            break
        else:
            # print(text == "\n")
            print(text, end="")      # 保留原文的換行,使print()的換行不起作用
臨江仙·滾滾長江東逝水
滾滾長江東逝水,浪花淘盡英雄。
是非成敗轉頭空。

青山依舊在,幾度夕陽紅。
白髮漁樵江渚上,慣看秋月春風。
一壺濁酒喜相逢。
古今多少事,都付笑談中。

3、讀入所有行,以每行爲元素 形成一個列表——f.readlines()

with open("三國演義片頭曲_gbk.txt", "r", encoding="gbk") as f:
    text = f.readlines()              # 注意每行末尾有換行符
    print(text)               
['臨江仙·滾滾長江東逝水\n', '滾滾長江東逝水,浪花淘盡英雄。\n', '是非成敗轉頭空。\n', '\n', '青山依舊在,幾度夕陽紅。\n', '白髮漁樵江渚上,慣看秋月春風。\n', '一壺濁酒喜相逢。\n', '古今多少事,都付笑談中。\n']
with open("三國演義片頭曲_gbk.txt", "r", encoding="gbk") as f:     
    for text in f.readlines():                                                   
        print(text)                # 不想換行則用print(text, end="")         
臨江仙·滾滾長江東逝水

滾滾長江東逝水,浪花淘盡英雄。

是非成敗轉頭空。



青山依舊在,幾度夕陽紅。

白髮漁樵江渚上,慣看秋月春風。

一壺濁酒喜相逢。

古今多少事,都付笑談中。

4、文本文件讀取小結

文件比較大時,read()和readlines()佔用內存過大,不建議使用

readline用起來又不太方便

with open("三國演義片頭曲_gbk.txt", "r", encoding="gbk") as f:     
    for text in f:         # f本身就是一個可迭代對象,每次迭代讀取一行內容 
        print(text)  
臨江仙·滾滾長江東逝水

滾滾長江東逝水,浪花淘盡英雄。

是非成敗轉頭空。



青山依舊在,幾度夕陽紅。

白髮漁樵江渚上,慣看秋月春風。

一壺濁酒喜相逢。

古今多少事,都付笑談中。

5、二進制文件

圖片:二進制文件

with open("test.jpg", "rb") as f:     
        print(len(f.readlines()))
69

8.1.3 文件的寫入

1、向文件寫入一個字符串或字節流(二進制)——f.write()

with open("第九套廣播體操.txt", "w", encoding="utf-8") as f:                      
        f.write("大家好\n")        # 文件不存在則立刻創建一個
        f.write("歡迎一起做體操\n")        # 如需換行,末尾加換行符\n
        f.write("第一節\n")
        f.write("頭部運動\n")
with open("第九套廣播體操.txt", "w", encoding="utf-8") as f:                      
        f.write("第二節\n")        # 如果文件存在,新寫入內容會覆蓋掉原內容,一定要注意!!!
        f.write("伸展運動\n")        
        f.write("12345678\n")
        f.write("22345678\n")

2、追加模式——"a"

with open("第九套廣播體操.txt", "a", encoding="utf-8") as f:                      
        f.write("第三節\n")        # 如果文件存在,新寫入內容會覆蓋掉原內容,一定要注意!!!
        f.write("腰部運動\n")        
        f.write("12345678\n")
        f.write("22345678\n")

3、將一個元素爲字符串的列表整體寫入文件——f.writelines()

ls = ["春天颳着風", "秋天下着雨", "我們要運動"]
with open("第九套廣播體操.txt", "w", encoding="utf-8") as f:
    f.writelines(ls)
ls = ["春天颳着風\n", "秋天下着雨\n", "我們要運動\n"]
with open("第九套廣播體操.txt", "w", encoding="utf-8") as f:
    f.writelines(ls)

8.1.4 既讀又寫

1、"r+"

  • 如果文件名不存在,則報錯
  • 指針在開始
  • 要把指針移到末尾才能開始寫,否則會覆蓋前面內容
with open("浪淘沙_北戴河.txt", "r+", encoding="gbk") as f:
#     for line in f:
#         print(line)   # 全部讀一遍後,指針到達結尾
    f.seek(0,2)         # 或者可以將指針移到末尾f.seek(偏移字節數,位置(0:開始;1:當前位置;2:結尾))
    text = ["蕭瑟秋風今又是,\n", "換了人間。\n"]
    f.writelines(text)

2、"w+"

  • 若文件不存在,則創建
  • 若文件存在,會立刻清空原內容!!!
with open("浪淘沙_北戴河.txt", "w+", encoding="gbk") as f:
    pass
with open("浪淘沙_北戴河.txt", "w+", encoding="gbk") as f:
    text = ["蕭瑟秋風今又是,\n", "換了人間。\n"]  # 清空原內容
    f.writelines(text)                             # 寫入新內容,指針在最後
    f.seek(0,0)            # 指針移到開始
    print(f.read())        # 讀取內容

3、"a+"

  • 若文件不存在,則創建
  • 指針在末尾,添加新內容,不會清空原內容
with open("浪淘沙_北戴河.txt", "a+", encoding="gbk") as f:
    f.seek(0,0)            # 指針移到開始
    print(f.read())        # 讀取內容
大雨落幽燕,
白浪滔天。
秦皇島外打魚船。
一片汪洋都不見,
知向誰邊?
往事越千年,
魏武揮鞭,
東臨碣石有遺篇。
蕭瑟秋風今又是,
換了人間。
with open("浪淘沙_北戴河.txt", "a+", encoding="gbk") as f:
    text = ["蕭瑟秋風今又是,\n", "換了人間。\n"]  
    f.writelines(text)                             # 指針在最後,追加新內容, 
    f.seek(0,0)            # 指針移到開始
    print(f.read())        # 讀取內容
大雨落幽燕,
白浪滔天。
秦皇島外打魚船。
一片汪洋都不見,
知向誰邊?
往事越千年,
魏武揮鞭,
東臨碣石有遺篇。
蕭瑟秋風今又是,
換了人間。
蕭瑟秋風今又是,
換了人間。

8.1.5 數據的存儲與讀取

通用的數據格式,可以在不同語言中加載和存儲

本節簡單瞭解兩種數據存儲結構csv和json

1、csv格式

由逗號將數據分開的字符序列,可以由excel打開

  • 讀取
with open("成績.csv", "r", encoding="gbk") as f:
    ls = [] 
    for line in f:                              # 逐行讀取
        ls.append(line.strip("\n").split(","))  # 去掉每行的換行符,然後用“,”進行分割
for res in ls:
    print(res)
['編號', '數學成績', '語文成績']
['1', '100', '98']
['2', '96', '99']
['3', '97', '95']
  • 寫入
ls = [['編號', '數學成績', '語文成績'], ['1', '100', '98'], ['2', '96', '99'], ['3', '97', '95']]
with open("score.csv", "w", encoding="gbk") as f:   # encoding="utf-8"中文出現亂碼
    for row in ls:                                  # 逐行寫入
        f.write(",".join(row)+"\n")                 # 用逗號組合成字符串形式,末尾加換行符

也可以藉助csv模塊完成上述操作

2、json格式

常被用來存儲字典類型

  • 寫入——dump()
import json

scores = {"Petter":{"math":96 , "physics": 98},
        "Paul":{"math":92 , "physics": 99},
        "Mary":{"math":98 , "physics": 97}}
with open("score.json", "w", encoding="utf-8") as f:             # 寫入整個對象 
        # indent 表示字符串換行+縮進 ensure_ascii=False 顯示中文
        json.dump(scores, f, indent=4, ensure_ascii=False)       
        
  • 讀取——load()
with open("score.json", "r", encoding="utf-8") as f:                                         
        scores = json.load(f)           # 加載整個對象
        for k,v in scores.items():
            print(k,v)
Petter {'math': 96, 'physics': 98}
Paul {'math': 92, 'physics': 99}
Mary {'math': 98, 'physics': 97}

8.2 異常處理

8.2.1 常見異常的產生

1、除0運算——ZeroDivisionError

1/0
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-1-9e1622b385b6> in <module>
----> 1 1/0


ZeroDivisionError: division by zero

2、找不到可讀文件——FileNotFoundError

with open("nobody.csv") as f:
    pass
---------------------------------------------------------------------------

FileNotFoundError                         Traceback (most recent call last)

<ipython-input-2-f2e8c7d0ac60> in <module>
----> 1 with open("nobody.csv") as f:
      2     pass


FileNotFoundError: [Errno 2] No such file or directory: 'nobody.csv'

3、值錯誤——ValueError

傳入一個調用者不期望的值,即使這個值的類型是正確的

s = "1.3"
n = int(s)
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-8-69942d9db3c0> in <module>
      1 s = "1.3"
----> 2 n = int(s)


ValueError: invalid literal for int() with base 10: '1.3'

4、索引錯誤——IndexError

下標超出序列邊界

ls = [1, 2, 3]
ls[5]
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-9-acf459124b52> in <module>
      1 ls = [1, 2, 3]
----> 2 ls[5]


IndexError: list index out of range

5、類型錯誤——TypeError

傳入對象類型與要求不符

1 + "3"
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-10-ee505dc42f75> in <module>
----> 1 1 + "3"
TypeError: unsupported operand type(s) for +: 'int' and 'str'

6、其他常見的異常類型

NameError 使用一個未被定義的變量
KeyError 試圖訪問字典裏不存在的鍵

print(a)
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-11-bca0e2660b9f> in <module>
----> 1 print(a)
NameError: name 'a' is not defined
d = {}
d["1"]
---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)

<ipython-input-12-e629d551aca0> in <module>
      1 d = {}
----> 2 d["1"]
KeyError: '1'

當異常發生的時候,如果不預先設定處理方法,程序就會中斷

8.2.2 異常的處理

提高程序的穩定性和可靠性

1、try_except

  • 如果try內代碼塊順利執行,except不被觸發

  • 如果try內代碼塊發生錯誤,觸發except,執行except內代碼塊

  • 單分支

x = 10
y = 0
try:
    z = x/y
except ZeroDivisionError:                  # 一般來說會預判到出現什麼錯誤
    # z = x/(y+1e-7)
    # print(z)
    print("0不可以被除!")    
0不可以被除!
x = 10
y = 0
try:
    z = x/y
except NameError:                  # 一般來說會預判到出現什麼錯誤
    # z = x/(y+1e-7)
    # print(z)
    print("0不可以被除!")   
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-14-aea58863ad72> in <module>
      2 y = 0
      3 try:
----> 4     z = x/y
      5 except NameError:                  # 一般來說會預判到出現什麼錯誤
      6     # z = x/(y+1e-7)
ZeroDivisionError: division by zero
  • 多分支
ls = []
d = {"name": "Faye"}
try:
    y = m
    # ls[3]
    # d["age"]
except NameError:
    print("變量名不存在")
except IndexError:
    print("索引超出界限")
except KeyError:
    print("鍵不存在")
變量名不存在
  • 萬能異常 Exception (所有錯誤的老祖宗)
ls = []
d = {"name": "Faye"}
try:
    # y = m
    ls[3]
    # d["age"]
except Exception:
    print("出錯啦")
出錯啦
  • 捕獲異常的值 as
ls = []
d = {"name": "Faye"}
# y = x
try:
    y = m
    # ls[3]
    # d["age"]
except Exception as e:    # 雖不能獲得錯誤具體類型,但可以獲得錯誤的值
    print(e)
name 'm' is not defined

2、try_except_else

  • 如果try 模塊執行,則else模塊也執行

可以將else 看做try成功的額外獎賞

try:
    with open("浪淘沙_北戴河.txt") as f:
        text = f.read()
except FileNotFoundError:
    print("找不到該文件,ta是不是用了美顏?")
else:
    for s in ["\n", ",", "。", "?"]:         # 去掉換行符和標點符號
        text = text.replace(s, "")
    print("名作《浪淘沙_北戴河》共由{}個字組成。".format(len(text)))
名作《浪淘沙_北戴河》共由65個字組成。

3、try_except_finally

  • 不論try模塊是否執行,finally最後都執行
ls = []
d = {"name": "Faye"}
# y = x
try:
    y = m
    # ls[3]
    # d["age"]
except Exception as e:    # 雖不能獲得錯誤具體類型,但可以獲得錯誤的值
    print(e)
finally:
    print("不論觸不觸發異常,都將執行")
name 'm' is not defined
不論觸不觸發異常,都將執行

8.3 模塊簡介

已經被封裝好

無需自己再“造輪子”

聲明導入後,拿來即用

8.3.1 廣義模塊分類

1、Python 內置

 時間庫time\  隨機庫random\  容器數據類型collection\  迭代器函數itertools

2、第三方庫

 數據分析numpy、pandas\  數據可視化matplotlib\  機器學習scikit-learn\  深度學習Tensorflow

3、自定義文件

  • 單獨py文件

  • 包——多個py文件

# 文件夾內多個py文件,再加一個__init__.py文件(內容可爲空)

8.3.2 模塊的導入

1、導入整個模塊——import 模塊名

  • **調用方式:**模塊名.函數名或類名
import time

start = time.time()      # 調用time模塊中的time()
time.sleep(3)            # 調用time模塊中的sleep()  休息3秒鐘
end = time.time()       
print("程序運行用時:{:.2f}秒".format(end-start))
程序運行用時:3.00秒
import fun1

fun1.f1()
導入fun1成功

2、從模塊中導入類或函數——from 模塊 import 類名或函數名

  • **調用方式:**函數名或類名
from itertools import product   

ls = list(product("AB", "123"))
print(ls)
[('A', '1'), ('A', '2'), ('A', '3'), ('B', '1'), ('B', '2'), ('B', '3')]
from function.fun1 import f1         # 注意這種用法

f1()
導入fun1成功

一次導入多個

from function import fun1, fun2

fun1.f1()
fun2.f2()
導入fun1成功
導入fun2成功

3、導入模塊中所有的類和函數——from 模塊 import *

  • **調用方式:**函數名或類名
from random import * 

print(randint(1,100))       # 產生一個[1,100]之間的隨機整數
print(random())             # 產生一個[0,1)之間的隨機小數
36
0.6582485822110181

8.3.3 模塊的查找路徑

模塊搜索查找順序:

  • 1、內存中已經加載的模塊
import fun1

fun1.f1()
導入fun1成功
# 刪除硬盤上的fun1文件後再次執行
import fun1

fun1.f1()
導入fun1成功
# 修改硬盤上的fun1 文件
import fun1

fun1.f1()
# 居然沒變,說明是優先從內存中讀取的
導入fun1成功
  • 2、內置模塊
# Python 啓動時,解釋器會默認加載一些 modules 存放在sys.modules中
# sys.modules 變量包含一個由當前載入(完整且成功導入)到解釋器的模塊組成的字典, 模塊名作爲鍵, 它們的位置作爲值
import sys

print(len(sys.modules))
print("math" in sys.modules)
print("numpy" in sys.modules)
for k,v in list(sys.modules.items())[:20]:
    print(k, ":", v)
738
True
False
sys : <module 'sys' (built-in)>
builtins : <module 'builtins' (built-in)>
_frozen_importlib : <module 'importlib._bootstrap' (frozen)>
_imp : <module '_imp' (built-in)>
_thread : <module '_thread' (built-in)>
_warnings : <module '_warnings' (built-in)>
_weakref : <module '_weakref' (built-in)>
zipimport : <module 'zipimport' (built-in)>
_frozen_importlib_external : <module 'importlib._bootstrap_external' (frozen)>
_io : <module 'io' (built-in)>
marshal : <module 'marshal' (built-in)>
nt : <module 'nt' (built-in)>
winreg : <module 'winreg' (built-in)>
encodings : <module 'encodings' from 'C:\\Users\\ibm\\Anaconda3\\lib\\encodings\\__init__.py'>
codecs : <module 'codecs' from 'C:\\Users\\ibm\\Anaconda3\\lib\\codecs.py'>
_codecs : <module '_codecs' (built-in)>
encodings.aliases : <module 'encodings.aliases' from 'C:\\Users\\ibm\\Anaconda3\\lib\\encodings\\aliases.py'>
encodings.utf_8 : <module 'encodings.utf_8' from 'C:\\Users\\ibm\\Anaconda3\\lib\\encodings\\utf_8.py'>
_signal : <module '_signal' (built-in)>
__main__ : <module '__main__'>
  • 3、sys.path路徑中包含的模塊
import sys

sys.path
['E:\\ipython',
 'C:\\Users\\ibm\\Anaconda3\\python37.zip',
 'C:\\Users\\ibm\\Anaconda3\\DLLs',
 'C:\\Users\\ibm\\Anaconda3\\lib',
 'C:\\Users\\ibm\\Anaconda3',
 '',
 'C:\\Users\\ibm\\AppData\\Roaming\\Python\\Python37\\site-packages',
 'C:\\Users\\ibm\\Anaconda3\\lib\\site-packages',
 'C:\\Users\\ibm\\Anaconda3\\lib\\site-packages\\win32',
 'C:\\Users\\ibm\\Anaconda3\\lib\\site-packages\\win32\\lib',
 'C:\\Users\\ibm\\Anaconda3\\lib\\site-packages\\Pythonwin',
 'C:\\Users\\ibm\\Anaconda3\\lib\\site-packages\\IPython\\extensions',
 'C:\\Users\\ibm\\.ipython']
  • sys.path的第一個路徑是當前執行文件所在的文件夾
  • 若需將不在該文件夾內的模塊導入,需要將模塊的路徑添加到sys.path
# import fun3
import sys

sys.path.append("C:\\Users\\ibm\\Desktop")    # 注意是雙斜槓

import fun3

fun3.f3()
導入fun3成功
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章