從 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'}