hand first python 選讀(2)

文件讀取與異常

文件讀取與判斷

os模塊是調用來處理文件的。html

先從最原始的讀取txt文件開始吧!python

新建一個aaa.txt文檔,鍵入以下英文名篇:app

Li Lei:"Hello,Han Meimei."
Han Meimei:"Hi,Li Lei.How are you?"
Li Lei:"I am fine,thank you.And you?"

同目錄下建立一個新的file.py文檔函數

import os
os.getcwd()

data=open('aaa.txt')
# 打開文件
print(data.readline(),end='')
# 讀取文件
print(data.readline(), end='')

data.seek(0)
# 又回到最初的起點

for line in data:
    print(line,end='')

結果以下測試

若是文件不存在怎麼辦?code

import os

if os.path.exists('aaa.txt'):
    # 業務代碼
else:
    print('error:the file is not existed.')

split切分

如今咱們要把這個橋段轉化爲第三人稱的形式htm

for line in data:
    (role,spoken)=line.split(':')
    print(role,end='')
    print(' said:',end='')
    print(spoken,end='')

這裏是個極其簡單對話區分。若是我把對話稍微複雜點對象

。。。

Han Meimei:"There is a question:shall we go to the bed together?"
(pause)
Li Lei:"Oh,let us go to the bed together!"

關鍵時刻豈可報錯。blog

首先發現問題出在冒號,split方法容許第二個參數.索引

如下實例展現了split()函數的使用方法:

#!/usr/bin/python

str = "Line1-abcdef \nLine2-abc \nLine4-abcd";
print str.split( );
print str.split(' ', 1 );

以上實例輸出結果以下:

['Line1-abcdef', 'Line2-abc', 'Line4-abcd']
['Line1-abcdef', '\nLine2-abc \nLine4-abcd']
data = open('aaa.txt')
# 打開文件

for line in data:
    (role,spoken)=line.split(':',1)
    print(role,end='')
    print(' said:',end='')
    print(spoken,end='')

取反:not

結果pause解析不了。每一行作多一個判斷。取反用的是not方法,查找用的是find方法。

Python find() 方法檢測字符串中是否包含子字符串 str ,若是指定 beg(開始) 和 end(結束) 範圍,則檢查是否包含在指定範圍內,若是包含子字符串返回開始的索引值,不然返回-1。

find()方法語法:

str.find(str, beg=0, end=len(string))

考慮這樣寫

for line in data:
    if not line.find(':')==-1:
        (role,spoken)=line.split(':',1)
        print(role,end='')
        print(' said:',end='')
        print(spoken,end='')
data.close()

關注代碼自己的目的功能:try...except...捕獲處理異常

劇本里的對話千差萬別,而我只想要人物的對話。不斷增長代碼複雜度是絕對不明智的。

python遇到代碼錯誤會以traceback方式告訴你大概出了什麼錯,並中斷處理流程(程序崩了!)。

try...except...相似try...catch語法,容許代碼中的錯誤發生,不中斷業務流程。

在上述業務代碼中我想統一忽略掉全部

  1. 只顯示

  2. 木有冒號的文本行

能夠 這麼寫:

for line in data:
    try:
        (role,spoken)=line.split(':',1)
        print(role,end='')
        print(' said:',end='')
        print(spoken,end='')
    except:
        pass

pass是python中的null語句,理解爲啥也不作。

經過這個語法,忽略處理掉了全部沒必要要的複雜邏輯。

複雜系統中,aaa.txt多是不存在的,你當然能夠用if讀取,還有一個更激進(先進)的寫法:

import os

try:
    data = open('aaa.txt')
    # 打開文件

    for line in data:
        try:
            (role,spoken)=line.split(':',1)
            print(role,end='')
            print(' said:',end='')
            print(spoken,end='')
        except:
            pass
except:
    print('error:could not read the file.')

兩種邏輯是不同的,上述是沒法讀取(可能讀取出錯),if是路徑不存在。因而引起了最後一個問題。

錯誤類型指定

過於通常化的代碼,老是不能很好地判斷就是是哪出了錯。try語句沒法判斷:到底是文件路徑不對仍是別的問題

import os

try:
    data = open('aaa.txt')
    # 打開文件

    for line in data:
        try:
            (role,spoken)=line.split(':',1)
            print(role,end='')
            print(' said:',end='')
            print(spoken,end='')
        except ValueError:
            # 參數出錯
            pass
except IOError:
    # 輸入輸出出錯
    print('error:could not find the file.')

python中異常對象有不少,可自行查閱

數據不符合指望格式:ValueError

IOError:路徑出錯

數據儲存到文件

業務代碼工做流程能夠儲存到文件中保存下來。下面先看一個需求:

  1. 分別建立一個名爲lilei和hanmeimei的空列表
  2. 刪除一個line裏面的換行符(replace方法和js中幾乎同樣。去除左右空格用strip方法)
  3. 給出條件和代碼,根據role的值將line添加到適當的列表中
  4. 輸出各自列表。

簡單說就是一個條件查詢的實現。

try:
    data = open('aaa.txt')
    lilei = []
    hanmeimei = []
    for line in data:
        try:
            (role, spoken) = line.split(':', 1)
            spoken = spoken.replace('\n', '')
            if role == 'Li Lei':
                lilei.append(spoken)
            else:
                hanmeimei.append(spoken)
        except ValueError:
            pass
    data.close()
except IOError:
    print('error:the file is not found.')
    
print(lilei)
print(hanmeimei)

很簡單。

寫模式:open('bbb.txt',w')

open方法默認爲讀模式open('bbb.txt','r'),寫模式對由於open('bbb.txt','w')

在同目錄下建立一個bbb.txt

寫入文件能夠用如下命令:

out = open('bbb.txt', 'w')
print('we are who we are.', file=out)
out.close()
文件訪問模式 釋義
r 讀取,是爲默認模式
w 打開一個文件,覆寫文件內容,如沒有則建立。
w+ 讀取和追加寫入(不清除)
a 追加寫入

打開的文件必須運行關閉!

好了,介紹完知識以後能夠在上一節代碼中分別寫入文件吧

try:
    data = open('aaa.txt')
    lilei = []
    hanmeimei = []
    for line in data:
        try:
            (role, spoken) = line.split(':', 1)
            spoken = spoken.strip()
            if role == 'Li Lei':
                lilei.append(spoken)
            else:
                hanmeimei.append(spoken)
        except ValueError:
            pass
    data.close()

    try:
        _lilei = open('lilei.txt', 'w')
        _hanmeimei = open('hanmeimei.txt', 'w')

        print(lilei,file=_lilei)
        print(hanmeimei,file=_hanmeimei)

        _lilei.close()
        _hanmeimei.close()
        print('works completed.')
    except IOError:
        print('file error.')
        
except IOError:
    print('error:the file is not found.')

測試成功,但以上代碼有個問題:我須要不管IOError都運行一套代碼。而且在文件建立後關閉

擴展try語句

當我嘗試以read模式打開一個文件,:

try:
        data = open('lilei.txt')
    except IOError as err:
        print('file error.'+str(err))
    finally:
        if 'data' in locals():
            _lilei.close()
        print('works completed.')
  • finally:不管是否運行成功都執行的代碼。
  • locals():告訴你文件是否成功被建立並打開。
  • as xxx:爲異常對象命名,而且經過str()轉化爲字符以便打印,也是一個賦值過程

實在太麻煩了。

with語句

with語句利用了一個上下文管理協議。有了它就不用些finally了。

目前爲止條件查找的方案是這樣的

# ...

    try:
        _lilei = open('lilei.txt','w')
        _hanmeimei = open('hanmeimei.txt','w')

        print(lilei, file=_lilei)
        print(hanmeimei, file=_hanmeimei)
    except IOError as err:
        print('file error.'+str(err))
    finally:
        if '_lilei' in locals():
            _lilei.close()
        if '_hanmeimei' in locals():
            _hanmeimei.close()
        print('works completed.')

except IOError:
    print('error:the file is not found.')

用with重寫以後:

try:
        with open('lilei.txt','w') as _lilei:
            print(lilei, file=_lilei)
        with open('hanmeimei.txt','w') as _hanmeimei:        
            print(hanmeimei, file=_hanmeimei)
        print('works completed.')
    except IOError as err:
        print('file error.'+str(err))

寫好以後就很是簡潔了。

因地制宜選擇輸出樣式

對於列表數據來講,直接存字符串是很不合適的。如今我要把第二章中的flatten加進來並加以改造。

# base.py

def flatten(_list, count=False, level=0):
    if(isinstance(_list, list)):
        for _item in _list:
            flatten(_item,count,level+1)
    else:
        if count:
            for step in range(level):
                print("\t", end='')
            print(_list)
        else:
            print(_list)

需求:向flatten添加第四個參數,標識數據寫入的位置,並容許缺省。

# base.py
def flatten(_list, count=False, level=0,_file=False):
    if(isinstance(_list, list)):
        for _item in _list:
            flatten(_item,count,level+1,_file)
    else:

        if count:
            for step in range(level):
                print("\t", end='',file=_file)
            print(_list,file=_file)
        else:
            print(_list)

調用

import base as utils
try:
    data = open('aaa.txt')
    lilei = []
    hanmeimei = []
    for line in data:
        try:
            (role, spoken) = line.split(':', 1)
            spoken = spoken.strip()
            if role == 'Li Lei':
                lilei.append(spoken)
            else:
                hanmeimei.append(spoken)
        except ValueError:
            pass
    data.close()

    try:
        with open('lilei.txt','w') as _lilei:
            utils.flatten(lilei,True,0,_lilei)
        with open('hanmeimei.txt','w') as _hanmeimei:        
            utils.flatten(hanmeimei, True, 0, _hanmeimei)
        print('works completed.')
    except IOError as err:
        print('file error.'+str(err))

    
except IOError:
    print('error:the file is not found.')

輸出成功

把格局拉高點吧,這仍然是一個高度定製化的代碼。

pickle庫的使用

pickle庫介紹

pickle是python語言的一個標準模塊,安裝python後已包含pickle庫,不須要單獨再安裝。

pickle模塊實現了基本的數據序列化和反序列化。經過pickle模塊的序列化操做咱們可以將程序中運行的對象信息保存到文件中去,永久存儲;經過pickle模塊的反序列化操做,咱們可以從文件中建立上一次程序保存的對象。

1、內存中操做:

import pickle
#dumps 轉化爲二進制文件
li = [11,22,33]
r = pickle.dumps(li)
print(r)

#loads 將二進制數據編譯出來
result = pickle.loads(r)
print(result)

2、文件中操做:

#dump:以二進制形式打開(讀取:rb,寫入wb)文件
li = [11,22,33]
pickle.dump(li,open('db','wb'))

#load
ret = pickle.load(open('db','rb'))
print(ret)

把二進制文件寫入文件中:

try:
        with open('lilei.txt','wb') as _lilei:
            # utils.flatten(lilei,True,0,_lilei)
            pickle.dump(lilei,_lilei)
        with open('hanmeimei.txt','wb') as _hanmeimei:        
            # utils.flatten(hanmeimei, True, 0, _hanmeimei)
            pickle.dump(hanmeimei,_hanmeimei)
        print('works completed.')
    except IOError as err:
        print('file error.'+str(err))
    
    except pickle.PickleError as pError:
        print('err:'+str(pError))

數據已經被寫入。

舉例說:如何打開lileii.txt並正確編譯呢?

new_lilei=[]
try:
    with open('lilei.txt','rb') as _new_lilei:
        new_lilei = pickle.load(_new_lilei)
        print(utils.flatten(new_lilei))
except IOError as io:
    print('err:'+str(io))
except pickle.PickleError as pError:
    print('pickleError'+str(pError))

測試成功。

用pickle的通用io纔是上策。

相關文章
相關標籤/搜索