一、Python語句簡介
1.1 一些語句的簡單介紹
>>> while True: #簡單的while循環
... reply = input('Enter text:') #調用了Input,將輸入傳參給reply
... if reply == 'stop': break #如果輸入的是stop就退出循環
... print(reply.upper()) #如果輸入的不是stop就一直將輸入的轉換為大寫字母
... Enter text:abc #這是第一個輸入abc,看到下面轉換成大寫的ABC了
ABC Enter text:nihao123da NIHAO123DA Enter text:stop #這里輸入了一個stop,然后循環就退出了
>>>
#上面的代碼利用了Python的while循環,它是Python最通用的循環語句。簡單的說,它的組成為:while這個單詞,之后跟一個其結果為真或假的表達式,再接一個當頂端測試為真(這時的True看做是永遠為真)時不停的迭代的嵌套代碼塊。
#這個Input內置函數,在這里用於通過控制台輸出,它打印可選的參數字符串作為提示,並返回用戶輸入的回復字符串。
#利用嵌套代碼塊特殊規則的單行if語句也在這里出現:if語句體出現在冒號之后的首行,而並不是在首行的下一行縮進。
#最后,Python的break語句用於立即退出循環。也就是完全跳出循環語句而程序會繼續循環之后的部分。如果沒有這個退出語句,while循環會因為測試總是真值而永遠循環下去。
>>> while True: ... reply = input('Enter text:') ... if reply == 'stop': #如果是stop就退出 ... break ... elif not reply.isdigit(): #如果輸入的不是數字類型就打印Bad1 8次 ... print('Bad!' * 8) ... else: #否則就打印輸入數字的2次方 ... print(int(reply) ** 2) ... #按回車下面是測試結果 Enter text:abc Bad!Bad!Bad!Bad!Bad!Bad!Bad!Bad! Enter text:a Bad!Bad!Bad!Bad!Bad!Bad!Bad!Bad! Enter text:2 4 Enter text:stop >>>
#Python會執行首次測試為真所想匹的代碼塊,按照由上至下的順序,如果所有測試都是假,就執行else部分。
1.2 賦值、表達式和打印
賦值語句
賦值語句有些特性要專門記住,如下所示
賦值語句建立對象引用值,Python賦值語句會把對象引用值存儲在變量名或數據結構的元素內。賦值語句總是建立對象的引用值,而不是賦值對象。因此,Python變量更像是指針,而不是數據存儲區域。
變量名在首次賦值時會被創建。Python會在首次將(即對象引用值)賦值給變量時創建其變量名。有些(並非全部)數據結構元素也會在賦值時創建(例如,字典中的元素,一些對象屬性)。一旦賦值了,每當這個變量名出線在表達式時,就會被其所引用的值取代。
變量名在引用前必須先賦值。使用尚未進行賦值的變量名是一種錯誤,如果你視圖這么做,Python會引發異常,而不是返回某種模糊的默認值;如果返回默認值,就很難再程序中找出輸入錯誤的地方。
執行隱式賦值的一些操作,在Python中,賦值語句會在許多情況下使用。例如,模塊導入、函數和類的定義、for循環變量以及函數參數全都是隱式賦值運算。
>>> seq = [1,2,3,4]
>>> a,b,c,*d = seq
>>> print(a,b,c,d)
1 2 3 [4]
>>> L = [1,2,3,4] >>> while L: ... front, *L = L ... print(front,L) ... 1 [2, 3, 4] 2 [3, 4] 3 [4] 4 []
#當使用一個帶星號的名稱的時候,左邊的目標中的項數不需要與主題序列的長度匹配。實際上,帶星號的名稱可以出現在目標中的任何地方
打印操作
在python中,print語句可以實現打印--只是對程序員友好的標准輸出流的接口而已。從技術角度來講,這是把一個或多個對象轉換為其文本表達形式,然后發送給標准輸出或另一個類似文件的流。
文件對象方法:例如file.write(str).打印操作是類似的,但更加專注--文件寫入方法是把字符串寫入到任意的文件,print默認地把對象打印到stdout流,添加了一些自動的格式化。和文件方法不同,在使用打印操作的時候,不需要把對象轉換為字符串。
標准輸出流:標准輸出流(通常叫做stdout)只是發送一個程序的文本輸出的默認的地方。加上標准輸入流和錯誤流,它只是腳本啟動時所創建的3種數據連接中的一種。標准輸出通常映射到啟動Python程序的窗口,除非它已經在操作系統的shell中重定向到一個文件或管道。
1.3 if測試和語法規則
Python語法規則
Python語法有些特性是我們需要知道的:
語句是逐個運行的:python一般都會按照次序從頭到尾執行文件中嵌套塊中的語句,但是像if(還有循環)這種語句會使得解釋器在程序內跳躍。因為Python經過一個程序的路徑叫做控制流程,像if這類會對其產生影響的語句,通常叫做控制流程語句。
塊和語句的邊界會自動檢測。Python的程序塊中沒有大括號或“begin/end”等分隔字符;反之,Python使用首行下的語句縮進把嵌套塊內的語句組合起來。同樣地,Python語句一般是不以分號終止的,一行的末尾通常就是該行所寫語句的結尾。
復合語句=首行+“: ” + 縮進語句。Python中所有復合語句都遵循相同格式:首行會以冒號終止,再接一個或多個嵌套語句,而且通常都是在首行下縮進的。縮進語句叫做塊(有時叫做組)。在If語句中,elif和else分句是if的一部分,也是其本身嵌套塊的首行。
空白行、空格以及注釋通常都會忽略。文件中空白行將忽略(但在交互模式提示符下不會)。語句和表達式中的空格幾乎都忽略(除了在字符串常量內,以及用在縮進時)。注釋總是忽略:它們以#字符開頭(不是在字符串常量內),而且延伸至該行的末尾。
文檔字符串(docstring)會忽略,但會保存並由工具顯示。Python支持的另一種注釋,叫做文檔字符串(簡稱docsting)。和#注釋不同的是,文檔字符串會在運行時保留下來以便查看。文檔字符串只是出現在程序文件和一些語句頂端的字符串中。Python會忽略這些內容,但是,在運行時會自動將其附加在對象上,而且能由 文檔工具顯示。
1.4 while和for循環
while循環
while語句是Python語言中最通用的迭代結構。
>>> x = 'spam' >>> while x: ... print(x,end='') ... x = x[1:] ... spampamamm>>>
#注意,這里使用end= ‘’關鍵字參數,使所有輸出都出現在同一行,之間用空格隔開;
在python中:
break : 跳出最近所在的循環(跳過整個循環語句)
continue : 跳到最近所在循環的開頭處(來到循環的首行)
pass:什么事也不做,只是空占位語句
循環else塊:只有當循環正常離開時才會執行(也就是沒有碰到break語句)
>>> a = b // 2 >>> while a > 1: ... if b % a == 0: ... print(b,'has factor',a) ... break ... x -= 1 ... else: ... print(b,'is prime') ... 2 is prime
#除了設置標志位在循環結束時進行測試外,也可以在找到因子時插入break。這樣一來,循環else分句可以視為只有當沒有找到因子時才會執行。如果你沒有碰到break,該數就是質數。
#如果循環主體沒有執行過,循環else分局也會執行,因為你沒在其中執行break語句。在while循環中,如果首行的測試一開始就是假,就會發生這種問題。因此在上面的例子中,如果a一開始就小於或等於1(例如,如果b是2),就會執行else的內容。
for循環
for循環在Python中是一個通用的序列迭代器:可以遍歷任何有序的序列對象內的元素。for語句可用於字符串、列表、元組、其他內置可迭代對象以及之后能夠通過類所創建的新對象。
>>> for x in ["spam","eggs","ham"]: ... print(x) ... spam eggs ham
#for循環可以遍歷任何一種序列對象。例如,上面的例子依次把變量名x由左至右賦值給列表中三個元素的每一個,而print語句將會每個元素都執行一次。在print語句內(循環主體),變量名x引用的是列表中的當前元素。
>>> S = "lumberjack" >>> T = ("and","I'm","okay") >>> for x in S: print(x,end= '') ... lumberjack>>> >>> for x in T: print(x,end=' ') ... and I'm okay >>>
#任何序列都適用for循環,因它是通用的工具。例如,上面for循環可用於字符串和元組。
>>> D = {'a':1,'b':2,'c':3} >>> for key in D: ... print(key,'=>',D[key]) ... c => 3 a => 1 b => 2 >>> list(D.items()) [('c', 3), ('a', 1), ('b', 2)] >>> for (key,value) in D.items(): ... print(key,'=>',value) ... c => 3 a => 1 b => 2
#這也是for的一種常用方法,for循環中的元組使用items方法來遍歷字典中的鍵和值變得很方便,而不必再遍歷鍵並手動地索引以獲取值。
>>> seq1 = 'spam' >>> seq2 = 'scam' >>> for x in seq1: ... if x in seq2: ... res.append(x) ... >>> res ['s', 'a', 'm']
#上面的例子是for循環里面嵌套if的方式。
循環計數器:while和range
range函數是通用的工具,可用於在各種環境下。雖然range常用在for循環中來產生索引,但也可以用在任何需要整數列表的地方。在Python 3.0中,range是一個迭代器,會根據需要產生元素,因此,我們需要將其包含到一個list調用中以一次性顯示其結果。
>>> list(range(5)),list(range(2,5)),list(range(0,10,2)) ([0, 1, 2, 3, 4], [2, 3, 4], [0, 2, 4, 6, 8])
>>> list(range(-5,5)) #range頁可以是非正數
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
>>> list(range(5,-5,-1)) #range也可以是非遞增的
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]
#一個參數時,range會產生從零算起的整數列表,但其中不包括該參數的值。如果傳進兩個參數,第一個將視為下邊界,第三個選用參數可以提供步進值。使用時,Python會對每個連續整數加上步進值從而得到結果(步進值默認為1)。
並行遍歷: zip和map
內置的zip函數可以使用for循環來並行使用多個序列。在基本運算中,zip會取得一個或多個序列為參數,然后返回元組的列表,將這些序列中的並排的元素配成對。
>>> L1 = [1,2,3,4,5] >>> L2 = [5,6,7,8,9] >>> zip(L1,L2) <zip object at 0x000000000071EB48> >>> list(zip(L1,L2)) [(1, 5), (2, 6), (3, 7), (4, 8), (5, 9)]
>>> for (x,y) in zip(L1,L2):
... print(x,y, '---', x+y)
...
1 5 --- 6
2 6 --- 8
3 7 --- 10
4 8 --- 12
5 9 --- 14
#上面的例子定義了兩個列表,可以使用zip來創建一個元組對的列表(和range一樣,zip在Python3.0中也是一個可迭代對象)合並列表中的元素。這樣的結果在其他環境下也有用,然后搭配for循環時,它就會支持並行迭代。
二、迭代器和解析
2.1 迭代器初探
文件迭代器
>>> f = open('D://test.txt') >>> f.readline() 'the is noe\n' >>> f.readline() 'the is two\n' >>> f.readline() 'the is three' >>> f.readline() ''
>>> f = open('D://test.txt')
>>> f.__next__()
'the is noe\n'
>>> f.__next__()
'the is two\n'
>>> f.__next__()
'the is three'
>>> f.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
#從上面的例子可以看到每次調用readline方法,就會讀取一行至到末尾,就會返回空字符串,可以通過它來檢測,從而跳出循環。
#從上面的第二個例子看出可以通過__next__的方法,差不多有相同的效果,但是到達文件末尾時,__next__會引發內置的異常而不是空字符串。這個接口就是Python中所謂的迭代協議:有__next__方法的對象會前進到下一個結果,而在一系列結果的末尾時,則會引發StopIteration。在Python中,任何這類對象都認為是可迭代的。任何這類對象也能以for循環或其他迭代工具遍歷,因為所有迭代工具內部工作起來都是在每次迭代中調用__next__,並且捕捉StopIteration異常來確定何時離開。
>>> for line in open('D://test.txt'): ... print(line.upper(),end='') ... THE IS NOE THE IS TWO THE IS THREE>
#逐行讀取文本文件的最佳方式就是根本不要去讀取;其替代的辦法就是讓for循環在每輪自動調用next從而前進到下一行。上面的第一個例子是逐行讀取文件(程序執行時打印每行的大寫版本),但沒有刻意從文件中讀取內容。注意,這里的print使用end=''來抑制添加一個\n,因為行字符串已經有了一個(如果沒有這點,我們的輸出將變成兩行隔開)。上面的例子是讀取文本文件的最佳方式,原因有三點:這是最簡單的寫法,運行最快,並且從內存使用情況來說也是最好的。相同效果的原始方式,是以for循環調用文件的readlines方法,將文件內容加載到內存,做成行字符串的列表。但是如今這種readlines不是最好的使用方法了,從內存的使用情況來看,效果很差。因為它是一次把整個文件加載到內存,如果文件太大,會導致計算機內存空間不夠,甚至不能夠工作。
>>> f = open('D://test.txt') >>> while True: ... line = f.readline() ... if not line: break ... print(line.upper(),end='') ... THE IS NOE THE IS TWO THE IS THREE
#當然也可以用while循環逐行讀取文件,盡管這樣,比起迭代器for循環的版本可能運行得更慢一些,因為迭代器在Python中是以C語言的速度運行的,而while循環版本則是通過Python虛擬機運行Python字節碼的。任何時候,把Python代碼換成C程序代碼,速度應該會變快,當然也絕非如此,尤其是在Python 3.0中,通過技時技術,可以來衡量各種方案的相對速度。
>>> f = open('D://test.txt') >>> f.__next__() 'the is noe\n' >>> next(f) 'the is two\n' >>> next(f) 'the is three' >>> next(f) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
>>> f = open('D://test.txt')
>>> while True:
... try: #當然我們也可以通過try捕捉錯誤然后讓其做其他操作的方式防止錯誤輸出
... next(f)
... except StopIteration:
... print('Is output over!')
... break
...
'the is noe\n'
'the is two\n'
'the is three'
Is output over!
#為了支持手工迭代代碼,python 3.0提供了一個內置函數next,它會自動調用一個對象的__next__方法。給定一個可迭代對象X,調用next(X)等同於X.__next__()。從技術角度來說,迭代協議還有一點值得注意。當for循環開始時,會通過它傳給Iter內置函數,以便從可迭代對象中獲得一個迭代器,返回的對象含有需要的next方法。如果看for循環內部如何處理列表這類內置序列類型的話,就會變得一目了然了。
其他內置類型迭代器
除了文件以及像列表這樣的實際的序列外,其他類型也有其適用的迭代器。
>>> D = {'a':1,'b':2,'c':3} #遍歷字典鍵讓其明確的獲取其鍵的列表 >>> for key in D.keys(): ... print(key,D[key]) ... a 1 b 2 c 3
>>> I = iter(D) #在最近的Python版本中,字典有一個迭代器,在迭代環境中,會自動一次返回一個鍵
>>> next(I)
'a'
>>> next(I)
'b'
>>> for key in D:
... print(key,D[key])
...
a 1
b 2
c 3
#注意上面的最后一個例子,在新版的python中,不再需要keys方法來遍歷字典鍵,for循環,將使用迭代協議在每次迭代的時候獲取一個值。
2.2 Python文檔資源
#注釋(文件中的文檔)
dir函數(對象中可用屬性的列表)
文檔字符串:__doc__(附加在對象上的文件中的文檔)
PyDoc:help函數(對象的交互幫助)
PyDoc:HTML報表(瀏覽器中的模塊文檔)
標准手冊(正式的語言和庫的說明)
#注釋
井字號注釋是代碼編寫文檔的最基本方式。Python會忽略#之后所有文字(只要#不是位於字符串常量中)。
dir函數
內置的dir函數是抓取對象內可用所有屬性列表的簡單方式。它能夠調用任何有屬性的對象。
>>> import sys >>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current _frames', '_debugmallocstats', '_getframe', '_home', '_mercurial', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'call stats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_coroutine_wra pper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'get windowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', ' path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'st derr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']
#上面是查看內置sys模塊有哪些可以用
>>> dir([]) ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem_ _', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>> dir('') ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__ ', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isident ifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', ' rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
#上面是找出內置對象類型提供了哪些屬性,可運行dir並傳入所需要類型的常量。任何內置類型的dir結果都包含了一組屬性,這些屬性和該類型的實現相關,他們的開頭和結尾都是雙下划線,從而保證了其獨特性。
文檔字符串:__doc__
除了#注釋外,Python也支持可自動附加在對象上的文檔,而且在運行時還可保存查看。從語法上來說,這類注釋是寫成字符串,放在模塊文件、函數以及類語句的頂端,就在任何可執行程序代碼前。Python會自動封裝這個字符串,也就是成為所謂的文檔字符串,使其成為相應對象的__doc__屬性。
>>> import sys >>> print(sys.__doc__)
>>> print(sys.maxsize .__doc__) #查看內置模塊內的函數、類以及方法在其__doc__屬性內也有附加的說明信息。
>>> print(int.__doc__) #通過文檔字符串讀取內置函數的說明
>>> print(map.__doc__)
map(func, *iterables) --> map object
Make an iterator that computes the function using arguments from each of the iterables. Stops when the shortest iterable is exhausted.
#通過上面的方式查看其文檔字符串,從而得到內置工具的大量信息。
PyDoc:help函數
>>> import sys >>> dir(sys) #查看sys內置的方法
>>> help(sys) #查看哪些方法可以用find函數查看完整的報表
>>> help(sys.find) #查看find方法的詳細使用
#注意調用Help時,不是一定要導入sys,但是要取得sys的輔助信息時,就得導入sys,help期待有個對象的引用值傳入。就較大對象而言,諸如,模塊和類,help顯示內容會分為幾段,而其中有一些會在這里顯示。