函數,對于人類來講,能夠發展到這個數學思維層次,是一個飛躍。可以說,它的提出,直接加快了現代科技和社會的發展,不論是現代的任何科技門類,乃至于經濟學、政治學、社會學等,都已經普遍使用函數。
下面一段來自維基百科(在本教程中,大量的定義來自維基百科,因為它真的很百科):[函數詞條](http://zh.wikipedia.org/zh/%E5%87%BD%E6%95%B0)
> 函數這個數學名詞是萊布尼茲在1694年開始使用的,以描述曲線的一個相關量,如曲線的斜率或者曲線上的某一點。萊布尼茲所指的函數現在被稱作可導函數,數學家之外的普通人一般接觸到的函數即屬此類。對于可導函數可以討論它的極限和導數。此兩者描述了函數輸出值的變化同輸入值變化的關系,是微積分學的基礎。
>
> 中文的“函數”一詞由清朝數學家李善蘭譯出。其《代數學》書中解釋:“凡此變數中函(包含)彼變數者,則此為彼之函數”。
函數,從簡單到復雜,各式各樣。前面提供的維基百科中的函數詞條,里面可以做一個概覽。但不管什么樣子的函數,都可以用下圖概括:
[](https://github.com/qiwsir/StarterLearningPython/blob/master/2images/20101.png)
有初中數學水平都能理解一個大概了。這里不贅述。
本講重點說明用python怎么來構造一個函數。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#深入理解函數)深入理解函數
在中學數學中,可以用這樣的方式定義函數:y=4x+3,這就是一個一次函數,當然,也可以寫成:f(x)=4x+3。其中x是變量,它可以代表任何數。
~~~
當x=2時,代入到上面的函數表達式:
f(2) = 4*2+3 = 11
所以:f(2) = 11
~~~
但是,這并不是函數的全部,在函數中,其實變量并沒有規定只能是一個數,它可以是饅頭、還可是蘋果,不知道讀者是否對函數有這個層次的理解。請繼續閱讀即更深刻
### [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#變量不僅僅是數)變量不僅僅是數
變量x只能是任意數嗎?其實,一個函數,就是一個對應關系。看官嘗試著將上面表達式的x理解為餡餅,4x+3,就是4個餡餅在加上3(一般來講,單位是統一的,但你非讓它不統一,也無妨),這個結果對應著另外一個東西,那個東西比如說是iphone。或者說可以理解為4個餡餅加3就對應一個iphone。這就是所謂映射關系。
所以,x,不僅僅是數,可以是你認為的任何東西。
### [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#變量本質占位符)變量本質——占位符
函數中為什么變量用x?這是一個有趣的問題,自己google一下,看能不能找到答案。
我也不清楚原因。不過,我清楚地知道,變量可以用x,也可以用別的符號,比如y,z,k,i,j...,甚至用alpha,beta這樣的字母組合也可以。
**變量在本質上就是一個占位符。**這是一針見血的理解。什么是占位符?就是先把那個位置用變量占上,表示這里有一個東西,至于這個位置放什么東西,以后再說,反正先用一個符號占著這個位置(占位符)。
其實在高級語言編程中,變量比我們在初中數學中學習的要復雜。但是,先不管那些,復雜東西放在以后再說了。現在,就按照初中數學的水平來研究python中的變量。
通常使小寫字母來命名python中的變量,也可以在其中加上下劃線什么的,表示區別。
比如:alpha,x,j,p_beta,這些都可以做為python的變量。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#建立簡單函數)建立簡單函數
~~~
>>> a = 2
>>> y = 3 * a + 2
>>> y
8
~~~
這種方式建立的函數,跟在初中數學中學習的沒有什么區別。當然,這種方式的函數,在編程實踐中沒有什么用途。
別急躁,你在輸入a=3,然后輸入y,看看得到什么結果呢?
~~~
>>> a = 2
>>> y = 3 * a + 2
>>> y
8
>>> a = 3
>>> y
8
~~~
是不是很奇怪?為什么后面已經讓a等于3了,結果y還是8。
還記得前面已經學習過的關于“變量賦值”的原理嗎?`a=2`的含義是將2這個對象貼上了變量a標簽,經過計算,得到了8,之后變量y引用了對象8。當變量a引用的對象修改為3的時候,但是y引用的對象還沒有變,所以,還是8。再計算一次,y的連接對象就變了:
~~~
>>> a = 3
>>> y
8
>>> y = 3 * a + 2
>>> y
11
~~~
特別注意,如果沒有先 a = 2 ,就直接下函數表達式了,像這樣,就會報錯。
~~~
>>> y = 3 * a + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
~~~
注意看錯誤提示,a是一個變量,提示中告訴我們這個變量沒有定義。顯然,如果函數中要使用某個變量,不得不提前定義出來。定義方法就是給這個變量賦值。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#建立實用的函數)建立實用的函數
上面用命令方式建立函數,還不夠“正規化”,那么就來寫一個.py文件吧。
例如下面的代碼:
~~~
#!/usr/bin/env python
#coding:utf-8
def add_function(a, b):
c = a + b
print c
if __name__ == "__main__":
add_function(2, 3)
~~~
然后將文件保存,我把她命名為20101.py,你根據自己的喜好取個名字。
然后我就進入到那個文件夾,運行這個文件,出現下面的結果,如圖:
[](https://github.com/qiwsir/StarterLearningPython/blob/master/2images/20102.png)
你運行的結果是什么?如果沒有得到上面的結果,你就非常認真地檢查代碼,是否跟我寫的完全一樣,注意,包括冒號和空格,都得一樣。**冒號和空格很重要。**
下面開始庖丁解牛:
* `def add_function(a, b)`: 這里是函數的開始。在聲明要建立一個函數的時候,一定要使用def(def 就是英文define的前三個字母),意思就是告知計算機,這里要聲明一個函數;add_function是這個函數名稱,取名字是有講究的,就好比你的名字一樣。在python中取名字的講究就是要有一定意義,能夠從名字中看出這個函數是用來干什么的。從add_function這個名字中,是不是看出她是用來計算加法的呢(嚴格地說,是把兩個對象“相加”,這里相加的含義是比較寬泛的,包括對字符串等相加)?(a,b)這個括號里面的是這個函數的參數,也就是函數變量。冒號,這個冒號非常非常重要,如果少了,就報錯了。冒號的意思就是下面好開始真正的函數內容了。
* `c = a + b`?特別注意,這一行比上一行要縮進四個空格。這是python的規定,要牢記,不可丟掉,丟了就報錯。然后這句話就是將兩個參數(變量)相加,結果賦值與另外一個變量c。
* `print c`?還是提醒看官注意,縮進四個空格。將得到的結果c的值打印出來。
* `if __name__ == "__main__"`: 這句話先照抄,不解釋,因為在[《自省》](https://github.com/qiwsir/StarterLearningPython/blob/master/130.md)有說明,不知道你是不是認真閱讀了。注意就是不縮進了。
* add_function(2,3) 這才是真正調用前面建立的函數,并且傳入兩個參數:a=2,b=3。仔細觀察傳入參數的方法,就是把2放在a那個位置,3放在b那個位置(所以說,變量就是占位符).
解牛完畢,做個總結:
定義函數的格式為:
~~~
def 函數名(參數1,參數2,...,參數n):
函數體(語句塊)
~~~
是不是樣式很簡單呢?
幾點說明:
* 函數名的命名規則要符合python中的命名要求。一般用小寫字母和單下劃線、數字等組合
* def是定義函數的關鍵詞,這個簡寫來自英文單詞define
* 函數名后面是圓括號,括號里面,可以有參數列表,也可以沒有參數
* 千萬不要忘記了括號后面的冒號
* 函數體(語句塊),相對于def縮進,按照python習慣,縮進四個空格
看簡單例子,深入理解上面的要點:
~~~
>>> def name(): #定義一個無參數的函數,只是通過這個函數打印
... print "qiwsir" #縮進4個空格
...
>>> name() #調用函數,打印結果
qiwsir
>>> def add(x,y): #定義一個非常簡單的函數
... return x+y #縮進4個空格
...
>>> add(2,3) #通過函數,計算2+3
5
~~~
注意上面的add(x,y)函數,在這個函數中,沒有特別規定參數x,y的類型。其實,這句話本身就是錯的,還記得在前面已經多次提到,在python中,變量無類型,只有對象才有類型,這句話應該說成:x,y并沒有嚴格規定其所引用的對象類型。這是python跟某些語言比如java很大的區別,在有些語言中,需要在定義函數的時候告訴函數參數的數據類型。python不用那樣做。
為什么?列位不要忘記了,這里的所謂參數,跟前面說的變量,本質上是一回事。只有當用到該變量的時候,才建立變量與對象的對應關系,否則,關系不建立。而對象才有類型。那么,在add(x,y)函數中,x,y在引用對象之前,是完全飄忽的,沒有被貼在任何一個對象上,換句話說它們有可能引用任何對象,只要后面的運算許可,如果后面的運算不許可,則會報錯。
~~~
>>> add("qiw","sir") #這里,x="qiw",y="sir",讓函數計算x+y,也就是"qiw"+"sir"
'qiwsir'
>>> add("qiwsir",4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in add
TypeError: cannot concatenate 'str' and 'int' objects #仔細閱讀報錯信息,就明白錯誤之處了
~~~
從實驗結果中發現:x+y的意義完全取決于對象的類型。在python中,將這種依賴關系,稱之為**多態**。對于python中的多態問題,以后還會遇到,這里僅僅以此例子顯示一番。請看官要留心注意的:**python中為對象編寫接口,而不是為數據類型。**讀者先留心一下這句話,或者記住它,隨著學習的深入,會領悟到其真諦的。
此外,也可以將函數通過賦值語句,與某個變量建立引用關系:
~~~
>>> result = add(3,4)
>>> result
7
~~~
在這里,其實解釋了函數的一個秘密。add(x,y)在被運行之前,計算機內是不存在的,直到代碼運行到這里的時候,在計算機中,就建立起來了一個對象,這就如同前面所學習過的字符串、列表等類型的對象一樣,運行add(x,y)之后,也建立了一個add(x,y)的對象,這個對象與變量result可以建立引用關系,并且add(x,y)將運算結果返回。于是,通過result就可以查看運算結果。
如果看官上面一段,感覺有點吃力或者暈乎,也不要緊,那就再讀一邊。是在搞不明白,就不要搞了。隨著學習的深入,它會被明白的。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#關于命名)關于命名
到現在為止,我們已經接觸過變量的命名、函數的命名問題。似乎已經到了將命名問題進行總結的時候了。
在某國,向來重視“名”,所謂“名不正言不順”,取名字或者給什么東西命名,常常是天大的事情,在很多時候就是為了那個“名”進行爭斗。
江湖上還有的大師,會通過某個人的名字來預測他/她的吉兇禍福等。看來名字這玩意太重要了。“名不正,言不順”,歪解:名字不正規化,就不順。這是歪解,希望不要影響看官正確理解。不知道大師們是不是能夠通過外國人名字預測外國人大的吉兇禍福呢?比如Aoi sola,這個人怎么樣?不管怎樣,某國人是很在意名字的,旁邊有個國家似乎就不在乎,比如山本五十六,在名字中間出現數字,就好像我們的張三李四王二麻子那樣隨便,不過,有一種說法,“山本五十六”的意思是這個人出生時,他父親56歲,看來跟張三還不一樣的。
python也很在乎名字問題,其實,所有高級語言對名字都有要求。為什么呢?因為如果命名亂了,計算機就有點不知所措了。看python對命名的一般要求。
* 文件名:全小寫,可使用下劃線
* 函數名:小寫,可以用下劃線風格單詞以增加可讀性。如:myfunction,my_example_function。*注意*:混合大小寫僅被允許用于這種風格已經占據優勢的時候,以便保持向后兼容。有的人,喜歡用這樣的命名風格:myFunction,除了第一個單詞首字母外,后面的單詞首字母大寫。這也是可以的,因為在某些語言中就習慣如此。
* 函數的參數:如果一個函數的參數名稱和保留的關鍵字(所謂保留關鍵字,就是python語言已經占用的名稱,通常被用來做為已經有的函數等的命名了,你如果還用,就不行了。)沖突,通常使用一個后綴下劃線好于使用縮寫或奇怪的拼寫。
* 變量:變量名全部小寫,由下劃線連接各個單詞。如color = WHITE,this_is_a_variable = 1。
其實,關于命名的問題,還有不少爭論呢?最典型的是所謂匈牙利命名法、駝峰命名等。如果你喜歡,可以google一下。以下內容供參考:
* [匈牙利命名法](http://zh.wikipedia.org/zh/%E5%8C%88%E7%89%99%E5%88%A9%E5%91%BD%E5%90%8D%E6%B3%95)
* [駝峰式大小寫](http://zh.wikipedia.org/wiki/%E9%A7%9D%E5%B3%B0%E5%BC%8F%E5%A4%A7%E5%B0%8F%E5%AF%AB)
* [帕斯卡命名法](http://zh.wikipedia.org/w/index.php?title=%E5%B8%95%E6%96%AF%E5%8D%A1%E5%91%BD%E5%90%8D%E6%B3%95&variant=zh-cn)
* [python命名的官方要求](http://legacy.python.org/dev/peps/pep-0008/#prescriptive-naming-conventions),如果看官的英文可以,一定要閱讀。如果英文稍遜,可以來閱讀[中文](http://wiki.jiayun.org/PEP_8_--_Style_Guide_for_Python_Code#.E5.91.BD.E5.90.8D.E6.85.A3.E4.BE.8B),不用梯子能行嗎?看你命了。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#調用函數)調用函數
前面的例子中已經有了一些關于調用的問題,為了深入理解,把這個問題單獨拿出來看看。
為什么要寫函數?從理論上說,不用函數,也能夠編程,我們在前面已經寫了程序,就沒有寫函數,當然,用python的內建函數姑且不算了。現在之所以使用函數,主要是:
1. 降低編程的難度,通常將一個復雜的大問題分解成一系列更簡單的小問題,然后將小問題繼續劃分成更小的問題,當問題細化為足夠簡單時,就可以分而治之。為了實現這種分而治之的設想,就要通過編寫函數,將各個小問題逐個擊破,再集合起來,解決大的問題。(看官請注意,分而治之的思想是編程的一個重要思想,所謂“分治”方法也。)
2. 代碼重(chong,二聲音)用。在編程的過程中,比較忌諱同樣一段代碼不斷的重復,所以,可以定義一個函數,在程序的多個位置使用,也可以用于多個程序。當然,后面我們還會講到“模塊”(此前也涉及到了,就是import導入的那個東西),還可以把函數放到一個模塊中供其他程序員使用。也可以使用其他程序員定義的函數(比如import ...,前面已經用到了,就是應用了別人——創造python的人——寫好的函數)。這就避免了重復勞動,提供了工作效率。
這樣看來,函數還是很必要的了。廢話少說,那就看函數怎么調用吧。以add(x,y)為例,前面已經演示了基本調用方式,此外,還可以這樣:
~~~
>>> def add(x,y): #為了能夠更明了顯示參數賦值特點,重寫此函數
... print "x=",x #分別打印參數賦值結果
... print "y=",y
... return x+y
...
>>> add(10,3) #x=10,y=3
x= 10
y= 3
13
>>> add(3,10) #x=3,y=10
x= 3
y= 10
13
~~~
所謂調用,最關鍵是要弄清楚如何給函數的參數賦值。這里就是按照參數次序賦值,根據參數的位置,值與之對應。
~~~
>>> add(x=10,y=3) #同上
x= 10
y= 3
13
~~~
還可以直接把賦值語句寫到里面,就明確了參數和對象的關系。當然,這時候順序就不重要了,也可以這樣
~~~
>>> add(y=10,x=3) #x=3,y=10
x= 3
y= 10
13
~~~
在定義函數的時候,參數可以像前面那樣,等待被賦值,也可以定義的時候就賦給一個默認值。例如:
~~~
>>> def times(x,y=2): #y的默認值為2
... print "x=",x
... print "y=",y
... return x*y
...
>>> times(3) #x=3,y=2
x= 3
y= 2
6
>>> times(x=3) #同上
x= 3
y= 2
6
~~~
如果不給那個有默認值的參數傳遞值(賦值的另外一種說法),那么它就是用默認的值。如果給它傳一個,它就采用新賦給它的值。如下:
~~~
>>> times(3,4) #x=3,y=4,y的值不再是2
x= 3
y= 4
12
>>> times("qiwsir") #再次體現了多態特點
x= qiwsir
y= 2
'qiwsirqiwsir'
~~~
給列位看官提一個思考題,請在閑暇之余用python完成:寫兩個數的加、減、乘、除的函數,然后用這些函數,完成簡單的計算。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/201.md#注意事項)注意事項
下面的若干條,是常見編寫代碼的注意事項:
1. 別忘了冒號。一定要記住符合語句首行末尾輸入“:”(if,while,for等的第一行)
2. 從第一行開始。要確定頂層(無嵌套)程序代碼從第一行開始。
3. 空白行在交互模式提示符下很重要。模塊文件中符合語句內的空白行常被忽視。但是,當你在交互模式提示符下輸入代碼時,空白行則是會結束語句。
4. 縮進要一致。避免在塊縮進中混合制表符和空格。
5. 使用簡潔的for循環,而不是while or range.相比,for循環更易寫,運行起來也更快
6. 要注意賦值語句中的可變對象。
7. 不要期待在原處修改的函數會返回結果,比如list.append(),這在可修改的對象中特別注意
8. 調用函數是,函數名后面一定要跟隨著括號,有時候括號里面就是空空的,有時候里面放參數。
9. 不要在導入和重載中使用擴展名或路徑。
以上各點如果有不理解的,也不要緊,在以后編程中,時不時地回來復習一下,能不斷領悟其內涵。
- 第零章 預備
- 關于Python的故事
- 從小工到專家
- Python安裝
- 集成開發環境
- 第壹章 基本數據類型
- 數和四則運算
- 除法
- 常用數學函數和運算優先級
- 寫一個簡單的程序
- 字符串(1)
- 字符串(2)
- 字符串(3)
- 字符串(4)
- 字符編碼
- 列表(1)
- 列表(2)
- 列表(3)
- 回顧list和str
- 元組
- 字典(1)
- 字典(2)
- 集合(1)
- 集合(2)
- 第貳章 語句和文件
- 運算符
- 語句(1)
- 語句(2)
- 語句(3)
- 語句(4)
- 語句(5)
- 文件(1)
- 文件(2)
- 迭代
- 練習
- 自省
- 第叁章 函數
- 函數(1)
- 函數(2)
- 函數(3)
- 函數(4)
- 函數練習
- 第肆章 類
- 類(1)
- 類(2)
- 類(3)
- 類(4)
- 類(5)
- 多態和封裝
- 特殊方法(1)
- 特殊方法(2)
- 迭代器
- 生成器
- 上下文管理器
- 第伍章 錯誤和異常
- 錯誤和異常(1)
- 錯誤和異常(2)
- 錯誤和異常(3)
- 第陸章 模塊
- 編寫模塊
- 標準庫(1)
- 標準庫(2)
- 標準庫(3)
- 標準庫(4)
- 標準庫(5)
- 標準庫(6)
- 標準庫(7)
- 標準庫(8)
- 第三方庫
- 第柒章 保存數據
- 將數據存入文件
- mysql數據庫(1)
- MySQL數據庫(2)
- mongodb數據庫(1)
- SQLite數據庫
- 電子表格
- 第捌章 用Tornado做網站
- 為做網站而準備
- 分析Hello
- 用tornado做網站(1)
- 用tornado做網站(2)
- 用tornado做網站(3)
- 用tornado做網站(4)
- 用tornado做網站(5)
- 用tornado做網站(6)
- 用tornado做網站(7)
- 第玖章 科學計算
- 為計算做準備
- Pandas使用(1)
- Pandas使用(2)
- 處理股票數據
- 附:網絡文摘
- 如何成為Python高手
- ASCII、Unicode、GBK和UTF-8字符編碼的區別聯系