1. 程式人生 > >從 Python到Tensorflow 學習之路(四)

從 Python到Tensorflow 學習之路(四)

從 Python到Tensorflow 學習之路(五)


最近畢業設計題目是研究對抗樣本,要用tensorflow來搭建神經網路,因此python必不可少,這個不是一個傳統的Python學習教程只是把學習Python過程中遇到的問題和經驗記錄下來(基於Python3.5),如果想要一步一步學習Python建議看下面的網站。
Python學習教程


錯誤、除錯和測試

錯誤處理

  • try...except...finally...其中finally可有可無,有的話一定會被執行
  • 如果沒有錯誤發生可以在except語句塊後面加一個else,當沒有錯誤發生時,會自動執行else
    語句
  • Python中所有的錯誤型別都繼承於BaseException,所以在使用except時需要注意,它不但捕獲該型別的錯誤,還把其子類也“一網打盡”
  • 出錯的時候,一定要分析錯誤的呼叫棧資訊,才能定位錯誤的位置。
  • 可以通過配置使用logging把錯誤記錄在日誌檔案中
import logging


def foo(s):
    return 10 / int(s)


def bar(s):
    return foo(s) * 2


def main():
    try:
        bar('0')
    except Exception as
e: logging.exception(e) main() print('END')

除錯

  • 使用斷言assert的意思是表示式n!=0應該是True,否則根據程式執行邏輯,後面的程式碼肯定會出錯。如果斷言失敗,assert語句本身就會丟擲AssertionError
def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n


def main():
    foo('0')


main()
  • 利用logging不會丟擲錯誤,而且可以輸出到檔案。它允許你指定記錄資訊的級別,有debug,info,warning,error等幾個級別,當我們指定level=INFO時,logging.debug就不起作用了。同理,指定level=WARNING後,debug和info就不起作用了。這樣一來,你可以放心地輸出不同級別的資訊,也不用刪除,最後統一控制輸出哪個級別的資訊。
import logging

logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
"""
INFO:root:n = 0
Traceback (most recent call last):
  File "/home/lwp/PycharmProjects/blog_test/blog_test.py", line 10, in <module>
    print(10 / n)
ZeroDivisionError: division by zero
"""

IO程式設計

檔案讀寫

  • 使用open()函式以讀檔案的模式開啟一個檔案物件,傳入檔名和識別符號,如果檔案不存在就會丟擲錯誤
f = open('test.txt', 'r')
"""
Traceback (most recent call last):
  File "/home/lwp/PycharmProjects/blog_test/blog_test.py", line 4, in <module>
    f = open('test.txt', 'r')
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'

"""
  • 呼叫read()方法可以一次性讀取檔案的全部內容,Python把內容讀到記憶體,用一個str物件表示
  • 呼叫close()方法可以關閉檔案。。檔案使用完畢後必須關閉,因為檔案物件會佔用作業系統的資源,並且作業系統同一時間能開啟的檔案數量也是有限的。使用with語句來自動呼叫close()方法
with open('test.txt', 'r') as f:
    print(f.read())

# output:111 111
         222 222
  • 呼叫read()會會一次性讀取檔案的全部內容,如果檔案有10G,記憶體就爆了,所以,要保險起見,可以反覆呼叫read(size)方法,每次最多讀取size個位元組的內容。另外,呼叫readline()可以每次讀取一行內容,呼叫readlines()一次讀取所有內容並按行返回list。由於print()函式自身會換行,所以我們需要把end引數進行修改。
with open('test.txt', 'r') as f:
    l1 = f.readline()
    l2 = f.readline()
    print(l1, end='')
    print(l2)
"""
111 111
222 222
"""
with open('test.txt', 'r') as f:
    for line in f.readlines():
        print(line.strip())
  • file-like Object:像open()函式返回的這種有個read()方法的物件,在Python中統稱為file-like Object。除了file外,還可以是記憶體的位元組流,網路流,自定義流等等。file-like Object不要求從特定類繼承,只要寫個read()方法就行。StringIO就是在記憶體中建立的file-like Object,常用作臨時緩衝。
  • 讀取二進位制檔案如圖片、視訊等等,用'rb'模式開啟檔案即可
  • 要讀取非UTF-8編碼的文字檔案,需要給open()函式傳入encoding引數。遇到有些編碼不規範的檔案,你可能會遇到UnicodeDecodeError,因為在文字檔案中可能夾雜了一些非法編碼的字元。遇到這種情況,open()函式還接收一個errors引數,表示如果遇到編碼錯誤後如何處理。最簡單的方式是直接忽略。
  • 寫檔案時和讀檔案是一樣的,唯一區別是呼叫open()函式時,傳入識別符號'w'或者'wb'表示寫文字檔案或寫二進位制檔案。以'w'模式寫入檔案時,如果檔案已存在,會直接覆蓋(相當於刪掉後新寫入一個檔案)。如果我們希望追加到檔案末尾怎麼辦?可以傳入'a'以追加(append)模式寫入。
with open('test2.txt', 'w') as f:
    f.write('Hello world!')

StringIO和BytesIO

  • 資料讀寫不一定是檔案,也可以在記憶體中讀寫。要把str寫入StringIO,我們需要先建立一個StringIO,然後,像檔案一樣寫入即可。getvalue()方法用於獲得寫入後的str
from io import StringIO
f = StringIO()
print(f.write('hello'))
# output: 5
print(f.write(' '))
# output: 1
print(f.write('world!'))
# output: 6
print(f.getvalue())
# output: hello world!
  • 要讀取StringIO,可以用一個str初始化StringIO,然後像檔案一樣讀取
from io import StringIO
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
    s = f.readline()
    if s == '':
        break;
    print(s.strip())
"""
Hello!
Hi!
Goodbye!
"""

*StringIO操作的只能是str,如果要操作二進位制資料,就需要使用BytesIO。BytesIO實現了在記憶體中讀寫bytes,我們建立一個BytesIO,然後寫入一些bytes

from io import BytesIO
f = BytesIO()
print(f.write('你好'.encode('utf-8')))
# output: 6
print(f.getvalue())
# output:b'\xe4\xbd\xa0\xe5\xa5\xbd'
  • 和StringIO類似,可以用一個bytes初始化BytesIO,然後,像讀檔案一樣讀取
from io import BytesIO
f = BytesIO(b'\xe4\xbd\xa0\xe5\xa5\xbd')
print(f.read())
# output:b'\xe4\xbd\xa0\xe5\xa5\xbd'

操作檔案和目錄

  • 環境變數:在作業系統中定義的環境變數,全部儲存在os.environ這個變數中,可以直接檢視。要獲取某個環境變數的值,可以呼叫os.environ.get('key')
import os
print(os.environ)
print(os.environ.get('PATH'))
  • 檢視、建立和刪除目錄。把兩個路徑合成一個時,不要直接拼字串,而要通過os.path.join()函式。同樣的道理,要拆分路徑時,也不要直接去拆字串,而要通過os.path.split()函式,這樣可以把一個路徑拆分為兩部分,後一部分總是最後級別的目錄或檔名:
import os
# 檢視當前目錄的絕對路徑
print(os.path.abspath('.'))
# 在某個目錄下建立一個新目錄,首先把新目錄的完整路徑表示出來:
s = os.path.join(os.path.abspath('.'), 'testdir')
#os.mkdir(s)
# 刪除建立的資料夾
#os.rmdir(s)
print(os.path.split(s))
# output:('/home/lwp/PycharmProjects/blog_test', 'testdir')
print(os.path.splitext(os.path.abspath('./test.txt')))
# output:('/home/lwp/PycharmProjects/blog_test/test', '.txt')


# 對檔案進行重新命名
os.rename('test2.txt', 'test2.py')
# 刪掉檔案
os.remove('test2.py')
  • 複製檔案的函式在os模組中不存在,原因是複製檔案並非由作業系統提供的系統呼叫。shutil模組提供了copyfile()的函式,可以在shutil模組中找到很多實用函式,它們可以看做是os模組的補充
  • 可以利用Python的特性來過濾檔案。比如我們要列出當前目錄下的所有目錄
import os
# 列出當前目錄下的所有目錄
print([x for x in os.listdir('.') if os.path.isdir(x)])
# 列出所有的.py檔案
print([x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] == '.py'])

序列化

  • 變數從記憶體中變成可儲存或傳輸的過程稱之為序列化。序列化之後,就可以把序列化後的內容寫入磁碟,或者通過網路傳輸到別的機器上。反過來,把變數內容從序列化的物件重新讀到記憶體裡稱之為反序列化,即unpickling。首先我們嘗試將一個物件序列化並寫入檔案。pickle.dump()直接把物件序列化後寫入一個file-like Object。
import pickle
d = dict(name='Bob', age=10, score=88)
print(pickle.dumps(d))
# output:b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\nX\x05\x00\x00\x00scoreq\x02KXX\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Bobq\x04u.'
with open('testfile.txt', 'wb') as f:
    pickle.dump(d, f)
  • 當我們要把物件從磁碟讀到記憶體時,可以先把內容讀到一個bytes,然後用pickle.loads()方法反序列化出物件,也可以直接用pickle.load()方法從一個file-like Object中直接反序列化出物件。
import pickle

with open('testfile.txt', 'rb') as f:
    d = pickle.load(f)
    print(d)
# output:{'score': 88, 'age': 10, 'name': 'Bob'}

我們下期見!~