# 1.2 Python語言
> 作者 Chris Burns, Christophe Combelles, Emmanuelle Gouillart, Gae?l Varoquaux
> **Python中的科學計算** 這里我們介紹Python語言。這里只會僅僅解決可以用于Numpy和Scipy的最低要求。想要更多的了解這門語言,請參考[http://docs.python.org/tutorial](http://docs.python.org/tutorial) 這個非常好的教程。也可以借助專門的圖書,比如:[http://diveintopython.org/](http://diveintopython.org/).
Python是一門**編程語言**,與C、Fortran、BASIC和PHP等等類似。Python的一些特性如下:
* 一種_解釋性_(不是編譯)語言。與C或者Fortran等不同,Python代碼在執行前不會編譯。另外,Python可以**交互**使用:有許多的Python解釋器,命令和腳本可以在其中執行。
* 在**開源**證書下發布的免費軟件:Python可以免費使用和分發,即使用于商用。
* **多平臺**:Python可以用于所有的主流操作系統,Windows、Linux/Unix、MacOS X, 甚至可能是你有手機操作系統等等。
* 可讀性很強的語言,有清晰不羅嗦的語法
* 擁有大量高質量的包,可以應用于多種多樣的應用,從網站框架到科學計算。
* 非常簡單的接口與其他語言交互,特別是C和C++
* 稍后會介紹一些語言的其他特性。例如Python是面向對象的語言,包含動態類型(一個變量可以在程序過程中,可以包含不同的對象類型)。
Python的特有特性的更多信息,請見:[http://www.python.org/about/](http://www.python.org/about/)
## 1.2.1 第一步
啟動**IPython** Shell(一個增強的Python交互Shell):
* 在Linux/Mac終端中輸入“ipython”,或者在Windows cmd sheell,
* 或者從菜單啟動程序,即在[Python(x,y)](http://www.pythonxy.com/)或[EPD](http://www.enthought.com/products/epd.php),如果你已經安裝這些Python科學套裝之一。
如果你的電腦上還沒有安裝IPython,也可以選擇其他Python shells,比如在終端中輸入“Python”啟動純Python shell,或者Idle解釋器。但是,我們建議使用IPython Shell,因為它增強特性,特別是對于科學計算。
如果你已經啟動了解釋器,輸入
In?[2]:
```
print "Hello, world!"
```
```
Hello, world!
```
接下來就會顯示信息"Hello, world!"。你已經執行了你的第一條Python命令,恭喜!
你自己開始吧,輸入下列命令
In?[1]:
```
a = 3
b = 2*a
type(b)
```
Out[1]:
```
int
```
In?[2]:
```
print b
```
```
6
```
In?[3]:
```
a*b
```
Out[3]:
```
18
```
In?[4]:
```
b = 'hello'
type(b)
```
Out[4]:
```
str
```
In?[5]:
```
b + b
```
Out[5]:
```
'hellohello'
```
In?[6]:
```
2*b
```
Out[6]:
```
'hellohello'
```
上面定義了_a_和_b_兩個變量。注意這里在賦值前沒有聲明變量類型。相反,在C中,應該寫為:
```
int a=3;
```
另外,變量的類型可以改變,在一個時間點它可以等于一個特定類型,在接下來的時間里,他可以等于另外的類型。_b_首先等于整數,但是當它被賦值為_"hello"_時他變成等于字符。在Python中,整數的運算符(b=2*a)原生支持的,一些字符上的操作符例如相加和相乘也是支持的,相當于串聯和重復。
## 1.2.2 基礎類型
### 1.2.2.1 數值類型
Python支持如下的數值、標量類型:
**整型:**
In?[8]:
```
1 + 1
```
Out[8]:
```
2
```
In?[11]:
```
a = 4
type(a)
```
Out[11]:
```
int
```
**浮點型:**
In?[12]:
```
c = 2.1
type(c)
```
Out[12]:
```
float
```
**復數:**
In?[13]:
```
a = 1.5 + 0.5j
a.real
```
Out[13]:
```
1.5
```
In?[14]:
```
a.imag
```
Out[14]:
```
0.5
```
In?[15]:
```
type(1. + 0j )
```
Out[15]:
```
complex
```
**布爾:**
In?[16]:
```
3 > 4
```
Out[16]:
```
False
```
In?[17]:
```
test = (3 > 4)
test
```
Out[17]:
```
False
```
In?[18]:
```
type(test)
```
Out[18]:
```
bool
```
因此,Python shell可以代替你的口袋計算器,因為基本的代數操作符 +、-、*、/、%(模)都已經原生實現了。
In?[19]:
```
7 * 3.
```
Out[19]:
```
21.0
```
In?[20]:
```
2**10
```
Out[20]:
```
1024
```
In?[21]:
```
8 % 3
```
Out[21]:
```
2
```
類型轉化(投射):
In?[22]:
```
float(1)
```
Out[22]:
```
1.0
```
**注意**:整數相除
In?[23]:
```
3 / 2
```
Out[23]:
```
1
```
**技巧**:使用浮點:
In?[24]:
```
3 / 2.
```
Out[24]:
```
1.5
```
In?[25]:
```
a = 3
b = 2
a / b
```
Out[25]:
```
1
```
In?[26]:
```
a / float(b)
```
Out[26]:
```
1.5
```
如果你明確想要整除,請使用//:
In?[27]:
```
3.0 // 2
```
Out[27]:
```
1.0
```
Python3改變了除運算符行為。細節請看[python3porting](http://python3porting.com/preparing.html#use-instead-of-when-dividing-integers)網站.
### 1.2.2.2 容器
Python提供了許多有效的容器類型,其中存儲了對象集合。
#### 1.2.2.2.1 列表
列表是一個有序的對象集合,對象可以有多種類型。例如:
In?[28]:
```
L = ['red', 'blue', 'green', 'black', 'white']
type(L)
```
Out[28]:
```
list
```
索引:訪問包含在列表中的單個對象:
In?[29]:
```
L[2]
```
Out[29]:
```
'green'
```
使用負索引,從結尾開始計數:
In?[30]:
```
L[-1]
```
Out[30]:
```
'white'
```
In?[31]:
```
L[-2]
```
Out[31]:
```
'black'
```
**注意:索引從0開始**(和C中一樣),而不是1(像在Fortran或Matlab)!
切片:獲得規律分布元素的子列表:
In?[32]:
```
L
```
Out[32]:
```
['red', 'blue', 'green', 'black', 'white']
```
In?[33]:
```
L[2:4]
```
Out[33]:
```
['green', 'black']
```
**注意**:L[start:stop]包含索引start<= i < stop的元素(i的范圍從start到stop-1)。因此,L[start:stop]包含(stop-start)個元素。
**切片語法**:`L[start:stop:stride]`
所有切片參數都是可選的:
In?[34]:
```
L
```
Out[34]:
```
['red', 'blue', 'green', 'black', 'white']
```
In?[35]:
```
L[3:]
```
Out[35]:
```
['black', 'white']
```
In?[36]:
```
L[:3]
```
Out[36]:
```
['red', 'blue', 'green']
```
列表是可變對象,可以被改變:
In?[38]:
```
L[0] = 'yellow'
L
```
Out[38]:
```
['yellow', 'blue', 'green', 'black', 'white']
```
In?[39]:
```
L[2:4] = ['gray', 'purple']
L
```
Out[39]:
```
['yellow', 'blue', 'gray', 'purple', 'white']
```
**注:**一個列表的元素可以有不同的類型:
In?[40]:
```
L = [3, -200, 'hello']
L
```
Out[40]:
```
[3, -200, 'hello']
```
In?[41]:
```
L[1], L[2]
```
Out[41]:
```
(-200, 'hello')
```
對于一個所有類型都相同的數值數據集合,使用Numpy模塊提供的數組類型通常更有效。Numpy數組是包含固定大小項目的內存組塊。使用Numpy數組,元素上的操作可以非常快速,因為元素均勻分布在內存上并且更多的操作是通過特殊的C函數而不是Python循環。
Python提供了一大組函數來修改或查詢列表。這里是一些例子,更多內容,請見:[http://docs.python.org/tutorial/datastructures.html#more-on-lists](http://docs.python.org/tutorial/datastructures.html#more-on-lists)
添加和刪除元素:
In?[42]:
```
L = ['red', 'blue', 'green', 'black', 'white']
L.append('pink')
L
```
Out[42]:
```
['red', 'blue', 'green', 'black', 'white', 'pink']
```
In?[43]:
```
L.pop() # 刪除并返回最后一個項目
```
Out[43]:
```
'pink'
```
In?[44]:
```
L
```
Out[44]:
```
['red', 'blue', 'green', 'black', 'white']
```
In?[45]:
```
L.extend(['pink', 'purple']) # 擴展列表L,原地
L
```
In?[46]:
```
L = L[:-2]
L
```
Out[46]:
```
['red', 'blue', 'green', 'black', 'white']
```
反轉:
In?[47]:
```
r = L[::-1]
r
```
Out[47]:
```
['white', 'black', 'green', 'blue', 'red']
```
In?[48]:
```
r2 = list(L)
r2
```
Out[48]:
```
['red', 'blue', 'green', 'black', 'white']
```
In?[49]:
```
r2.reverse() # 原對象
r2
```
Out[49]:
```
['white', 'black', 'green', 'blue', 'red']
```
串聯和重復列表:
In?[50]:
```
r + L
```
Out[50]:
```
['white',
'black',
'green',
'blue',
'red',
'red',
'blue',
'green',
'black',
'white']
```
In?[51]:
```
r * 2
```
Out[51]:
```
['white',
'black',
'green',
'blue',
'red',
'white',
'black',
'green',
'blue',
'red']
```
排序:
In?[52]:
```
sorted(r) # 新對象
```
Out[52]:
```
['black', 'blue', 'green', 'red', 'white']
```
In?[53]:
```
r
```
Out[53]:
```
['white', 'black', 'green', 'blue', 'red']
```
In?[55]:
```
r.sort() # 原對象
r
```
Out[55]:
```
['black', 'blue', 'green', 'red', 'white']
```
**方法和面向對象編程**
符號r.method() (即 r.append(3) and L.pop()) 是我們第一個關于面向對象編程的例子(OOP)。作為列表,對象r有可以以這種方式調用的方法函數。對于這篇教程不需要關于面向對象編程的更多知識,只需要理解這種符號。
**發現方法**:
提醒:在IPython中:tab完成 (按tab)
```
In [28]: r.<TAB>
r.__add__ r.__iadd__ r.__setattr__
r.__class__ r.__imul__ r.__setitem__
r.__contains__ r.__init__ r.__setslice__
r.__delattr__ r.__iter__ r.__sizeof__
r.__delitem__ r.__le__ r.__str__
r.__delslice__ r.__len__ r.__subclasshook__
r.__doc__ r.__lt__ r.append
r.__eq__ r.__mul__ r.count
r.__format__ r.__ne__ r.extend
r.__ge__ r.__new__ r.index
r.__getattribute__ r.__reduce__ r.insert
r.__getitem__ r.__reduce_ex__ r.pop
r.__getslice__ r.__repr__ r.remove
r.__gt__ r.__reversed__ r.reverse
r.__hash__ r.__rmul__ r.sort
```
#### 1.2.2.2.2 字符
不同的字符語法(單引號、雙引號或三個引號):
In?[58]:
```
s = 'Hello, how are you?'
s = "Hi, what's up"
s = '''Hello,
how are you''' # 三個引號可以允許字符跨行
s = """Hi,
what's up?"""
'Hi, what's up?'
```
```
File "<ipython-input-58-dfe00f996c26>", line 7
'Hi, what's up?'
^
SyntaxError: invalid syntax
```
如果在字符中要是使用引號,那么應該嵌套使用,或者使用"\"進行轉義,否則會報錯。
換行的符號為 \n,tab符號是\t。
字符也是類似與列表的結合。因此,也可以使用相同的語法和規則索引和切片。
索引:
In?[59]:
```
a = "hello"
a[0]
```
Out[59]:
```
'h'
```
In?[60]:
```
a[1]
```
Out[60]:
```
'e'
```
In?[61]:
```
a[-1]
```
Out[61]:
```
'o'
```
(記住負索引從右側開始計數。)
切片:
In?[64]:
```
a = "hello, world!"
a[3:6] # 第三到第六個(不包含)元素:元素3、4、5
```
Out[64]:
```
'lo,'
```
In?[65]:
```
a[2:10:2] # 語法:a[開始:結束:步幅]
```
Out[65]:
```
'lo o'
```
In?[66]:
```
a[::3] # 從開始到結尾,每隔3個字母
```
Out[66]:
```
'hl r!'
```
重音符號和特殊字符也可以被處理為Unicode字符(請見 [http://docs.python.org/tutorial/introduction.html#unicode-strings)。](http://docs.python.org/tutorial/introduction.html#unicode-strings)。)
字符是**不可變**對象,不可能修改內容。不過可以從原始的字符中創建一個新的字符。
In?[68]:
```
a = "hello, world!"
a[2] = 'z'
```
```
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-68-8f124c87c8cf> in <module>()
1 a = "hello, world!"
----> 2 a[2] = 'z'
TypeError: 'str' object does not support item assignment
```
In?[69]:
```
a.replace('l', 'z', 1)
```
Out[69]:
```
'hezlo, world!'
```
In?[70]:
```
a.replace('l', 'z')
```
Out[70]:
```
'hezzo, worzd!'
```
字符有許多有用的方法,比如上面的a.replace。回憶一下a.面向對象的符號,并且使用tab完成或者help(str)來搜索新的方法。and use tab completion or
**更多內容** Python提供了操作的字符的高級可能性,看一下模式或格式。感興趣的讀者請參考:[http://docs.python.org/library/stdtypes.html#string-methods](http://docs.python.org/library/stdtypes.html#string-methods) 和 [http://docs.python.org/library/string.html#new-string-formatting。](http://docs.python.org/library/string.html#new-string-formatting。)
字符格式:
In?[71]:
```
'An integer: %i; a float: %f; another string: %s' % (1, 0.1, 'string')
```
Out[71]:
```
'An integer: 1; a float: 0.100000; another string: string'
```
In?[72]:
```
i = 102
filename = 'processing_of_dataset_%d.txt' % i
filename
```
Out[72]:
```
'processing_of_dataset_102.txt'
```
#### 1.2.2.2.3\. Dictionaries
字典本質上是一個**映射鍵值**的高效表格。它是一個**無序**的容器
In?[74]:
```
tel = {'emmanuelle': 5752, 'sebastian': 5578}
tel['francis'] = 5915
tel
```
Out[74]:
```
{'emmanuelle': 5752, 'francis': 5915, 'sebastian': 5578}
```
In?[75]:
```
tel['sebastian']
```
Out[75]:
```
5578
```
In?[76]:
```
tel.keys()
```
Out[76]:
```
['sebastian', 'francis', 'emmanuelle']
```
In?[77]:
```
tel.values()
```
Out[77]:
```
[5578, 5915, 5752]
```
它可以方便的以名字(日期的字符和名稱等)存儲和獲取值。更多信息見 [http://docs.python.org/tutorial/datastructures.html#dictionaries。](http://docs.python.org/tutorial/datastructures.html#dictionaries。)
一個字典的鍵(代表值)可以有不同的類型:
In?[78]:
```
d = {'a':1, 'b':2, 3:'hello'}
d
```
Out[78]:
```
{3: 'hello', 'a': 1, 'b': 2}
```
#### 1.2.2.2.4\. More container types
**元組**
元組本質上是不可變列表。元組的元素用括號包起來,或者只是用逗號分割:
In?[79]:
```
t = 12345, 54321, 'hello!'
t[0]
```
Out[79]:
```
12345
```
In?[80]:
```
t
```
Out[80]:
```
(12345, 54321, 'hello!')
```
In?[81]:
```
u = (0, 2)
```
**集合**:無序,惟一項目:
In?[82]:
```
s = set(('a', 'b', 'c', 'a'))
s
```
Out[82]:
```
{'a', 'b', 'c'}
```
In?[83]:
```
s.difference(('a', 'b'))
```
Out[83]:
```
{'c'}
```
#### 1.2.2.3\. 賦值運算
[Python類庫參考:](http://docs.python.org/reference/simple_stmts.html#assignment-statements)
> 賦值語句被用于(重)綁定名稱與值,以及修改可變對象的項目或屬性。
簡單來說,它這樣工作(簡單賦值):
1. 右側表達式被評估,創建或獲得產生的對象
2. 左側的名字被賦值或綁定到右側的對象
需要注意的事情:
* 單個對象可以有多個綁定的名稱:
In?[84]:
```
a = [1, 2, 3]
b = a
a
```
Out[84]:
```
[1, 2, 3]
```
In?[85]:
```
b
```
Out[85]:
```
[1, 2, 3]
```
In?[86]:
```
a is b
```
Out[86]:
```
True
```
In?[87]:
```
b[1] = 'hi!'
a
```
Out[87]:
```
[1, 'hi!', 3]
```
* 要在**原地**改變列表,請使用索引或切片:
In?[88]:
```
a = [1, 2, 3]
a
```
Out[88]:
```
[1, 2, 3]
```
In?[89]:
```
a = ['a', 'b', 'c'] # 創建另一個對象
a
```
Out[89]:
```
['a', 'b', 'c']
```
In?[90]:
```
id(a)
```
Out[90]:
```
4394695640
```
In?[91]:
```
a[:] = [1, 2, 3] # 在原地修改對象
a
```
Out[91]:
```
[1, 2, 3]
```
In?[92]:
```
id(a)
```
Out[92]:
```
4394695640
```
與上一個id相同,你的可能有所不同...
* 這里的關鍵觀點是可變 vs. 不可變
* 可變對象可以在原地修改
* 不可變對象一旦被創建就不可修改
**更多內容**在David M. Beazley的文章[Python中的類型和對象](http://www.informit.com/articles/article.aspx?p=453682)中也可以找到關于以上問題非常不錯的詳盡解釋。
## 1.2.3 流程控制
控制代碼執行順序。
### 1.2.3.1 if/elif/else
In?[93]:
```
if 2**2 == 4:
print 'Obvious!'
```
```
Obvious!
```
**代碼塊用縮進限定**
**小技巧**:在你的Python解釋器內輸入下列行,并且注意保持縮進深度。IPython shell會在一行的 : 符號后自動增加縮進,如果要減少縮進,向左側移動4個空格使用后退鍵。按兩次回車鍵離開邏輯塊。
In?[96]:
```
a = 10
if a == 1:
print(1)
elif a == 2:
print(2)
else:
print('A lot')
```
```
A lot
```
在腳本中也是強制縮進的。作為練習,在condition.py腳本中以相同的縮進重新輸入之前幾行,并在IPython中用`run condition.py`執行腳本。
### 1.2.3.2 for/range
在索引上迭代:
In?[97]:
```
for i in range(4):
print(i)
```
```
0
1
2
3
```
但是最經常使用,也更易讀的是在值上迭代:
In?[98]:
```
for word in ('cool', 'powerful', 'readable'):
print('Python is %s' % word)
```
```
Python is cool
Python is powerful
Python is readable
```
### 1.2.3.3 while/break/continue
典型的C式While循環(Mandelbrot問題):
In?[13]:
```
z = 1 + 1j
while abs(z) < 100:
z = z**2 + 1
z
```
Out[13]:
```
(-134+352j)
```
**更高級的功能**
bread 跳出for/while循環:
In?[103]:
```
z = 1 + 1j
while abs(z) < 100:
if z.imag == 0:
break
z = z**2 + 1
print z
```
```
(1+2j)
(-2+4j)
(-11-16j)
(-134+352j)
```
continue 繼續下一個循環迭代:
In?[101]:
```
a = [1, 0, 2, 4]
for element in a:
if element == 0:
continue
print 1. / element
```
```
1.0
0.5
0.25
```
### 1.2.3.4 條件表達式
**if [OBJECT]:**
評估為False:
```
- 任何等于0的數字 (0、0.0、0+0j)
- 空容器(列表、元組、集合、字典, ...)
- False,None
```
評估為True:
```
- 任何其他的東西
```
**a == b:**
判斷邏輯是否相等:
In?[1]:
```
1 == 1
```
Out[1]:
```
True
```
**a is b:**
測試同一性:兩邊是相同的對象:
In?[2]:
```
1 is 1
```
Out[2]:
```
True
```
In?[3]:
```
a = 1
b = 1
a is b
```
Out[3]:
```
True
```
**a in b:**
對于任何集合b:b包含a
In?[11]:
```
b = [1, 2, 3]
2 in b
```
Out[11]:
```
True
```
In?[12]:
```
5 in b
```
Out[12]:
```
False
```
如果b是字典,這個語法測試a是否是b的一個鍵。
### 1.2.3.5\. 高級循環
#### 1.2.3.5.1 序列循環
你可以在任何序列上進行循環(字符、列表、字典的鍵,文件的行...):
In?[14]:
```
vowels = 'aeiouy'
for i in 'powerful':
if i in vowels:
print(i),
```
```
o e u
```
In?[15]:
```
message = "Hello how are you?"
message.split() # 返回一個列表
```
Out[15]:
```
['Hello', 'how', 'are', 'you?']
```
In?[16]:
```
for word in message.split():
print word
```
```
Hello
how
are
you?
```
很少有語言(特別是科學計算語言)允許在整數或索引之外的循環。在Python中,可以在感興趣的對象上循環,而不用擔心你通常不關心的索引。這個功能通常用來讓代碼更易讀。
**警告**:改變正在循環的序列是不安全的。
#### 1.2.3.5.2 跟蹤列舉數
通常任務是在一個序列上循環,同時跟蹤項目數。
```
- 可以像上面,使用帶有計數器的while循環。或者一個for循環:
```
In?[17]:
```
words = ('cool', 'powerful', 'readable')
for i in range(0, len(words)):
print i, words[i]
```
```
0 cool
1 powerful
2 readable
```
但是,Python為這種情況提供了enumerate關鍵詞:
In?[18]:
```
for index, item in enumerate(words):
print index, item
```
```
0 cool
1 powerful
2 readable
```
#### 1.2.3.5.3 字典循環
使用**iteritems**:
In?[19]:
```
d = {'a': 1, 'b':1.2, 'c':1j}
for key, val in d.iteritems():
print('Key: %s has value: %s' % (key, val))
```
```
Key: a has value: 1
Key: c has value: 1j
Key: b has value: 1.2
```
#### 1.2.3.5.4 列表理解
In?[20]:
```
[i**2 for i in range(4)]
```
Out[20]:
```
[0, 1, 4, 9]
```
**練習**
用Wallis公式,計算π的小數

## 1.2.4\. 定義函數
### 1.2.4.1 函數的定義
In?[21]:
```
def test():
print('in test function')
test()
```
```
in test function
```
**注意**:函數塊必須像其他流程控制塊一樣縮進
### 1.2.4.2 返回語句
函數**可以選擇**返回值。
In?[22]:
```
def disk_area(radius):
return 3.14 * radius * radius
disk_area(1.5)
```
Out[22]:
```
7.0649999999999995
```
**注意**:默認函數返回`None`。
**注意**:注意定義函數的語法:
* def關鍵字:
* 接下來是函數的名稱,然后
* 在冒號后是在括號中的函數的參數。
* 函數體;
* 以及可選返回值的返回對象
### 1.2.4.3 參數
必選參數(位置參數)
In?[24]:
```
def double_it(x):
return x * 2
double_it(3)
```
Out[24]:
```
6
```
In?[25]:
```
double_it()
```
```
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-25-51cdedbb81b0> in <module>()
----> 1 double_it()
TypeError: double_it() takes exactly 1 argument (0 given)
```
可選參數(關鍵詞和命名參數)
In?[26]:
```
def double_it(x=2):
return x * 2
double_it()
```
Out[26]:
```
4
```
In?[27]:
```
double_it(3)
```
Out[27]:
```
6
```
關鍵詞參數允許你設置特定默認值。
**警告:**默認值在函數定義時被評估,而不是在調用時。如果使用可變類型(即字典或列表)并在函數體內修改他們,這可能會產生問題,因為這個修改會在函數被引用的時候一直持續存在。
在關鍵詞參數中使用不可變類型:
In?[2]:
```
bigx = 10
def double_it(x=bigx):
return x * 2
bigx = 1e9 # 現在真的非常大
double_it()
```
Out[2]:
```
20
```
在關鍵詞參數中使用可變類型(并且在函數體內修改它):
In?[3]:
```
def add_to_dict(args={'a': 1, 'b': 2}):
for i in args.keys():
args[i] += 1
print args
add_to_dict
```
Out[3]:
```
<function __main__.add_to_dict>
```
In?[4]:
```
add_to_dict()
```
```
{'a': 2, 'b': 3}
```
In?[5]:
```
add_to_dict()
```
```
{'a': 3, 'b': 4}
```
In?[6]:
```
add_to_dict()
```
```
{'a': 4, 'b': 5}
```
更復雜的例子,實現Python的切片:
In?[7]:
```
def slicer(seq, start=None, stop=None, step=None):
"""Implement basic python slicing."""
return seq[start:stop:step]
rhyme = 'one fish, two fish, red fish, blue fish'.split()
rhyme
```
Out[7]:
```
['one', 'fish,', 'two', 'fish,', 'red', 'fish,', 'blue', 'fish']
```
In?[8]:
```
slicer(rhyme)
```
Out[8]:
```
['one', 'fish,', 'two', 'fish,', 'red', 'fish,', 'blue', 'fish']
```
In?[9]:
```
slicer(rhyme, step=2)
```
Out[9]:
```
['one', 'two', 'red', 'blue']
```
In?[10]:
```
slicer(rhyme, 1, step=2)
```
Out[10]:
```
['fish,', 'fish,', 'fish,', 'fish']
```
In?[11]:
```
slicer(rhyme, start=1, stop=4, step=2)
```
Out[11]:
```
['fish,', 'fish,']
```
關鍵詞參數的順序**不**重要:
In?[12]:
```
slicer(rhyme, step=2, start=1, stop=4)
```
Out[12]:
```
['fish,', 'fish,']
```
但是,最好是使用與函數定義相同的順序。
_關鍵詞參數_是特別方便的功能,可以用可變數量的參數來定義一個函數,特別是當函數據絕大多數調用都會使用默認值時。
### 1.2.4.4 值傳遞
可以在一個函數內部改變變量的值嗎?大多數語言(C、Java...)區分了“值傳遞“和”引用傳遞“。在Python中,沒有嚴格的這種區分,并且視你的變量是否會修改而有一些不同。幸運的是,這些情況存在明確的規則。
函數的參數是對象的引用,傳遞的是值。當你像一個函數傳遞了一個變量,Python傳遞的是對象的引用,這個對象引用的變量(值)。而不是變量本身。
如果**值**傳遞給函數的值是不可變的,那么這個函數并不會改變調用者的變量。如果**值**是可變的,那么函數將可能在原地修改調用者的變量。
In?[13]:
```
def try_to_modify(x, y, z):
x = 23
y.append(42)
z = [99] # 新引用
print(x)
print(y)
print(z)
a = 77 # 不可變變量
b = [99] # 可變變量
c = [28]
try_to_modify(a, b, c)
```
```
23
[99, 42]
[99]
```
In?[14]:
```
print(a)
```
```
77
```
In?[15]:
```
print(b)
```
```
[99, 42]
```
In?[16]:
```
print(c)
```
```
[28]
```
函數有名為_local namespace_的本地變量表。
變量X只存在于函數try_to_modify內部。
### 1.2.4.5 全局變量
在函數外定義的變量可以在函數內引用:
In?[18]:
```
x = 5
def addx(y):
return x + y
addx(10)
```
Out[18]:
```
15
```
但是,這些全局變量不能在函數內修改,除非在函數內聲明**global**。
這樣沒用:
In?[19]:
```
def setx(y):
x = y
print('x is %d' % x)
setx(10)
```
```
x is 10
```
In?[20]:
```
x
```
Out[20]:
```
5
```
這樣可以:
In?[21]:
```
def setx(y):
global x
x = y
print('x is %d' % x)
setx(10)
```
```
x is 10
```
In?[22]:
```
x
```
Out[22]:
```
10
```
### 1.2.4.6 可變數量參數
函數的特殊形式:
```
- *args:封裝成元組的任意數量的位置參數
- **kwargs:封裝成字典的任意數量的關鍵詞參數
```
In?[23]:
```
def variable_args(*args, **kwargs):
print 'args is', args
print 'kwargs is', kwargs
variable_args('one', 'two', x=1, y=2, z=3)
```
```
args is ('one', 'two')
kwargs is {'y': 2, 'x': 1, 'z': 3}
```
### 1.2.4.7 Docstrings
關于函數作用及參數的文檔。通常慣例:
In?[24]:
```
def funcname(params):
"""Concise one-line sentence describing the function.
Extended summary which can contain multiple paragraphs.
"""
# 函數體
pass
funcname?
```
```
Type: function
Base Class: type 'function'>
String Form: <function funcname at 0xeaa0f0>
Namespace: Interactive
File: <ipython console>
Definition: funcname(params)
Docstring:
Concise one-line sentence describing the function.
Extended summary which can contain multiple paragraphs.
```
**注 Docstring 指導**
為了標準化,Docstring 慣例頁面為Python Docstring相關的含義及慣例提供了文檔。
Numpy和Scipy模塊也為科學計算函數定義了清晰的標準,你可能想要在自己的函數中去遵循,這個標準有參數部分,例子部分等。見[http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standard](http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standard) 及 [http://projects.scipy.org/numpy/browser/trunk/doc/example.py#L37](http://projects.scipy.org/numpy/browser/trunk/doc/example.py#L37)
### 1.2.4.8 函數作為對象
函數是一級對象,這意味著他們可以是:
```
- 可以被賦值給變量
- 列表的一個項目(或任何集合)
- 作為參數傳遞給另一個函數
```
In?[26]:
```
va = variable_args
va('three', x=1, y=2)
```
```
args is ('three',)
kwargs is {'y': 2, 'x': 1}
```
### 1.2.4.9 方法
方法是對象的函數。你已經在我們關于列表、字典和字符等...的例子上看到了。
### 1.2.4.10\. 練習
**練習:斐波那契數列**
寫一個函數來展示斐波那契數列的前n個項目,定義如下:
```
- u_0 = 1; u_1 = 1
- u_(n+2) = u_(n+1) + u_n
```
**練習:快速排序**
實現快速排序算法,定義來自wikipedia:
function quicksort(array)
```
var list less, greater if length(array) < 2
return array
select and remove a pivot value pivot from array for each x in array
if x < pivot + 1 then append x to less else append x to greater
return concatenate(quicksort(less), pivot, quicksort(greater))
```
- 介紹
- 1.1 科學計算工具及流程
- 1.2 Python語言
- 1.3 NumPy:創建和操作數值數據
- 1.4 Matplotlib:繪圖
- 1.5 Scipy:高級科學計算
- 1.6 獲取幫助及尋找文檔
- 2.1 Python高級功能(Constructs)
- 2.2 高級Numpy
- 2.3 代碼除錯
- 2.4 代碼優化
- 2.5 SciPy中稀疏矩陣
- 2.6 使用Numpy和Scipy進行圖像操作及處理
- 2.7 數學優化:找到函數的最優解
- 2.8 與C進行交互
- 3.1 Python中的統計學
- 3.2 Sympy:Python中的符號數學
- 3.3 Scikit-image:圖像處理
- 3.4 Traits:創建交互對話
- 3.5 使用Mayavi進行3D作圖
- 3.6 scikit-learn:Python中的機器學習