Python

學廖雪峯老師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以執行權限:

chmod a+x hello.py

就能夠直接運行hello.py了,好比在Mac下運行:

./hello.py
hello,word

小結:一、用文本編輯器寫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裏,各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文本中,顯示出來會有亂碼。

char-encoding-problem

所以,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,直接支持多語言。

strbytes互相轉換時,須要指定編碼。最經常使用的編碼是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元素個數

>>>len(classmates)
3

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,能夠寫成():

>>> t = ()
>>> t
()

可是要定義一個只有1個元素的tuple,若是你這麼定義

>>> t = (1)
>>> t
1

定義的不是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判斷條件還能夠簡寫,好比寫:

if x:
    print('True');

只要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是否存在:

>>>'Tomas' in d
False

二是經過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函數爲例:

 
   
# -*- coding: utf-8 -*-
def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x
print(my_abs(-99))

請注意,函數體內部的語句在執行時,一旦執行到return時,函數就執行完畢,並將結果返回。所以,函數內部經過條件判斷和循環能夠實現很是複雜的邏輯。

若是沒有return語句,函數執行完畢後也會返回結果,只是結果爲Nonereturn 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語句:

def nop():
    pass

pass語句什麼都不作,那有什麼用?實際上pass能夠用來做爲佔位符,好比如今還沒想好怎麼寫函數的代碼,就能夠先放一個pass,讓代碼能運行起來。

pass還能夠用在其餘語句裏,好比:

if age >= 18:
    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包裏的sincos等函數。

而後,咱們就能夠同時得到返回值:

>>> 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

 

相關文章
相關標籤/搜索