資料來源:https://github.com/BrambleXu/pydata-notebook
第2章 Python語法基礎(chǔ),IPython和Jupyter Notebooks
當(dāng)我在2011年和2012年寫作本書的第一版時,可用的學(xué)習(xí)Python數(shù)據(jù)分析的資源很少。這部分上是一個雞和蛋的問題:我們現(xiàn)在使用的庫罢低,比如pandas、scikit-learn和statsmodels胖笛,那時相對來說并不成熟网持。2017年,數(shù)據(jù)科學(xué)长踊、數(shù)據(jù)分析和機(jī)器學(xué)習(xí)的資源已經(jīng)很多功舀,原來通用的科學(xué)計(jì)算拓展到了計(jì)算機(jī)科學(xué)家、物理學(xué)家和其它研究領(lǐng)域的工作人員身弊。學(xué)習(xí)Python和成為軟件工程師的優(yōu)秀書籍也有了辟汰。
因?yàn)檫@本書是專注于Python數(shù)據(jù)處理的,對于一些Python的數(shù)據(jù)結(jié)構(gòu)和庫的特性難免不足阱佛。因此帖汞,本章和第3章的內(nèi)容只夠你能學(xué)習(xí)本書后面的內(nèi)容。
在我來看凑术,沒有必要為了數(shù)據(jù)分析而去精通Python翩蘸。我鼓勵你使用IPython shell和Jupyter試驗(yàn)示例代碼,并學(xué)習(xí)不同類型淮逊、函數(shù)和方法的文檔催首。雖然我已盡力讓本書內(nèi)容循序漸進(jìn),但讀者偶爾仍會碰到?jīng)]有之前介紹過的內(nèi)容泄鹏。
本書大部分內(nèi)容關(guān)注的是基于表格的分析和處理大規(guī)模數(shù)據(jù)集的數(shù)據(jù)準(zhǔn)備工具郎任。為了使用這些工具,必須首先將混亂的數(shù)據(jù)規(guī)整為整潔的表格(或結(jié)構(gòu)化)形式备籽。幸好舶治,Python是一個理想的語言,可以快速整理數(shù)據(jù)车猬。Python使用得越熟練霉猛,越容易準(zhǔn)備新數(shù)據(jù)集以進(jìn)行分析。
最好在IPython和Jupyter中親自嘗試本書中使用的工具诈唬。當(dāng)你學(xué)會了如何啟動Ipython和Jupyter韩脏,我建議你跟隨示例代碼進(jìn)行練習(xí)缩麸。與任何鍵盤驅(qū)動的操作環(huán)境一樣铸磅,記住常見的命令也是學(xué)習(xí)曲線的一部分。
筆記:本章沒有介紹Python的某些概念,如類和面向?qū)ο缶幊淘淖校憧赡軙l(fā)現(xiàn)它們在Python數(shù)據(jù)分析中很有用吹散。 為了加強(qiáng)Python知識,我建議你學(xué)習(xí)官方Python教程八酒,https://docs.python.org/3/空民,或是通用的Python教程書籍,比如:
- Python Cookbook羞迷,第3版界轩,David Beazley和Brian K. Jones著(O’Reilly)
- 流暢的Python,Luciano Ramalho著 (O’Reilly)
- 高效的Python衔瓮,Brett Slatkin著 (Pearson)
2.1 Python解釋器
Python是解釋性語言浊猾。Python解釋器同一時間只能運(yùn)行一個程序的一條語句。標(biāo)準(zhǔn)的交互Python解釋器可以在命令行中通過鍵入python
命令打開:
$ python
Python 3.6.0 | packaged by conda-forge | (default, Jan 13 2017, 23:17:12)
[GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 5
>>> print(a)
5
>>>
提示輸入代碼热鞍。要退出Python解釋器返回終端葫慎,可以輸入exit()
或按Ctrl-D。
運(yùn)行Python程序只需調(diào)用Python的同時薇宠,使用一個.py
文件作為它的第一個參數(shù)偷办。假設(shè)創(chuàng)建了一個hello_world.py
文件,它的內(nèi)容是:
print('Hello world')
你可以用下面的命令運(yùn)行它(hello_world.py
文件必須位于終端的工作目錄):
$ python hello_world.py
Hello world
一些Python程序員總是這樣執(zhí)行Python代碼的澄港,從事數(shù)據(jù)分析和科學(xué)計(jì)算的人卻會使用IPython椒涯,一個強(qiáng)化的Python解釋器,或Jupyter notebooks慢睡,一個網(wǎng)頁代碼筆記本逐工,它原先是IPython的一個子項(xiàng)目。在本章中漂辐,我介紹了如何使用IPython和Jupyter泪喊,在附錄A中有更深入的介紹。當(dāng)你使用%run
命令髓涯,IPython會同樣執(zhí)行指定文件中的代碼袒啼,結(jié)束之后,還可以與結(jié)果交互:
$ ipython
Python 3.6.0 | packaged by conda-forge | (default, Jan 13 2017, 23:17:12)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: %run hello_world.py
Hello world
In [2]:
IPython默認(rèn)采用序號的格式In [2]:
纬纪,與標(biāo)準(zhǔn)的>>>
提示符不同蚓再。
2.2 IPython基礎(chǔ)
在本節(jié)中,我們會教你打開運(yùn)行IPython shell和jupyter notebook包各,并介紹一些基本概念摘仅。
運(yùn)行IPython Shell
你可以用ipython
在命令行打開IPython Shell,就像打開普通的Python解釋器:
$ ipython
Python 3.6.0 | packaged by conda-forge | (default, Jan 13 2017, 23:17:12)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: a = 5
In [2]: a
Out[2]: 5
你可以通過輸入代碼并按Return(或Enter)问畅,運(yùn)行任意Python語句娃属。當(dāng)你只輸入一個變量六荒,它會顯示代表的對象:
In [5]: import numpy as np
In [6]: data = {i : np.random.randn() for i in range(7)}
In [7]: data
Out[7]:
{0: -0.20470765948471295,
1: 0.47894333805754824,
2: -0.5194387150567381,
3: -0.55573030434749,
4: 1.9657805725027142,
5: 1.3934058329729904,
6: 0.09290787674371767}
前兩行是Python代碼語句;第二條語句創(chuàng)建一個名為data
的變量矾端,它引用一個新創(chuàng)建的Python字典掏击。最后一行打印data
的值。
許多Python對象被格式化為更易讀的形式秩铆,或稱作pretty-printed
砚亭,它與普通的print
不同。如果在標(biāo)準(zhǔn)Python解釋器中打印上述data
變量殴玛,則可讀性要降低:
>>> from numpy.random import randn
>>> data = {i : randn() for i in range(7)}
>>> print(data)
{0: -1.5948255432744511, 1: 0.10569006472787983, 2: 1.972367135977295,
3: 0.15455217573074576, 4: -0.24058577449429575, 5: -1.2904897053651216,
6: 0.3308507317325902}
IPython還支持執(zhí)行任意代碼塊(通過一個華麗的復(fù)制-粘貼方法)和整段Python腳本的功能捅膘。你也可以使用Jupyter notebook運(yùn)行大代碼塊,接下來就會看到滚粟。
運(yùn)行Jupyter Notebook
notebook是Jupyter項(xiàng)目的重要組件之一篓跛,它是一個代碼、文本(有標(biāo)記或無標(biāo)記)坦刀、數(shù)據(jù)可視化或其它輸出的交互式文檔愧沟。Jupyter Notebook需要與內(nèi)核互動,內(nèi)核是Jupyter與其它編程語言的交互編程協(xié)議鲤遥。Python的Jupyter內(nèi)核是使用IPython沐寺。要啟動Jupyter,在命令行中輸入jupyter notebook
:
$ jupyter notebook
[I 15:20:52.739 NotebookApp] Serving notebooks from local directory:
/home/wesm/code/pydata-book
[I 15:20:52.739 NotebookApp] 0 active kernels
[I 15:20:52.739 NotebookApp] The Jupyter Notebook is running at:
http://localhost:8888/
[I 15:20:52.740 NotebookApp] Use Control-C to stop this server and shut down
all kernels (twice to skip confirmation).
Created new window in existing browser session.
在多數(shù)平臺上盖奈,Jupyter會自動打開默認(rèn)的瀏覽器(除非指定了--no-browser
)混坞。或者钢坦,可以在啟動notebook之后究孕,手動打開網(wǎng)頁http://localhost:8888/
。圖2-1展示了Google Chrome中的notebook爹凹。
筆記:許多人使用Jupyter作為本地的計(jì)算環(huán)境厨诸,但它也可以部署到服務(wù)器上遠(yuǎn)程訪問。這里不做介紹禾酱,如果需要的話微酬,鼓勵讀者自行到網(wǎng)上學(xué)習(xí)史辙。
要新建一個notebook堪滨,點(diǎn)擊按鈕New茵宪,選擇“Python3”或“conda[默認(rèn)項(xiàng)]”揩慕。如果是第一次,點(diǎn)擊空格兑障,輸入一行Python代碼姑躲。然后按Shift-Enter執(zhí)行棠涮。
當(dāng)保存notebook時(File目錄下的Save and Checkpoint)搅方,會創(chuàng)建一個后綴名為.ipynb
的文件比吭。這是一個自包含文件格式茬斧,包含當(dāng)前筆記本中的所有內(nèi)容(包括所有已評估的代碼輸出)」4可以被其它Jupyter用戶加載和編輯。要加載存在的notebook绣溜,把它放到啟動notebook進(jìn)程的相同目錄內(nèi)慷彤。你可以用本書的示例代碼練習(xí),見圖2-3怖喻。
雖然Jupyter notebook和IPython shell使用起來不同底哗,本章中幾乎所有的命令和工具都可以通用。
Tab補(bǔ)全
從外觀上锚沸,IPython shell和標(biāo)準(zhǔn)的Python解釋器只是看起來不同跋选。IPython shell的進(jìn)步之一是具備其它IDE和交互計(jì)算分析環(huán)境都有的tab補(bǔ)全功能。在shell中輸入表達(dá)式哗蜈,按下Tab前标,會搜索已輸入變量(對象、函數(shù)等等)的命名空間:
In [1]: an_apple = 27
In [2]: an_example = 42
In [3]: an<Tab>
an_apple and an_example any
在這個例子中距潘,IPython呈現(xiàn)出了之前兩個定義的變量和Python的關(guān)鍵字和內(nèi)建的函數(shù)any
炼列。當(dāng)然,你也可以補(bǔ)全任何對象的方法和屬性:
In [3]: b = [1, 2, 3]
In [4]: b.<Tab>
b.append b.count b.insert b.reverse
b.clear b.extend b.pop b.sort
b.copy b.index b.remove
同樣也適用于模塊:
In [1]: import datetime
In [2]: datetime.<Tab>
datetime.date datetime.MAXYEAR datetime.timedelta
datetime.datetime datetime.MINYEAR datetime.timezone
datetime.datetime_CAPI datetime.time datetime.tzinfo
在Jupyter notebook和新版的IPython(5.0及以上)音比,自動補(bǔ)全功能是下拉框的形式俭尖。
筆記:注意,默認(rèn)情況下洞翩,IPython會隱藏下劃線開頭的方法和屬性稽犁,比如魔術(shù)方法和內(nèi)部的“私有”方法和屬性,以避免混亂的顯示(和讓新手迷惑Iб凇)這些也可以tab補(bǔ)全已亥,但是你必須首先鍵入一個下劃線才能看到它們。如果你喜歡總是在tab補(bǔ)全中看到這樣的方法来屠,你可以IPython配置中進(jìn)行設(shè)置陷猫。可以在IPython文檔中查找方法的妖。
除了補(bǔ)全命名绣檬、對象和模塊屬性,Tab還可以補(bǔ)全其它的嫂粟。當(dāng)輸入看似文件路徑時(即使是Python字符串)娇未,按下Tab也可以補(bǔ)全電腦上對應(yīng)的文件信息:
In [7]: datasets/movielens/<Tab>
datasets/movielens/movies.dat datasets/movielens/README
datasets/movielens/ratings.dat datasets/movielens/users.dat
In [7]: path = 'datasets/movielens/<Tab>
datasets/movielens/movies.dat datasets/movielens/README
datasets/movielens/ratings.dat datasets/movielens/users.dat
結(jié)合%run
,tab補(bǔ)全可以節(jié)省許多鍵盤操作星虹。
另外零抬,tab補(bǔ)全可以補(bǔ)全函數(shù)的關(guān)鍵詞參數(shù)(包括等于號=)镊讼。見圖2-4。
后面會仔細(xì)地學(xué)習(xí)函數(shù)平夜。
自省
在變量前后使用問號蝶棋?,可以顯示對象的信息:
In [8]: b = [1, 2, 3]
In [9]: b?
Type: list
String Form:[1, 2, 3]
Length: 3
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
In [10]: print?
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type: builtin_function_or_method
這可以作為對象的自省忽妒。如果對象是一個函數(shù)或?qū)嵗椒ㄍ嫒梗x過的文檔字符串,也會顯示出信息段直。假設(shè)我們寫了一個如下的函數(shù):
def add_numbers(a, b):
"""
Add two numbers together
Returns
-------
the_sum : type of arguments
"""
return a + b
然后使用?符號吃溅,就可以顯示如下的文檔字符串:
In [11]: add_numbers?
Signature: add_numbers(a, b)
Docstring:
Add two numbers together
Returns
-------
the_sum : type of arguments
File: <ipython-input-9-6a548a216e27>
Type: function
使用??會顯示函數(shù)的源碼:
In [12]: add_numbers??
Signature: add_numbers(a, b)
Source:
def add_numbers(a, b):
"""
Add two numbers together
Returns
-------
the_sum : type of arguments
"""
return a + b
File: <ipython-input-9-6a548a216e27>
Type: function
?還有一個用途,就是像Unix或Windows命令行一樣搜索IPython的命名空間鸯檬。字符與通配符結(jié)合可以匹配所有的名字决侈。例如,我們可以獲得所有包含load的頂級NumPy命名空間:
In [13]: np.*load*?
np.__loader__
np.load
np.loads
np.loadtxt
np.pkgload
%run命令
你可以用%run
命令運(yùn)行所有的Python程序喧务。假設(shè)有一個文件ipython_script_test.py
:
def f(x, y, z):
return (x + y) / z
a = 5
b = 6
c = 7.5
result = f(a, b, c)
可以如下運(yùn)行:
In [14]: %run ipython_script_test.py
這段腳本運(yùn)行在空的命名空間(沒有import和其它定義的變量)赖歌,因此結(jié)果和普通的運(yùn)行方式python script.py
相同。文件中所有定義的變量(import功茴、函數(shù)和全局變量俏站,除非拋出異常),都可以在IPython shell中隨后訪問:
In [15]: c
Out [15]: 7.5
In [16]: result
Out[16]: 1.4666666666666666
如果一個Python腳本需要命令行參數(shù)(在sys.argv
中查找)痊土,可以在文件路徑之后傳遞肄扎,就像在命令行上運(yùn)行一樣。
筆記:如果想讓一個腳本訪問IPython已經(jīng)定義過的變量赁酝,可以使用
%run -i
犯祠。
在Jupyter notebook中,你也可以使用%load
酌呆,它將腳本導(dǎo)入到一個代碼格中:
>>> %load ipython_script_test.py
def f(x, y, z):
return (x + y) / z
a = 5
b = 6
c = 7.5
result = f(a, b, c)
中斷運(yùn)行的代碼
代碼運(yùn)行時按Ctrl-C衡载,無論是%run或長時間運(yùn)行命令,都會導(dǎo)致KeyboardInterrupt
隙袁。這會導(dǎo)致幾乎所有Python程序立即停止痰娱,除非一些特殊情況。
警告:當(dāng)Python代碼調(diào)用了一些編譯的擴(kuò)展模塊菩收,按Ctrl-C不一定將執(zhí)行的程序立即停止梨睁。在這種情況下,你必須等待娜饵,直到控制返回Python解釋器坡贺,或者在更糟糕的情況下強(qiáng)制終止Python進(jìn)程。
從剪貼板執(zhí)行程序
如果使用Jupyter notebook,你可以將代碼復(fù)制粘貼到任意代碼格執(zhí)行遍坟。在IPython shell中也可以從剪貼板執(zhí)行拳亿。假設(shè)在其它應(yīng)用中復(fù)制了如下代碼:
x = 5
y = 7
if x > 5:
x += 1
y = 8
最簡單的方法是使用%paste
和%cpaste
函數(shù)。%paste
可以直接運(yùn)行剪貼板中的代碼:
In [17]: %paste
x = 5
y = 7
if x > 5:
x += 1
y = 8
## -- End pasted text --
%cpaste
功能類似愿伴,但會給出一條提示:
In [18]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:x = 5
:y = 7
:if x > 5:
: x += 1
:
: y = 8
:--
使用%cpaste
肺魁,你可以粘貼任意多的代碼再運(yùn)行。你可能想在運(yùn)行前隔节,先看看代碼鹅经。如果粘貼了錯誤的代碼,可以用Ctrl-C中斷官帘。
鍵盤快捷鍵
IPython有許多鍵盤快捷鍵進(jìn)行導(dǎo)航提示(類似Emacs文本編輯器或UNIX bash Shell)和交互shell的歷史命令。表2-1總結(jié)了常見的快捷鍵昧谊。圖2-5展示了一部分刽虹,如移動光標(biāo)。
Jupyter notebooks有另外一套龐大的快捷鍵呢诬。因?yàn)樗目旖萱I比IPython的變化快涌哲,建議你參閱Jupyter notebook的幫助文檔。
魔術(shù)命令
IPython中特殊的命令(Python中沒有)被稱作“魔術(shù)”命令尚镰。這些命令可以使普通任務(wù)更便捷阀圾,更容易控制IPython系統(tǒng)。魔術(shù)命令是在指令前添加百分號%前綴狗唉。例如初烘,可以用%timeit
(這個命令后面會詳談)測量任何Python語句,例如矩陣乘法分俯,的執(zhí)行時間:
In [20]: a = np.random.randn(100, 100)
In [20]: %timeit np.dot(a, a)
10000 loops, best of 3: 20.9 μs per loop
魔術(shù)命令可以被看做IPython中運(yùn)行的命令行肾筐。許多魔術(shù)命令有“命令行”選項(xiàng),可以通過缸剪?查看:
In [21]: %debug?
Docstring:
::
%debug [--breakpoint FILE:LINE] [statement [statement ...]]
Activate the interactive debugger.
This magic command support two ways of activating debugger.
One is to activate debugger before executing code. This way, you
can set a break point, to step through the code from the point.
You can use this mode by giving statements to execute and optionally
a breakpoint.
The other one is to activate debugger in post-mortem mode. You can
activate this mode simply running %debug without any argument.
If an exception has just occurred, this lets you inspect its stack
frames interactively. Note that this will always work only on the last
traceback that occurred, so you must call this quickly after an
exception that you wish to inspect has fired, because if another one
occurs, it clobbers the previous one.
If you want IPython to automatically do this on every exception, see
the %pdb magic for more details.
positional arguments:
statement Code to run in debugger. You can omit this in cell
magic mode.
optional arguments:
--breakpoint <FILE:LINE>, -b <FILE:LINE>
Set break point at LINE in FILE.
魔術(shù)函數(shù)默認(rèn)可以不用百分號吗铐,只要沒有變量和函數(shù)名相同。這個特點(diǎn)被稱為“自動魔術(shù)”杏节,可以用%automagic
打開或關(guān)閉唬渗。
一些魔術(shù)函數(shù)與Python函數(shù)很像,它的結(jié)果可以賦值給一個變量:
In [22]: %pwd
Out[22]: '/home/wesm/code/pydata-book
In [23]: foo = %pwd
In [24]: foo
Out[24]: '/home/wesm/code/pydata-book'
IPython的文檔可以在shell中打開奋渔,我建議你用%quickref
或%magic
學(xué)習(xí)下所有特殊命令镊逝。表2-2列出了一些可以提高生產(chǎn)率的交互計(jì)算和Python開發(fā)的IPython指令。
集成Matplotlib
IPython在分析計(jì)算領(lǐng)域能夠流行的原因之一是它非常好的集成了數(shù)據(jù)可視化和其它用戶界面庫嫉鲸,比如matplotlib蹋半。不用擔(dān)心以前沒用過matplotlib,本書后面會詳細(xì)介紹。%matplotlib
魔術(shù)函數(shù)配置了IPython shell和Jupyter notebook中的matplotlib减江。這點(diǎn)很重要染突,其它創(chuàng)建的圖不會出現(xiàn)(notebook)或獲取session的控制,直到結(jié)束(shell)辈灼。
在IPython shell中份企,運(yùn)行%matplotlib
可以進(jìn)行設(shè)置,可以創(chuàng)建多個繪圖窗口巡莹,而不會干擾控制臺session:
In [26]: %matplotlib
Using matplotlib backend: Qt4Agg
在JUpyter中司志,命令有所不同(圖2-6):
In [26]: %matplotlib inline
2.3 Python語法基礎(chǔ)
在本節(jié)中,我將概述基本的Python概念和語言機(jī)制降宅。在下一章骂远,我將詳細(xì)介紹Python的數(shù)據(jù)結(jié)構(gòu)、函數(shù)和其它內(nèi)建工具腰根。
語言的語義
Python的語言設(shè)計(jì)強(qiáng)調(diào)的是可讀性激才、簡潔和清晰。有些人稱Python為“可執(zhí)行的偽代碼”额嘿。
使用縮進(jìn)瘸恼,而不是括號
Python使用空白字符(tab和空格)來組織代碼,而不是像其它語言册养,比如R东帅、C++、JAVA和Perl那樣使用括號球拦】勘眨看一個排序算法的for
循環(huán):
for x in array:
if x < pivot:
less.append(x)
else:
greater.append(x)
冒號標(biāo)志著縮進(jìn)代碼塊的開始,冒號之后的所有代碼的縮進(jìn)量必須相同坎炼,直到代碼塊結(jié)束阎毅。不管是否喜歡這種形式,使用空白符是Python程序員開發(fā)的一部分点弯,在我看來扇调,這可以讓python的代碼可讀性大大優(yōu)于其它語言。雖然期初看起來很奇怪抢肛,經(jīng)過一段時間狼钮,你就能適應(yīng)了。
筆記:我強(qiáng)烈建議你使用四個空格作為默認(rèn)的縮進(jìn)捡絮,可以使用tab代替四個空格熬芜。許多文本編輯器的設(shè)置是使用制表位替代空格。某些人使用tabs或不同數(shù)目的空格數(shù)福稳,常見的是使用兩個空格涎拉。大多數(shù)情況下,四個空格是大多數(shù)人采用的方法,因此建議你也這樣做鼓拧。
你應(yīng)該已經(jīng)看到半火,Python的語句不需要用分號結(jié)尾。但是季俩,分號卻可以用來給同在一行的語句切分:
a = 5; b = 6; c = 7
Python不建議將多條語句放到一行钮糖,這會降低代碼的可讀性。
萬物皆對象
Python語言的一個重要特性就是它的對象模型的一致性酌住。每個數(shù)字店归、字符串、數(shù)據(jù)結(jié)構(gòu)酪我、函數(shù)消痛、類、模塊等等都哭,都是在Python解釋器的自有“盒子”內(nèi)秩伞,它被認(rèn)為是Python對象。每個對象都有類型(例如质涛,字符串或函數(shù))和內(nèi)部數(shù)據(jù)稠歉。在實(shí)際中掰担,這可以讓語言非常靈活汇陆,因?yàn)楹瘮?shù)也可以被當(dāng)做對象使用。
注釋
任何前面帶有井號#的文本都會被Python解釋器忽略带饱。這通常被用來添加注釋毡代。有時,你會想排除一段代碼勺疼,但并不刪除教寂。簡便的方法就是將其注釋掉:
results = []
for line in file_handle:
# keep the empty lines for now
# if len(line) == 0:
# continue
results.append(line.replace('foo', 'bar'))
也可以在執(zhí)行過的代碼后面添加注釋。一些人習(xí)慣在代碼之前添加注釋执庐,前者這種方法有時也是有用的:
print("Reached this line") # Simple status report
函數(shù)和對象方法調(diào)用
你可以用圓括號調(diào)用函數(shù)酪耕,傳遞零個或幾個參數(shù),或者將返回值給一個變量:
result = f(x, y, z)
g()
幾乎Python中的每個對象都有附加的函數(shù)轨淌,稱作方法迂烁,可以用來訪問對象的內(nèi)容〉蒺模可以用下面的語句調(diào)用:
obj.some_method(x, y, z)
函數(shù)可以使用位置和關(guān)鍵詞參數(shù):
result = f(a, b, c, d=5, e='foo')
后面會有更多介紹盟步。
變量和參數(shù)傳遞
當(dāng)在Python中創(chuàng)建變量(或名字),你就在等號右邊創(chuàng)建了一個對這個變量的引用躏结∪磁蹋考慮一個整數(shù)列表:
In [8]: a = [1, 2, 3]
假設(shè)將a賦值給一個新變量b:
In [9]: b = a
在有些方法中,這個賦值會將數(shù)據(jù)[1, 2, 3]也復(fù)制。在Python中黄橘,a和b實(shí)際上是同一個對象兆览,即原有列表[1, 2, 3](見圖2-7)。你可以在a中添加一個元素旬陡,然后檢查b:
In [10]: a.append(4)
In [11]: b
Out[11]: [1, 2, 3, 4]
理解Python的引用的含義拓颓,數(shù)據(jù)是何時、如何描孟、為何復(fù)制的驶睦,是非常重要的。尤其是當(dāng)你用Python處理大的數(shù)據(jù)集時匿醒。
筆記:賦值也被稱作綁定场航,我們是把一個名字綁定給一個對象。變量名有時可能被稱為綁定變量廉羔。
當(dāng)你將對象作為參數(shù)傳遞給函數(shù)時溉痢,新的局域變量創(chuàng)建了對原始對象的引用,而不是復(fù)制憋他。如果在函數(shù)里綁定一個新對象到一個變量孩饼,這個變動不會反映到上一層。因此可以改變可變參數(shù)的內(nèi)容竹挡。假設(shè)有以下函數(shù):
def append_element(some_list, element):
some_list.append(element)
然后有:
In [27]: data = [1, 2, 3]
In [28]: append_element(data, 4)
In [29]: data
Out[29]: [1, 2, 3, 4]
動態(tài)引用镀娶,強(qiáng)類型
與許多編譯語言(如JAVA和C++)對比,Python中的對象引用不包含附屬的類型揪罕。下面的代碼是沒有問題的:
In [12]: a = 5
In [13]: type(a)
Out[13]: int
In [14]: a = 'foo'
In [15]: type(a)
Out[15]: str
變量是在特殊命名空間中的對象的名字梯码,類型信息保存在對象自身中。一些人可能會說Python不是“類型化語言”好啰。這是不正確的轩娶,看下面的例子:
In [16]: '5' + 5
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-f9dbf5f0b234> in <module>()
----> 1 '5' + 5
TypeError: must be str, not int
在某些語言中,例如Visual Basic框往,字符串‘5’可能被默許轉(zhuǎn)換(或投射)為整數(shù)鳄抒,因此會產(chǎn)生10。但在其它語言中椰弊,例如JavaScript许溅,整數(shù)5會被投射成字符串,結(jié)果是聯(lián)結(jié)字符串‘55’男应。在這個方面闹司,Python被認(rèn)為是強(qiáng)類型化語言,意味著每個對象都有明確的類型(或類)沐飘,默許轉(zhuǎn)換只會發(fā)生在特定的情況下游桩,例如:
In [17]: a = 4.5
In [18]: b = 2
# String formatting, to be visited later
In [19]: print('a is {0}, b is {1}'.format(type(a), type(b)))
a is <class 'float'>, b is <class 'int'>
In [20]: a / b
Out[20]: 2.25
知道對象的類型很重要牲迫,最好能讓函數(shù)可以處理多種類型的輸入。你可以用isinstance
函數(shù)檢查對象是某個類型的實(shí)例:
In [21]: a = 5
In [22]: isinstance(a, int)
Out[22]: True
isinstance
可以用類型元組借卧,檢查對象的類型是否在元組中:
In [23]: a = 5; b = 4.5
In [24]: isinstance(a, (int, float))
Out[24]: True
In [25]: isinstance(b, (int, float))
Out[25]: True
屬性和方法
Python的對象通常都有屬性(其它存儲在對象內(nèi)部的Python對象)和方法(對象的附屬函數(shù)可以訪問對象的內(nèi)部數(shù)據(jù))盹憎。可以用obj.attribute_name
訪問屬性和方法:
In [1]: a = 'foo'
In [2]: a.<Press Tab>
a.capitalize a.format a.isupper a.rindex a.strip
a.center a.index a.join a.rjust a.swapcase
a.count a.isalnum a.ljust a.rpartition a.title
a.decode a.isalpha a.lower a.rsplit a.translate
a.encode a.isdigit a.lstrip a.rstrip a.upper
a.endswith a.islower a.partition a.split a.zfill
a.expandtabs a.isspace a.replace a.splitlines
a.find a.istitle a.rfind a.startswith
也可以用getattr
函數(shù)铐刘,通過名字訪問屬性和方法:
In [27]: getattr(a, 'split')
Out[27]: <function str.split>
在其它語言中陪每,訪問對象的名字通常稱作“反射”。本書不會大量使用getattr
函數(shù)和相關(guān)的hasattr
和setattr
函數(shù)镰吵,使用這些函數(shù)可以高效編寫原生的檩禾、可重復(fù)使用的代碼。
鴨子類型
經(jīng)常地疤祭,你可能不關(guān)心對象的類型盼产,只關(guān)心對象是否有某些方法或用途。這通常被稱為“鴨子類型”勺馆,來自“走起來像鴨子戏售、叫起來像鴨子,那么它就是鴨子”的說法草穆。例如灌灾,你可以通過驗(yàn)證一個對象是否遵循迭代協(xié)議,判斷它是可迭代的悲柱。對于許多對象锋喜,這意味著它有一個__iter__
魔術(shù)方法,其它更好的判斷方法是使用iter
函數(shù):
def isiterable(obj):
try:
iter(obj)
return True
except TypeError: # not iterable
return False
這個函數(shù)會返回字符串以及大多數(shù)Python集合類型為True
:
In [29]: isiterable('a string')
Out[29]: True
In [30]: isiterable([1, 2, 3])
Out[30]: True
In [31]: isiterable(5)
Out[31]: False
我總是用這個功能編寫可以接受多種輸入類型的函數(shù)诗祸。常見的例子是編寫一個函數(shù)可以接受任意類型的序列(list跑芳、tuple轴总、ndarray)或是迭代器直颅。你可先檢驗(yàn)對象是否是列表(或是NUmPy數(shù)組),如果不是的話怀樟,將其轉(zhuǎn)變成列表:
if not isinstance(x, list) and isiterable(x):
x = list(x)
引入
在Python中功偿,模塊就是一個有.py
擴(kuò)展名、包含Python代碼的文件往堡。假設(shè)有以下模塊:
# some_module.py
PI = 3.14159
def f(x):
return x + 2
def g(a, b):
return a + b
如果想從同目錄下的另一個文件訪問some_module.py
中定義的變量和函數(shù)械荷,可以:
import some_module
result = some_module.f(5)
pi = some_module.PI
或者:
from some_module import f, g, PI
result = g(5, PI)
使用as
關(guān)鍵詞,你可以給引入起不同的變量名:
import some_module as sm
from some_module import PI as pi, g as gf
r1 = sm.f(pi)
r2 = gf(6, pi)
二元運(yùn)算符和比較運(yùn)算符
大多數(shù)二元數(shù)學(xué)運(yùn)算和比較都不難想到:
In [32]: 5 - 7
Out[32]: -2
In [33]: 12 + 21.5
Out[33]: 33.5
In [34]: 5 <= 2
Out[34]: False
表2-3列出了所有的二元運(yùn)算符虑灰。
要判斷兩個引用是否指向同一個對象吨瞎,可以使用is
方法。is not
可以判斷兩個對象是不同的:
In [35]: a = [1, 2, 3]
In [36]: b = a
In [37]: c = list(a)
In [38]: a is b
Out[38]: True
In [39]: a is not c
Out[39]: True
因?yàn)?code>list總是創(chuàng)建一個新的Python列表(即復(fù)制)穆咐,我們可以斷定c是不同于a的颤诀。使用is
比較與==
運(yùn)算符不同字旭,如下:
In [40]: a == c
Out[40]: True
is
和is not
常用來判斷一個變量是否為None
,因?yàn)橹挥幸粋€None
的實(shí)例:
In [41]: a = None
In [42]: a is None
Out[42]: True
可變與不可變對象
Python中的大多數(shù)對象崖叫,比如列表遗淳、字典、NumPy數(shù)組心傀,和用戶定義的類型(類)屈暗,都是可變的。意味著這些對象或包含的值可以被修改:
In [43]: a_list = ['foo', 2, [4, 5]]
In [44]: a_list[2] = (3, 4)
In [45]: a_list
Out[45]: ['foo', 2, (3, 4)]
其它的脂男,例如字符串和元組养叛,是不可變的:
In [46]: a_tuple = (3, 5, (4, 5))
In [47]: a_tuple[1] = 'four'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-47-b7966a9ae0f1> in <module>()
----> 1 a_tuple[1] = 'four'
TypeError: 'tuple' object does not support item assignment
記住,可以修改一個對象并不意味就要修改它宰翅。這被稱為副作用一铅。例如,當(dāng)寫一個函數(shù)堕油,任何副作用都要在文檔或注釋中寫明潘飘。如果可能的話,我推薦避免副作用掉缺,采用不可變的方式卜录,即使要用到可變對象。
標(biāo)量類型
Python的標(biāo)準(zhǔn)庫中有一些內(nèi)建的類型眶明,用于處理數(shù)值數(shù)據(jù)艰毒、字符串、布爾值搜囱,和日期時間丑瞧。這些單值類型被稱為標(biāo)量類型,本書中稱其為標(biāo)量蜀肘。表2-4列出了主要的標(biāo)量绊汹。日期和時間處理會另外討論,因?yàn)樗鼈兪菢?biāo)準(zhǔn)庫的datetime
模塊提供的扮宠。
數(shù)值類型
Python的主要數(shù)值類型是int
和float
西乖。int
可以存儲任意大的數(shù):
In [48]: ival = 17239871
In [49]: ival ** 6
Out[49]: 26254519291092456596965462913230729701102721
浮點(diǎn)數(shù)使用Python的float
類型。每個數(shù)都是雙精度(64位)的值坛增。也可以用科學(xué)計(jì)數(shù)法表示:
In [50]: fval = 7.243
In [51]: fval2 = 6.78e-5
不能得到整數(shù)的除法會得到浮點(diǎn)數(shù):
In [52]: 3 / 2
Out[52]: 1.5
要獲得C-風(fēng)格的整除(去掉小數(shù)部分)获雕,可以使用底除運(yùn)算符//:
In [53]: 3 // 2
Out[53]: 1
字符串
許多人是因?yàn)镻ython強(qiáng)大而靈活的字符串處理而使用Python的。你可以用單引號或雙引號來寫字符串:
a = 'one way of writing a string'
b = "another way"
對于有換行符的字符串收捣,可以使用三引號届案,'''或"""都行:
c = """
This is a longer string that
spans multiple lines
"""
字符串c
實(shí)際包含四行文本,"""后面和lines后面的換行符罢艾¢沟撸可以用count
方法計(jì)算c
中的新的行:
In [55]: c.count('\n')
Out[55]: 3
Python的字符串是不可變的嫁乘,不能修改字符串:
In [56]: a = 'this is a string'
In [57]: a[10] = 'f'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-57-5ca625d1e504> in <module>()
----> 1 a[10] = 'f'
TypeError: 'str' object does not support item assignment
In [58]: b = a.replace('string', 'longer string')
In [59]: b
Out[59]: 'this is a longer string'
經(jīng)過以上的操作,變量a
并沒有被修改:
In [60]: a
Out[60]: 'this is a string'
許多Python對象使用str
函數(shù)可以被轉(zhuǎn)化為字符串:
In [61]: a = 5.6
In [62]: s = str(a)
In [63]: print(s)
5.6
字符串是一個序列的Unicode字符球碉,因此可以像其它序列蜓斧,比如列表和元組(下一章會詳細(xì)介紹兩者)一樣處理:
In [64]: s = 'python'
In [65]: list(s)
Out[65]: ['p', 'y', 't', 'h', 'o', 'n']
In [66]: s[:3]
Out[66]: 'pyt'
語法s[:3]
被稱作切片,適用于許多Python序列睁冬。后面會更詳細(xì)的介紹挎春,本書中用到很多切片。
反斜杠是轉(zhuǎn)義字符豆拨,意思是它備用來表示特殊字符直奋,比如換行符\n或Unicode字符。要寫一個包含反斜杠的字符串施禾,需要進(jìn)行轉(zhuǎn)義:
In [67]: s = '12\\34'
In [68]: print(s)
12\34
如果字符串中包含許多反斜杠脚线,但沒有特殊字符,這樣做就很麻煩弥搞。幸好邮绿,可以在字符串前面加一個r,表明字符就是它自身:
In [69]: s = r'this\has\no\special\characters'
In [70]: s
Out[70]: 'this\\has\\no\\special\\characters'
r表示raw攀例。
將兩個字符串合并船逮,會產(chǎn)生一個新的字符串:
In [71]: a = 'this is the first half '
In [72]: b = 'and this is the second half'
In [73]: a + b
Out[73]: 'this is the first half and this is the second half'
字符串的模板化或格式化,是另一個重要的主題粤铭。Python 3拓展了此類的方法挖胃,這里只介紹一些。字符串對象有format
方法梆惯,可以替換格式化的參數(shù)為字符串酱鸭,產(chǎn)生一個新的字符串:
In [74]: template = '{0:.2f} {1:s} are worth US${2:d}'
在這個字符串中,
-
{0:.2f}
表示格式化第一個參數(shù)為帶有兩位小數(shù)的浮點(diǎn)數(shù)垛吗。 -
{1:s}
表示格式化第二個參數(shù)為字符串凹髓。 -
{2:d}
表示格式化第三個參數(shù)為一個整數(shù)。
要替換參數(shù)為這些格式化的參數(shù)职烧,我們傳遞format
方法一個序列:
In [75]: template.format(4.5560, 'Argentine Pesos', 1)
Out[75]: '4.56 Argentine Pesos are worth US$1'
字符串格式化是一個很深的主題扁誓,有多種方法和大量的選項(xiàng)防泵,可以控制字符串中的值是如何格式化的蚀之。推薦參閱Python官方文檔。
這里概括介紹字符串處理捷泞,第8章的數(shù)據(jù)分析會詳細(xì)介紹足删。
字節(jié)和Unicode
在Python 3及以上版本中,Unicode是一級的字符串類型锁右,這樣可以更一致的處理ASCII和Non-ASCII文本失受。在老的Python版本中讶泰,字符串都是字節(jié),不使用Unicode編碼拂到。假如知道字符編碼痪署,可以將其轉(zhuǎn)化為Unicode⌒盅看一個例子:
In [76]: val = "espa?ol"
In [77]: val
Out[77]: 'espa?ol'
可以用encode
將這個Unicode字符串編碼為UTF-8:
In [78]: val_utf8 = val.encode('utf-8')
In [79]: val_utf8
Out[79]: b'espa\xc3\xb1ol'
In [80]: type(val_utf8)
Out[80]: bytes
如果你知道一個字節(jié)對象的Unicode編碼狼犯,用decode
方法可以解碼:
In [81]: val_utf8.decode('utf-8')
Out[81]: 'espa?ol'
雖然UTF-8編碼已經(jīng)變成主流,但因?yàn)闅v史的原因领铐,你仍然可能碰到其它編碼的數(shù)據(jù):
In [82]: val.encode('latin1')
Out[82]: b'espa\xf1ol'
In [83]: val.encode('utf-16')
Out[83]: b'\xff\xfee\x00s\x00p\x00a\x00\xf1\x00o\x00l\x00'
In [84]: val.encode('utf-16le')
Out[84]: b'e\x00s\x00p\x00a\x00\xf1\x00o\x00l\x00'
工作中碰到的文件很多都是字節(jié)對象悯森,盲目地將所有數(shù)據(jù)編碼為Unicode是不可取的。
雖然用的不多绪撵,你可以在字節(jié)文本的前面加上一個b:
In [85]: bytes_val = b'this is bytes'
In [86]: bytes_val
Out[86]: b'this is bytes'
In [87]: decoded = bytes_val.decode('utf8')
In [88]: decoded # this is str (Unicode) now
Out[88]: 'this is bytes'
布爾值
Python中的布爾值有兩個瓢姻,True和False。比較和其它條件表達(dá)式可以用True和False判斷音诈。布爾值可以與and和or結(jié)合使用:
In [89]: True and True
Out[89]: True
In [90]: False or True
Out[90]: True
類型轉(zhuǎn)換
str幻碱、bool、int和float也是函數(shù)细溅,可以用來轉(zhuǎn)換類型:
In [91]: s = '3.14159'
In [92]: fval = float(s)
In [93]: type(fval)
Out[93]: float
In [94]: int(fval)
Out[94]: 3
In [95]: bool(fval)
Out[95]: True
In [96]: bool(0)
Out[96]: False
None
None是Python的空值類型收班。如果一個函數(shù)沒有明確的返回值,就會默認(rèn)返回None:
In [97]: a = None
In [98]: a is None
Out[98]: True
In [99]: b = 5
In [100]: b is not None
Out[100]: True
None也常常作為函數(shù)的默認(rèn)參數(shù):
def add_and_maybe_multiply(a, b, c=None):
result = a + b
if c is not None:
result = result * c
return result
另外谒兄,None不僅是一個保留字摔桦,還是唯一的NoneType的實(shí)例:
In [101]: type(None)
Out[101]: NoneType
日期和時間
Python內(nèi)建的datetime
模塊提供了datetime
、date
和time
類型承疲。datetime
類型結(jié)合了date
和time
邻耕,是最常使用的:
In [102]: from datetime import datetime, date, time
In [103]: dt = datetime(2011, 10, 29, 20, 30, 21)
In [104]: dt.day
Out[104]: 29
In [105]: dt.minute
Out[105]: 30
根據(jù)datetime
實(shí)例,你可以用date
和time
提取出各自的對象:
In [106]: dt.date()
Out[106]: datetime.date(2011, 10, 29)
In [107]: dt.time()
Out[107]: datetime.time(20, 30, 21)
strftime
方法可以將datetime格式化為字符串:
In [108]: dt.strftime('%m/%d/%Y %H:%M')
Out[108]: '10/29/2011 20:30'
strptime
可以將字符串轉(zhuǎn)換成datetime
對象:
In [109]: datetime.strptime('20091031', '%Y%m%d')
Out[109]: datetime.datetime(2009, 10, 31, 0, 0)
表2-5列出了所有的格式化命令燕鸽。
當(dāng)你聚類或?qū)r間序列進(jìn)行分組兄世,替換datetimes的time字段有時會很有用。例如啊研,用0替換分和秒:
In [110]: dt.replace(minute=0, second=0)
Out[110]: datetime.datetime(2011, 10, 29, 20, 0)
因?yàn)?code>datetime.datetime是不可變類型御滩,上面的方法會產(chǎn)生新的對象。
兩個datetime對象的差會產(chǎn)生一個datetime.timedelta
類型:
In [111]: dt2 = datetime(2011, 11, 15, 22, 30)
In [112]: delta = dt2 - dt
In [113]: delta
Out[113]: datetime.timedelta(17, 7179)
In [114]: type(delta)
Out[114]: datetime.timedelta
結(jié)果timedelta(17, 7179)
指明了timedelta
將17天党远、7179秒的編碼方式削解。
將timedelta
添加到datetime
,會產(chǎn)生一個新的偏移datetime
:
In [115]: dt
Out[115]: datetime.datetime(2011, 10, 29, 20, 30, 21)
In [116]: dt + delta
Out[116]: datetime.datetime(2011, 11, 15, 22, 30)
控制流
Python有若干內(nèi)建的關(guān)鍵字進(jìn)行條件邏輯沟娱、循環(huán)和其它控制流操作氛驮。
if、elif和else
if是最廣為人知的控制流語句济似。它檢查一個條件矫废,如果為True盏缤,就執(zhí)行后面的語句:
if x < 0:
print('It's negative')
if
后面可以跟一個或多個elif
,所有條件都是False時蓖扑,還可以添加一個else
:
if x < 0:
print('It's negative')
elif x == 0:
print('Equal to zero')
elif 0 < x < 5:
print('Positive but smaller than 5')
else:
print('Positive and larger than or equal to 5')
如果某個條件為True唉铜,后面的elif
就不會被執(zhí)行颅崩。當(dāng)使用and和or時浙巫,復(fù)合條件語句是從左到右執(zhí)行:
In [117]: a = 5; b = 7
In [118]: c = 8; d = 4
In [119]: if a < b or c > d:
.....: print('Made it')
Made it
在這個例子中,c > d
不會被執(zhí)行途乃,因?yàn)榈谝粋€比較是True:
也可以把比較式串在一起:
In [120]: 4 > 3 > 2 > 1
Out[120]: True
for循環(huán)
for循環(huán)是在一個集合(列表或元組)中進(jìn)行迭代俩功,或者就是一個迭代器幻枉。for循環(huán)的標(biāo)準(zhǔn)語法是:
for value in collection:
# do something with value
你可以用continue使for循環(huán)提前,跳過剩下的部分诡蜓“靖Γ看下面這個例子,將一個列表中的整數(shù)相加蔓罚,跳過None:
sequence = [1, 2, None, 4, None, 5]
total = 0
for value in sequence:
if value is None:
continue
total += value
可以用break
跳出for循環(huán)椿肩。下面的代碼將各元素相加,直到遇到5:
sequence = [1, 2, 0, 4, 6, 5, 2, 1]
total_until_5 = 0
for value in sequence:
if value == 5:
break
total_until_5 += value
break只中斷for循環(huán)的最內(nèi)層豺谈,其余的for循環(huán)仍會運(yùn)行:
In [121]: for i in range(4):
.....: for j in range(4):
.....: if j > i:
.....: break
.....: print((i, j))
.....:
(0, 0)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
(2, 2)
(3, 0)
(3, 1)
(3, 2)
(3, 3)
如果集合或迭代器中的元素序列(元組或列表)郑象,可以用for循環(huán)將其方便地拆分成變量:
for a, b, c in iterator:
# do something
While循環(huán)
while循環(huán)指定了條件和代碼,當(dāng)條件為False或用break退出循環(huán)茬末,代碼才會退出:
x = 256
total = 0
while x > 0:
if total > 500:
break
total += x
x = x // 2
pass
pass是Python中的非操作語句厂榛。代碼塊不需要任何動作時可以使用(作為未執(zhí)行代碼的占位符);因?yàn)镻ython需要使用空白字符劃定代碼塊丽惭,所以需要pass:
if x < 0:
print('negative!')
elif x == 0:
# TODO: put something smart here
pass
else:
print('positive!')
range
range函數(shù)返回一個迭代器击奶,它產(chǎn)生一個均勻分布的整數(shù)序列:
In [122]: range(10)
Out[122]: range(0, 10)
In [123]: list(range(10))
Out[123]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range的三個參數(shù)是(起點(diǎn),終點(diǎn)责掏,步進(jìn)):
In [124]: list(range(0, 20, 2))
Out[124]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
In [125]: list(range(5, 0, -1))
Out[125]: [5, 4, 3, 2, 1]
可以看到柜砾,range產(chǎn)生的整數(shù)不包括終點(diǎn)。range的常見用法是用序號迭代序列:
seq = [1, 2, 3, 4]
for i in range(len(seq)):
val = seq[i]
可以使用list來存儲range在其他數(shù)據(jù)結(jié)構(gòu)中生成的所有整數(shù)换衬,默認(rèn)的迭代器形式通常是你想要的痰驱。下面的代碼對0到99999中3或5的倍數(shù)求和:
sum = 0
for i in range(100000):
# % is the modulo operator
if i % 3 == 0 or i % 5 == 0:
sum += i
雖然range可以產(chǎn)生任意大的數(shù),但任意時刻耗用的內(nèi)存卻很小瞳浦。
三元表達(dá)式
Python中的三元表達(dá)式可以將if-else語句放到一行里担映。語法如下:
value = true-expr if condition else false-expr
true-expr
或false-expr
可以是任何Python代碼。它和下面的代碼效果相同:
if condition:
value = true-expr
else:
value = false-expr
下面是一個更具體的例子:
In [126]: x = 5
In [127]: 'Non-negative' if x >= 0 else 'Negative'
Out[127]: 'Non-negative'
和if-else一樣术幔,只有一個表達(dá)式會被執(zhí)行另萤。因此,三元表達(dá)式中的if和else可以包含大量的計(jì)算诅挑,但只有True的分支會被執(zhí)行四敞。因此,三元表達(dá)式中的if和else可以包含大量的計(jì)算拔妥,但只有True的分支會被執(zhí)行忿危。
雖然使用三元表達(dá)式可以壓縮代碼,但會降低代碼可讀性没龙。