學廖雪峯老師Python教程筆記php
1、Python簡介java
一、Python適合開發哪些類型的應用呢?python
首選是網絡應用,包括網站、後臺服務等等;算法
其次是不少平常須要的小工具,包括系統管理員須要的腳本任務等等;macos
另外就是把其餘語言開發的程序再包裝起來,方便使用。編程
二、Python缺點數組
運行速度慢、代碼不能加密瀏覽器
2、Python安裝安全
在Mac上安裝Python服務器
目前,Python有兩個版本,一個是2.x版本,一個是3.x版,這兩個版本是不兼容的。
若是你正在使用Mac,系統是OS X>=10.9,那麼系統自帶的Python版本是2.7。要安裝最新的Python3.7,有兩個方法:
方法一:從Python官網下載Python 3.7的安裝程序(網速慢的同窗請移步國內鏡像),雙擊運行並安裝;
方法二:若是安裝了Homebrew,直接經過命令brew install python3安裝便可。
3、第一個Python程序
一、安裝好之後,輸入Python回車進入Python的交互式命令行,100+200回車輸出300,print('hello word')輸出hello word
也能夠直接在命令行模式執行,Python hello.py執行Python腳本。
二、直接運行py文件
Windows上不能夠像.exe文件那樣直接運行.py文件。可是在Mac和Linux上是能夠的,方法是在.py文件的第一行加上一個特殊的註釋:
#!/usr/bin/env python3
print('hello, world')
而後經過命令給hello.py以執行權限:
就能夠直接運行hello.py了,好比在Mac下運行:
小結:一、用文本編輯器寫Python程序,而後保存爲後綴爲.py的文件,就能夠用Python直接運行這個程序了。
二、Python的交互模式和直接運行.py文件有什麼區別呢?
直接輸入Python進入交互模式,至關於啓動了Python解釋器,可是等待你一行一行的輸入源代碼,沒輸入一行就執行一行。
直接運行.py文件至關於啓動了Python解釋器,而後一次性把.py文件的源代碼給執行了,你是沒有機會以交互的方式輸入源代碼的。
用Python發程序,徹底能夠一邊在文本編輯器裏寫代碼,一邊開一個交互式命令窗口,在寫代碼的過程當中,把部分代碼粘到命令行去驗證,事半功倍!提早是得有個27‘的超大顯示器!
4、Python基礎
一、Python程序是大小寫敏感的,若是寫錯了大小寫,程序會報錯。
二、字符編碼
咱們已經講過了,字符串也是一種數據類型,可是,字符串比較特殊的是還有一個編碼問題。
由於計算機只能處理數字,若是要處理文本,就必須先把文本轉換爲數字才能處理。最先的計算機在設計時採用8個比特(bit)做爲一個字節(byte),因此,一個字節能表示的最大的整數就是255(二進制11111111=十進制255),若是要表示更大的整數,就必須用更多的字節。好比兩個字節能夠表示的最大整數是65535
,4個字節能夠表示的最大整數是4294967295
。
因爲計算機是美國人發明的,所以,最先只有127個字符被編碼到計算機裏,也就是大小寫英文字母、數字和一些符號,這個編碼表被稱爲ASCII
編碼,好比大寫字母A
的編碼是65
,小寫字母z
的編碼是122
。
可是要處理中文顯然一個字節是不夠的,至少須要兩個字節,並且還不能和ASCII編碼衝突,因此,中國製定了GB2312
編碼,用來把中文編進去。
你能夠想獲得的是,全世界有上百種語言,日本把日文編到Shift_JIS
裏,韓國把韓文編到Euc-kr
裏,各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文本中,顯示出來會有亂碼。
所以,Unicode應運而生。Unicode把全部語言都統一到一套編碼裏,這樣就不會再有亂碼問題了。
Unicode標準也在不斷髮展,但最經常使用的是用兩個字節表示一個字符(若是要用到很是偏僻的字符,就須要4個字節)。現代操做系統和大多數編程語言都直接支持Unicode。
如今,捋一捋ASCII編碼和Unicode編碼的區別:ASCII編碼是1個字節,而Unicode編碼一般是2個字節。
字母A
用ASCII編碼是十進制的65
,二進制的01000001
;
字符0
用ASCII編碼是十進制的48
,二進制的00110000
,注意字符'0'
和整數0
是不一樣的;
漢字中
已經超出了ASCII編碼的範圍,用Unicode編碼是十進制的20013
,二進制的01001110 00101101
。
你能夠猜想,若是把ASCII編碼的A
用Unicode編碼,只須要在前面補0就能夠,所以,A
的Unicode編碼是00000000 01000001
。
新的問題又出現了:若是統一成Unicode編碼,亂碼問題今後消失了。可是,若是你寫的文本基本上所有是英文的話,用Unicode編碼比ASCII編碼須要多一倍的存儲空間,在存儲和傳輸上就十分不划算。
因此,本着節約的精神,又出現了把Unicode編碼轉化爲「可變長編碼」的UTF-8
編碼。UTF-8編碼把一個Unicode字符根據不一樣的數字大小編碼成1-6個字節,經常使用的英文字母被編碼成1個字節,漢字一般是3個字節,只有很生僻的字符纔會被編碼成4-6個字節。若是你要傳輸的文本包含大量英文字符,用UTF-8編碼就能節省空間:
字符 |
ASCII |
Unicode |
UTF-8 |
A |
01000001 |
00000000 01000001 |
01000001 |
中 |
x |
01001110 00101101 |
11100100 10111000 10101101 |
從上面的表格還能夠發現,UTF-8編碼有一個額外的好處,就是ASCII編碼實際上能夠被當作是UTF-8編碼的一部分,因此,大量只支持ASCII編碼的歷史遺留軟件能夠在UTF-8編碼下繼續工做。
搞清楚了ASCII、Unicode和UTF-8的關係,咱們就能夠總結一下如今計算機系統通用的字符編碼工做方式:
在計算機內存中,統一使用Unicode編碼,當須要保存到硬盤或者須要傳輸的時候,就轉換爲UTF-8編碼。
用記事本編輯的時候,從文件讀取的UTF-8字符被轉換爲Unicode字符到內存裏,編輯完成後,保存的時候再把Unicode轉換爲UTF-8保存到文件:
瀏覽網頁的時候,服務器會把動態生成的Unicode內容轉換爲UTF-8再傳輸到瀏覽器:
因此你看到不少網頁的源碼上會有相似<meta charset="UTF-8" />
的信息,表示該網頁正是用的UTF-8編碼。
二、1箇中文字符通過utf-8編碼後一般會佔用3個字節,而1個英文字符只佔用1個字節。
在操做字符串時,咱們常常遇到str和bytes的互相轉換。爲了不亂碼問題,應當始終堅持使用utf-8編碼對str和bytes進行轉換。
因爲Python源代碼也是一個文本文件,因此,當你的源代碼中包含中文的時候,在保存源代碼時,就須要務必指定保存爲utf-8編碼。當Python解釋器讀取源代碼時,爲了讓他按utf-8編碼讀取,咱們一般在文件開頭寫上這兩行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
第一行註釋是爲了告訴Linux/OS X系統,這是一個Python可執行程序,Windows系統會忽略這個註釋;
第二行註釋是爲了告訴Python解釋器,按照utf-8編碼讀取源代碼,不然,你在源代碼中寫的中文輸出可能會有亂碼。
申明瞭utf-8編碼並不意味着你的.py文件就是utf-8編碼,必須而且要確保文本編輯器正在使用utf-8 without BOM編碼:
若是.py文件自己使用utf-8編碼,而且也申明瞭# -*- coding: utf-8 -*-,打開命令提示符測試就能夠正常顯示中文:
三、格式化
即字符替換:
例:
>>>'Hello, %s' % 'word'
'Hello, word'
>>>'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'
%s表示用字符串替換,%d表示用整數替換,%f表示用浮點數替換,有幾個%?佔位符,後面就跟幾個變量或者值,順序要對應好。若是隻有一個%?,括號能夠省略。
例:
#-*- coding:utf-8 -*-
print('%2d-%02d' % (3,1))
print('%.2f' % 3.1415926)
若是你不太肯定應該用什麼,%s永遠起做用,它會把任何數據類型轉換爲字符串:
>>>'age: %s Gender: %s' % (25, True)
'Age:25 Gender:True'
有些時候,字符串裏面的%是一個普通字符怎麼辦?這個時候就須要轉義,用%%來表示一個%
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
小結:
Python 3的字符串使用Unicode,直接支持多語言。
當str
和bytes
互相轉換時,須要指定編碼。最經常使用的編碼是UTF-8
。Python固然也支持其餘編碼方式,好比把Unicode編碼成GB2312
:
>>> '中文'.encode('gb2312') b'\xd6\xd0\xce\xc4'
但這種方式純屬自找麻煩,若是沒有特殊業務要求,請牢記僅使用UTF-8
編碼。
格式化字符串的時候,能夠用Python的交互式環境測試,方便快捷。
四、使用list和tuple
list
1)建立列表:
>>>classmates = ['gouzi', 'caihua', 'damao']
>>>classmates
['gouzi', 'caihua', 'damao']
2)獲取list元素個數
3)訪問
>>> classmates[0]
'gouzi'
>>> classmates[1]
'caihua'
>>> classmates[2]
'damao'
>>> classmates[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
當索引超出了範圍時,Python會報一個IndexError
錯誤,因此,要確保索引不要越界,記得最後一個元素的索引是len(classmates) - 1
。
若是要取最後一個元素,除了計算索引位置外,還能夠用-1
作索引,直接獲取最後一個元素:
>>> classmates[-1]
'damao'
以此類推,能夠獲取倒數第2個、倒數第3個:
>>> classmates[-2]
'caihua'
>>> classmates[-3]
'gouzi'
>>> classmates[-4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
倒數第4個就越界了。
4)、追加元素到末尾
>>>classmates.append('erya')
>>>classmates
['gouzi', 'caihua', 'damao', 'erya']
也能夠把元素插入到指定的位置,好比索引爲1的位置:
>>>classmates.insert(1, 'goudan')
>>>classmates
['gouzi', 'goudan', 'caihua', 'damao', 'erya']
5)、刪除list末尾的元素,用pop()方法:
>>>classmates.pop()
'erya'
>>>classmates
['gouzi', 'goudan', 'caihua', 'damao']
要刪除指定位置的元素,用pop(i)方法,其中i是索引位置:
>>>classmates.pop(1)
'goudan'
>>>classmates
['gouzi', 'caihua', 'damao']
6)、把某個元素替換成別的元素,能夠直接賦值給對應的索引位置:
>>>classmates[1] = 'yuanshuai'
>>>classmates
['gouzi', 'yuanshuai', 'caihua']
7)、list裏面元素的數據類型也能夠不一樣,好比:
>>>L = ['Apple', 123, True]
8)、list元素也能夠是另一個list,好比:
>>> s = ['python', 'java', ['asp', 'php'], 'scheme']
>>> len(s)
4
要拿到'php'能夠寫s[2][1],所以s能夠當作是一個二維數組,相似的還有三維、四維...數組,不過不多用到。
若是一個list中一個元素也沒有,就是一個空的list,他的長度爲0:
tuple
另外一種有序列表叫元組:tuple。tuple和list很是相似,可是tuple一旦初始化就不能修改,好比一樣是累出同窗的名字:
1)、建立
>>>classmates = ('gouzi', 'caihua', 'erya')
因此建立list使用[],建立tuple是使用()
如今,classmates這個tuple不能變了,它也沒有append(),insert()這樣的方法。其餘獲取元素的方法和list是同樣的,你能夠正常地使用classmates[0],classmates[-1],但不能賦值成另外的元素。
不可變的tuple有什麼意義?由於tuple不可變,因此代碼更安全。若是可能,能用tuple代替list就儘可能用tuple。
tuple的陷阱:當你定義一個tuple時,在定義的時候,tuple的元素就必須被肯定下來,好比:
>>> t = (1, 2)
>>> t
(1, 2)
若是定義一個空的tuple,能夠寫成():
可是要定義一個只有1個元素的tuple,若是你這麼定義
定義的不是tuple,是1這個數!這是由於括號()既能夠表示tuple,是1這個數!這是由於括號()既能夠表示tuple,又能夠表示數學公式中的小括號,這就產生了歧義,所以,Python規定,這種狀況下,按小括號進行計算,計算結果天然是1。
因此,只有1個元素的tuple定義事必須加一個逗號,來消除歧義:
>>> t = (1, )
>>> t
(1, )
python在顯示只有一個元素的tuple時,也會加一個逗號,一面你誤會成數學計算意義上的括號。
最後來看一個‘可變的’tuple:
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
四、條件判斷
1)、小例子
age = 20
if age >= 18:
print('your age is', age)
print('adult')
elif age>=6:
print('teenager')
else:
print('your age is', age)
print('teenager')
形式爲:
if <條件判斷1>:
<執行1>
elif <條件判斷2>:
<執行2>
elif <條件判斷3>:
<執行3>
else:
<執行4>
if語句執行有個特色,他是從上往下判斷,若是在某個判斷上是true,把該判斷對應的語句執行後,就忽略剩下的elif和else,因此,請測試並解釋爲何下面的程序打印的是teenager:
age = 20
if age >= 6:
print('teenager')
elif age >= 18:
print('adult')
else:
print('kid')
if判斷條件還能夠簡寫,好比寫:
只要x是非零數值、費控字符串、非空list等,就判斷爲True,不然爲False。
再議input
最後看一個有問題的條件判斷。不少同窗會用input()讀取用戶的輸入,這樣能夠本身輸入,程序運行的更有意思:
birth = input('birth:');
if birth < 2000:
print('00前')
else:
print('00後')
輸入1982,結果報錯:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() > int()
這是由於input()返回數據類型是str,str不能直接和整數比較,必須先把str轉換成整數。Python提供了int()函數來完成這件事情:
s = input('birth:')
birth = int(s)
if birth < 2000;
print('00前')
else:
print('00後')
再次運行就能夠獲得正確的結果。可是,若是輸入abc呢?又會獲得一個錯誤信息:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'abc'
原來int()函數發現一個字符串並非合法的數字時就會報錯,程序就退出了。
如何檢查並捕獲程序運行期的錯誤呢?後面的錯誤和調試會講到。
五、循環
Python有兩種循環,一種是for...in,一種是while循環
1)、for...in循環
例:
names = ['Michael', 'Bob', 'Tracy']
for name in names :
print(name)
因此for x in ...循環就是把每一個元素帶入變量x,而後執行縮進快的語句。
再好比咱們想計算1-10的整數之和,能夠用一個sum變量作累加:
sum = 0
for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
sum = num + x
print(sum)
若是要計算1-100的整數之和,從1寫到100有點困難,幸虧Python提供一個range()函數,能夠生成一個整數序列,再經過list()函數能夠轉換爲list。好比range(5)生成的序列是從0開始小於5的整數:
>>>list(range(5))
[0, 1, 2, 3, 4]
range(101)就能夠生成0-100的整數序列,計算以下:
sum = 0
for x in range(101):
sum = sum + x
print(sum)
2)、while循環
只要條件知足,就不斷循環,條件不知足時退出循環。好比咱們要計算100之內全部奇數之和,能夠用while循環實現:
sum = 0
n = 99
while n>0:
sum = sum + n
n = n -2
print(sum)
再循環內部變量n不斷自減,知道變爲-1時,再也不知足while條件,魂環退出。
3)break
再循環中,break語句能夠提早退出循環。例如,原本要循環打印1~100的數字:
n = 1
while n <= 100:
print(n)
n = n + 1
print('END')
上面打印的代碼 能夠打印出1~100.
若是要提早結束循環,能夠用break語句:
n = 1
while n<= 100
if n > 10:
break
print(n)
n = n + 1
print('END')
執行上面的代碼能夠看到,打印出1~10後,緊接着打印END,程序結束。
可見break的做用是提早結束循環。
continue
再循環過程當中,也能夠經過continue語句,跳過當前的此次循環,直接開始下一次循環。
n = 0
while n < 10:
n = n + 1
print(n)
上面的程序能夠打印出1~10。可是,若是咱們想只打印奇數,能夠用continue語句跳過某些循環:
n = 0
while n < 10:
n = n + 1
if n % 2 == 0: # 若是n是偶數,執行continue語句
continue # continue語句會直接繼續下一輪循環,後續的print()語句不會執行
print(n)
執行上面的代碼能夠看到,打印的再也不是1~10,而是1, 3, 5, 7, 9
可見continue的做用是提早結束本輪循環,並直接開始下一輪循環。
六、使用dict和set
Python內置了字典:dict的支持,dict全稱dictionary,在其餘語言中也稱爲map,使用鍵-值(key-value)存儲,具備極快的查找速度。
假設要根據同窗的名字查找對應的成績,用dict實現,只須要一個「名字」-「成績」的對照表,直接根據名字查找成績,不管這個表有多大,查找速度都不會變慢。用Python寫一個dict以下:
>>>d = {'gouzi' : 29, 'dabai' : 26, 'cuihua' : 18}
>>>d['gouzi']
29
爲何dict查找速度這麼快?由於dict的實現原理和查字典是同樣的。假設字段包含了1萬個漢字,咱們要查某一個字,一個辦法是把字典從第一頁日後翻,知道找到咱們想要的字爲止,這種方法就是在list中查找元素的方法,list越大,查找越慢。
第二種方法是先在字典的索引裏(好比部首表)查這個字對應的頁碼,而後直接翻到該頁,找到這個字。不管找哪一個字,這種查找速度都很是快,不會隨着字典大小的增長而變慢。
dict就是第二種實現方法,給定一個名字,好比‘gouzi’,dict在內部就能夠直接計算出gouzi對應的存放成績的「頁碼」,也就是29這個數字存放的內存地址,直接取出來,因此速度很是快。
這總key-value存儲方式,在放進去的時候,必須根據key算出value的存放位置,這樣,去的時候才能根據key直接拿到value。
把數據放入dict的方法,除了初始化時指定外,還能夠經過key放入:
>>>d['Adam'] = 67
>>>d['Adam']
67
因爲一個key只能對應一個value,因此,屢次對一個key放入value,後面的值會把前面的值沖掉:
>>> d['Jack'] = 90
>>> d['Jack']
90
>>> d['Jack'] = 88
>>> d['Jack']
88
若是key不存在,dict就會報錯:
>>> d['Thomas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Thomas'
要避免key不存在的錯誤,有兩種辦法,一是經過in判斷key是否存在:
二是經過dict提供的get()方法,若是key不存在,能夠返回None,或者本身指定的value:
>>>d.get('dada')
>>>d.get('dada', -1)
-1
注意:返回None的時候Python的交互環境不顯示結果。
要刪除一個key,用pop(key)方法,對應的value也會從dict中刪除:
>>>d.pop('cuihua')
12
>>>d
{'gouzi':29, 'libai': 101}
請務必注意,dict內部存放的順序和key放入的順序和key放入的順序是沒有關係的。
和list比較,dict有如下幾個特色:
一、查找和插入的速度極快,不會隨着key的增長而變慢;
二、須要佔用大量的內存,內存浪費多。
而list相反:
一、查找和插入的時間隨着元素的增長而增長;
二、佔用空間小,浪費內存不多。
因此,dict使用空間來換取時間的一種方法。
dict能夠用在須要高速查找的不少地方,在Python代碼中幾乎無處不在,正確使用dict很是重要,須要牢記的而第一條就是dict的key必須是不可變對象。
這是由於dict根據key來計算value的存儲位置,若是每次計算相同的key得出的結果不一樣,那dict內部就徹底混亂了。這個經過key來計算vlaue的存儲位置,若是每次計算相同的key得出的結果不一樣,那dict內部就徹底混亂了。這個經過key計算位置的額算法稱爲哈希算法。
要保證hash的正確性,做爲key的對象就不能變。在Python中,字符串、整數等都是不可變的,所以,能夠放心地做爲key。而list是可變的,就不能做爲key:
set
set和dict相似,也是一組key的集合,但不存儲value。因爲key不能重複,因此,在set中,沒有重複的key。
要建立一個set,須要提供一個list做爲輸入集合:
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
注意,傳入的參數[1, 2, 3]
是一個list,而顯示的{1, 2, 3}
只是告訴你這個set內部有1,2,3這3個元素,顯示的順序也不表示set是有序的。。
重複元素在set中自動被過濾:
>>> s = set([1, 1, 2, 2, 3, 3])
>>> s
{1, 2, 3}
經過add(key)
方法能夠添加元素到set中,能夠重複添加,但不會有效果:
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
經過remove(key)
方法能夠刪除元素:
>>> s.remove(4)
>>> s
{1, 2, 3}
set能夠當作數學意義上的無序和無重複元素的集合,所以,兩個set能夠作數學意義上的交集、並集等操做:
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}
set和dict的惟一區別僅在於沒有存儲對應的value,可是,set的原理和dict同樣,因此,一樣不能夠放入可變對象,由於沒法判斷兩個可變對象是否相等,也就沒法保證set內部「不會有重複元素」。試試把list放入set,看看是否會報錯。
再議不可變對象
上面咱們講了,str是不變對象,而list是可變對象。
對於可變對象,好比list,對list進行操做,list內部的內容是會變化的,好比:
>>> a = ['c', 'b', 'a']
>>> a.sort()
>>> a
['a', 'b', 'c']
而對於不可變對象,好比str,對str進行操做呢:
>>> a = 'abc'
>>> a.replace('a', 'A')
'Abc'
>>> a
'abc'
雖然字符串有個replace()
方法,也確實變出了'Abc'
,但變量a
最後還是'abc'
,應該怎麼理解呢?
咱們先把代碼改爲下面這樣:
>>> a = 'abc'
>>> b = a.replace('a', 'A')
>>> b
'Abc'
>>> a
'abc'
要始終牢記的是,a
是變量,而'abc'
纔是字符串對象!有些時候,咱們常常說,對象a
的內容是'abc'
,但實際上是指,a
自己是一個變量,它指向的對象的內容纔是'abc'
:
┌───┐ ┌───────┐
│ a │─────────────────>│ 'abc' │
└───┘ └───────┘
當咱們調用a.replace('a', 'A')
時,實際上調用方法replace
是做用在字符串對象'abc'
上的,而這個方法雖然名字叫replace
,但卻沒有改變字符串'abc'
的內容。相反,replace
方法建立了一個新字符串'Abc'
並返回,若是咱們用變量b
指向該新字符串,就容易理解了,變量a
仍指向原有的字符串'abc'
,但變量b
卻指向新字符串'Abc'
了:
┌───┐ ┌───────┐
│ a │─────────────────>│ 'abc' │
└───┘ └───────┘
┌───┐ ┌───────┐
│ b │─────────────────>│ 'Abc' │
└───┘ └───────┘
因此,對於不變對象來講,調用對象自身的任意方法,也不會改變該對象自身的內容。相反,這些方法會建立新的對象並返回,這樣,就保證了不可變對象自己永遠是不可變的。
小結
使用key-value存儲結構的dict在Python中很是有用,選擇不可變對象做爲key很重要,最經常使用的key是字符串。
tuple雖然是不變對象,但試試把(1, 2, 3)
和(1, [2, 3])
放入dict或set中,並解釋結果。
5、定義函數
在Python中,定義一個函數要使用
def
語句,依次寫出函數名、括號、括號中的參數和冒號
:
,而後,在縮進塊中編寫函數體,函數的返回值用
return
語句返回。
咱們以自定義一個求絕對值的my_abs
函數爲例:
請注意,函數體內部的語句在執行時,一旦執行到return
時,函數就執行完畢,並將結果返回。所以,函數內部經過條件判斷和循環能夠實現很是複雜的邏輯。
若是沒有return
語句,函數執行完畢後也會返回結果,只是結果爲None
。return None
能夠簡寫爲return
。
在Python交互環境中定義函數時,注意Python會出現...
的提示。函數定義結束後須要按兩次回車從新回到>>>
提示符下:
┌────────────────────────────────────────────────────────┐
│Command Prompt - python - □ x │
├────────────────────────────────────────────────────────┤
│>>> def my_abs(x): │
│... if x >= 0: │
│... return x │
│... else: │
│... return -x │
│... │
│>>> my_abs(-9) │
│9 │
│>>> _ │
│ │
│ │
└────────────────────────────────────────────────────────┘
若是你已經把my_abs()
的函數定義保存爲abstest.py
文件了,那麼,能夠在該文件的當前目錄下啓動Python解釋器,用from abstest import my_abs
來導入my_abs()
函數,注意abstest
是文件名(不含.py
擴展名):
┌────────────────────────────────────────────────────────┐
│Command Prompt - python - □ x │
├────────────────────────────────────────────────────────┤
│>>> from abstest import my_abs │
│>>> my_abs(-9) │
│9 │
│>>> _ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└────────────────────────────────────────────────────────┘
import
的用法在後續模塊一節中會詳細介紹。
空函數
若是想定義一個什麼事也不作的空函數,能夠用pass
語句:
pass
語句什麼都不作,那有什麼用?實際上pass
能夠用來做爲佔位符,好比如今還沒想好怎麼寫函數的代碼,就能夠先放一個pass
,讓代碼能運行起來。
pass
還能夠用在其餘語句裏,好比:
缺乏了pass
,代碼運行就會有語法錯誤。
參數檢查
調用函數時,若是參數個數不對,Python解釋器會自動檢查出來,並拋出TypeError
:
>>> my_abs(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: my_abs() takes 1 positional argument but 2 were given
可是若是參數類型不對,Python解釋器就沒法幫咱們檢查。試試my_abs
和內置函數abs
的差異:
>>> my_abs('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in my_abs
TypeError: unorderable types: str() >= int()
>>> abs('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'
當傳入了不恰當的參數時,內置函數abs
會檢查出參數錯誤,而咱們定義的my_abs
沒有參數檢查,會致使if
語句出錯,出錯信息和abs
不同。因此,這個函數定義不夠完善。
讓咱們修改一下my_abs
的定義,對參數類型作檢查,只容許整數和浮點數類型的參數。數據類型檢查能夠用內置函數isinstance()
實現:
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
添加了參數檢查後,若是傳入錯誤的參數類型,函數就能夠拋出一個錯誤:
>>> my_abs('A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in my_abs
TypeError: bad operand type
錯誤和異常處理將在後續講到。
返回多個值
函數能夠返回多個值嗎?答案是確定的。
好比在遊戲中常常須要從一個點移動到另外一個點,給出座標、位移和角度,就能夠計算出新的新的座標:
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
import math
語句表示導入math
包,並容許後續代碼引用math
包裏的sin
、cos
等函數。
而後,咱們就能夠同時得到返回值:
>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632 70.0
但其實這只是一種假象,Python函數返回的仍然是單一值:
>>> r = move(100, 100, 60, math.pi / 6)
>>> print(r)
(151.96152422706632, 70.0)
原來返回值是一個tuple!可是,在語法上,返回一個tuple能夠省略括號,而多個變量能夠同時接收一個tuple,按位置賦給對應的值,因此,Python的函數返回多值其實就是返回一個tuple,但寫起來更方便。
小結
定義函數時,須要肯定函數名和參數個數;
若是有必要,能夠先對參數的數據類型作檢查;
函數體內部能夠用return
隨時返回函數結果;
函數執行完畢也沒有return
語句時,自動return None
。
函數能夠同時返回多個值,但其實就是一個tuple。
練習
請定義一個函數quadratic(a, b, c)
,接收3個參數,返回一元二次方程:
ax2 + bx + c = 0
的兩個解。
提示:計算平方根能夠調用math.sqrt()
函數:
>>> import math
>>> math.sqrt(2)
1.4142135623730951