1切省、函數(shù)的基本概念
函數(shù): 是一段可以重復(fù)多次調(diào)用的代碼辩块,通過輸入的參數(shù)值蛔六,返回需要的結(jié)果。通俗地說(shuō)庆捺,函數(shù)就是完成特定功能的一個(gè)語(yǔ)句組古今,這組語(yǔ)句可以作為一個(gè)單位使用,并且給它取一個(gè)名字滔以,這樣捉腥,我們就可以通過函數(shù)名在程序的不同地方多次執(zhí)行(這通常叫做函數(shù)調(diào)用),卻不需要在所有地方都重復(fù)編寫這些語(yǔ)句你画。另外抵碟,每次使用函數(shù)時(shí)可以提供不同的參數(shù)作為輸入,以便對(duì)不同的數(shù)據(jù)進(jìn)行處理坏匪;函數(shù)處理后拟逮,還可以將相應(yīng)的結(jié)果反饋給我們。
2适滓、定義函數(shù):
2.1敦迄、函數(shù)定義的語(yǔ)法:
def function_name(argument1[=default_value1], argument2[=default_value2]...):
''' docString '''
pass
return expression
- def 關(guān)鍵字:definition 的縮寫,表示后面定義的是一個(gè)函數(shù)或方法。
- 函數(shù)名:以字母罚屋、數(shù)字或下劃線組成的字符串苦囱,但是不能以數(shù)字開頭。推薦全部使用小寫字母脾猛,單詞之間以下劃線隔開
- 文檔字符串:是包, 模塊, 類或函數(shù)里的第一個(gè)語(yǔ)句撕彤。 這些字符串可以通過對(duì)象的
__doc__
成員被自動(dòng)提取, 并且被 pydoc 所用。 - 函數(shù)的參數(shù):放在一對(duì)圓括號(hào)中猛拴,參數(shù)的個(gè)數(shù)可以有零個(gè)羹铅、一個(gè)或多個(gè),參數(shù)之間用逗號(hào)隔開愉昆。
- 形參职员、實(shí)參:在定義函數(shù)時(shí),函數(shù)名后面圓括號(hào)中的變量名稱叫做“形式參數(shù)”撼唾,或簡(jiǎn)稱為“形參”廉邑;在調(diào)用函數(shù)時(shí),函數(shù)名后面圓括號(hào)中的變量名稱叫做“實(shí)際參數(shù)”倒谷,或簡(jiǎn)稱為“實(shí)參”。
- 缺省參數(shù):在定義函數(shù)時(shí)糙箍,我們可以用賦值符號(hào)給某些形參指定默認(rèn)值渤愁,這樣當(dāng)調(diào)用該函數(shù)的時(shí)候,如果調(diào)用方?jīng)]有為該參數(shù)提供值的話深夯,則使用默認(rèn)值抖格;如果調(diào)用該函數(shù)的時(shí)候?yàn)樵搮?shù)提供了值的話,則使用調(diào)用方提供的值 -- 像這樣的參數(shù)我們稱之為缺省參數(shù)咕晋。
- return 語(yǔ)句:return 語(yǔ)句的作用是結(jié)束函數(shù)調(diào)用雹拄,并將結(jié)果返回給調(diào)用者。不過掌呜,對(duì)于函數(shù)來(lái)說(shuō)滓玖,該語(yǔ)句是可選的,并且可以出現(xiàn)在函數(shù)體的任意位置质蕉;對(duì)于沒有使用 return 語(yǔ)句的函數(shù)势篡,它實(shí)際上也向調(diào)用者返回一個(gè)值,那就是 None模暗。
2.2禁悠、定義一個(gè)空函數(shù):
def function_name(argument1[=default_value1], argument2[=default_value2]...):
pass
pass 語(yǔ)句什么都不做,只是用來(lái)作為占位符兑宇,比如:現(xiàn)在還沒想好怎么寫函數(shù)的代碼碍侦,就可以先放一個(gè)pass,讓代碼能運(yùn)行起來(lái)。
3瓷产、函數(shù)調(diào)用:
3.1比规、函數(shù)調(diào)用語(yǔ)法:
function_name(argument1, argument2...)
在交互式命令行,比如說(shuō)想要獲得 print 函數(shù)的幫助信息拦英,可以執(zhí)行如下命令
>>> help('print')
3.2蜒什、參數(shù)傳遞的方法
- 標(biāo)準(zhǔn)調(diào)用:標(biāo)準(zhǔn)調(diào)用方式,傳遞的值按照形參定義的順序相應(yīng)地賦給它們疤估。
- 關(guān)鍵字調(diào)用:即在調(diào)用函數(shù)時(shí)同時(shí)給出形式參數(shù)和實(shí)際參數(shù)灾常。解釋器能通過給出的關(guān)鍵字來(lái)匹配參數(shù)的值,所以這樣就允許參數(shù)缺失或者不按定義函數(shù)時(shí)的形式參數(shù)的順序提供實(shí)際參數(shù)铃拇。
- 默認(rèn)值參數(shù):只有在形參表末尾的那些參數(shù)可以有默認(rèn)參數(shù)值钞瀑,也就是說(shuō)你不能在聲明函數(shù)形參的時(shí)候,先聲明有默認(rèn)值的形參而后聲明沒有默認(rèn)值的形參慷荔。這是因?yàn)橘x給形參的值是根據(jù)位置而賦值的雕什。例如,
def func(a, b=1)
是有效的显晶,但是def func(a=1, b)
是無(wú)效的贷岸。
注:
默認(rèn)參數(shù)的值是不可變的對(duì)象,比如 None磷雇、True偿警、False、數(shù)字或字符串
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
def print_info( a , b = [] ):
print("value: %s, id: %d" %(b, id(b)))
return b
if __name__ == '__main__':
result = print_info(1)
result.append('error')
print_info(2)
執(zhí)行結(jié)果:
value: [], id: 42733832
value: ['error'], id: 42733832
3.2唯笙、參數(shù)檢查:
個(gè)數(shù)檢查:調(diào)用函數(shù)時(shí)螟蒸,如果參數(shù)個(gè)數(shù)不對(duì),Python 解釋器會(huì)自動(dòng)檢查出來(lái)崩掘,并拋出
TypeError
類型檢查:內(nèi)置函數(shù)
isinstance
可以用來(lái)判斷對(duì)象的類型七嫌,基本語(yǔ)法如下:
isinstance(object, class-or-type-or-tuple) -> bool
第二個(gè)參數(shù)可以是一個(gè)類型名或一個(gè)元組,如果是元組的話苞慢,對(duì)象類型與元組中類型名之一相同即返回True诵原。
判斷一個(gè)對(duì)象是否是字符串
>>> s = 'abc'
>>> isinstance(s,basestring)
True
>>> s = 3
>>> isinstance(s,basestring)
False
檢查到錯(cuò)誤之后,我們可以通過 raise 自己觸發(fā)一個(gè)異常
3.4枉疼、變量的作用域
在 Python 中的任何變量都有其特定的作用域皮假,比如在一個(gè)函數(shù)中定義的變量一般只能在該函數(shù)內(nèi)部使用,這些只能在程序的特定部分使用的變量我們稱之為局部變量骂维;比如在一個(gè)文件頂部定義的變量可以供該文件中的任何函數(shù)調(diào)用惹资,這些可以為整個(gè)程序所使用的變量稱為全局變量。
上面是從空間的角度來(lái)考察變量的局部性和全局性航闺,如果從時(shí)間的角度來(lái)看褪测,不妨簡(jiǎn)單地認(rèn)為在程序運(yùn)行的整個(gè)過程中猴誊,全局變量一直占據(jù)著內(nèi)存,并且它的值可以供所有函數(shù)訪問侮措;而局部變量則是只有在其所在函數(shù)被調(diào)用時(shí)才給它分配內(nèi)存懈叹,當(dāng)函數(shù)返回時(shí),其所占內(nèi)存就會(huì)被釋放分扎,所以它只能供其所在的函數(shù)所訪問——換句話說(shuō)澄成,當(dāng)某個(gè)函數(shù)退出時(shí),其局部變量原先所占的內(nèi)存將被分配給其它函數(shù)的局部變量畏吓。打個(gè)不太貼切的比方墨状,全局變量就好比您自己買的房子,通常一家人要在那里住上好幾十年菲饼,如果我要找您要債肾砂,我會(huì)老往您家里跑;而局部變量好像旅館宏悦,今天您租住這件房間镐确,我可以到這個(gè)房間來(lái)找您,但是到明天再來(lái)這間房間的話饼煞,找到的可能就是別人了源葫。
在同一個(gè)源文件中,全局變量和局部變量同名時(shí)派哲,在局部變量的作用范圍內(nèi)臼氨,全局變量不起作用。像下面這個(gè)例子芭届,在函數(shù) func 外部定義的變量 x ,和在函數(shù)內(nèi)部定義的 x 互不影響
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
def func(x):
print("x 在函數(shù)內(nèi)感耙,改變前:%d, x is %d" %(id(x), x))
x = 2
print("x 在函數(shù)內(nèi)褂乍,改變后:%d, x is %d" %(id(x), x))
if __name__ == '__main__':
x = 50
print("x 在函數(shù)外:%d, x is %d" %(id(x), x))
func(x)
print('x 在函數(shù)外:%d, x is still %d' %(id(x), x))
輸出:
x 在函數(shù)外:500593664, x is 50
x 在函數(shù)內(nèi),改變前:500593664, x is 50
x 在函數(shù)內(nèi)即硼,改變后:500592128, x is 2
x 在函數(shù)外:500593664, x is still 50
這個(gè)過程逃片,用文字描述如下:
- “x = 50”:新建了一個(gè)整形對(duì)象 50,分配了內(nèi)存地址為:500593664只酥,并且將函數(shù)外變量 x 綁定到了這個(gè)對(duì)象上褥实。
- “func(x)”:新建了一個(gè)函數(shù)內(nèi)變量 x,并且將 x 綁定到這個(gè)對(duì)象上裂允,所以此時(shí)损离,對(duì)象內(nèi)存地址未變
- “x = 2”:新建了一個(gè)整型對(duì)象 2,分配了內(nèi)存地址:500592128绝编,并將函數(shù)內(nèi)變量 x 重新綁定到了這個(gè)對(duì)象上
如果你想要為一個(gè)定義在函數(shù)外的變量賦值僻澎,那么你就得告訴 Python 這個(gè)變量名不是局部的貌踏,而是全局的。我們使用 global 語(yǔ)句完成這一功能窟勃。
global 語(yǔ)句的作用是將某些變量聲明為全局變量祖乳,變量名可以是一個(gè),也可以是多個(gè)秉氧。當(dāng)關(guān)鍵詞 global 后面跟隨多個(gè)變量名稱時(shí)眷昆,各名稱之間要用逗號(hào)分隔開來(lái)。
#!/usr/bin/python
# Filename: func_global.py
def func():
global x
print 'x is', x
x = 2
print 'Changed local x to', x
x = 50
func()
print 'Value of x is', x
輸出
]# python func_global.py
x is 50
Changed global x to 2
Value of x is 2
注1:
在 Python 中汁咏,字符串亚斋,整形,浮點(diǎn)型梆暖,tuple 是不可更改的對(duì)象伞访,而 list , dict 等是可以更改的對(duì)象轰驳。
- 不可更改的類型:類似 c++ 的值傳遞厚掷,如:整數(shù)、字符串级解、元組冒黑。如fun(a),傳遞的只是 a 的值勤哗,沒有影響 a 對(duì)象本身抡爹。比如在 fun(a) 內(nèi)部修改 a 的值,只是修改另一個(gè)復(fù)制的對(duì)象芒划,不會(huì)影響 a 本身冬竟。
- 可更改的類型:類似 c++ 的引用傳遞,如:列表民逼,字典泵殴。如 fun(a),則是將 a 真正的傳過去拼苍,修改后 fun 外部的 a 也會(huì)受影響
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
def chagne_list( b ):
print('函數(shù)中一開始 b 的值:{}, id 值為:%d' .format( b ) %id(b))
b.append(1000)
print('函數(shù)中 b 賦值后的值:{}, id 值為:%d' .format( b ) %id(b))
if __name__ == '__main__':
b = [1, 2, 3, 4, 5]
chagne_list(b)
print('最后輸出 b 的值:{}, id 值為:%d'.format(b) %id(b))
執(zhí)行結(jié)果為:
函數(shù)中一開始 b 的值:[1, 2, 3, 4, 5], id 值為:42799368
函數(shù)中 b 賦值后的值:[1, 2, 3, 4, 5, 1000], id 值為:42799368
最后輸出 b 的值:[1, 2, 3, 4, 5, 1000], id 值為:42799368
注2:
如果要避免上面這種情況發(fā)生笑诅,可以向函數(shù)傳遞一個(gè)字典或列表的副本,而不是它本身
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
import copy
def chagne_list( b ):
print('函數(shù)中一開始 b 的值:{}, id 值為:%d' .format( b ) %id(b))
b.append(1000)
print('函數(shù)中 b 賦值后的值:{}, id 值為:%d' .format( b ) %id(b))
if __name__ == '__main__':
b = [1, 2, 3, 4, 5]
print('函數(shù)外一開始 b 的值:{}, id 值為:%d'.format(b) % id(b))
chagne_list(copy.deepcopy(b))
執(zhí)行結(jié)果為:
函數(shù)外一開始 b 的值:[1, 2, 3, 4, 5], id 值為:43472904
函數(shù)中一開始 b 的值:[1, 2, 3, 4, 5], id 值為:43473096
函數(shù)中 b 賦值后的值:[1, 2, 3, 4, 5, 1000], id 值為:43473096
注3:
上面這個(gè)例子疮鲫,又涉及到了 python 的淺拷貝和深拷貝吆你,再舉一個(gè)例子來(lái)說(shuō)明一下:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
import copy
if __name__ == '__main__':
original = [[1], "test"]
shallow_copy = copy.copy(original)
deep_copy = copy.deepcopy(original)
print("改變前:")
print("original 值為:{}, id 為:{}".format(original, id(original)))
print("shallow_copy 值為:{}, id 為:{}".format(shallow_copy, id(shallow_copy)))
print("deep_copy 值為:{}, id 為:{}".format(deep_copy, id(deep_copy)))
original[0].append(2)
print ("改變后:")
print("original 值為:{}, id 為:{}".format(original, id(original)))
print("shallow_copy 值為:{}, id 為:{}".format(shallow_copy, id(shallow_copy)))
print("deep_copy 值為:{}, id 為:{}".format(deep_copy, id(deep_copy)))
執(zhí)行結(jié)果:
改變前:
original 值為:[[1], 'test'], id 為:43338056
shallow_copy 值為:[[1], 'test'], id 為:43339336
deep_copy 值為:[[1], 'test'], id 為:43339272
改變后:
original 值為:[[1, 2], 'test'], id 為:43338056
shallow_copy 值為:[[1, 2], 'test'], id 為:43339336
deep_copy 值為:[[1], 'test'], id 為:43339272
3.5、傳遞長(zhǎng)度可變的參數(shù):
預(yù)先并不知道, 函數(shù)使用者會(huì)傳遞多少個(gè)參數(shù)給你, 所以在這個(gè)場(chǎng)景下使用如下兩個(gè)關(guān)鍵字俊犯。
- 在函數(shù)的參數(shù)前使用標(biāo)識(shí)符
*
:通常的寫法*args
妇多,可以將數(shù)量不定的,以位置參數(shù)方式傳入的參數(shù)打包一個(gè)元組中瘫析。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
def print_everything(*args):
for count, thing in enumerate(args):
print('{0}. {1}'.format(count, thing))
if __name__ == '__main__':
print_everything('apple', 'banana', 'cabbage')
輸出:
0. apple
1. banana
2. cabbage
- 在函數(shù)的參數(shù)前使用標(biāo)識(shí)符
**
:通常的寫法**kwargs
砌梆,可以將數(shù)量不定的默责,以關(guān)鍵字方式傳入的參數(shù)打包到一個(gè)字典中。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4
def greet_me(**kwargs):
for key, value in kwargs.items():
print("{0} == {1}".format(key, value))
if __name__ == '__main__':
greet_me(name="yasoob",age=15)
輸出
name == yasoob
age == 15
4咸包、函數(shù)的返回
python 函數(shù)返回值有兩種形式:
- 返回一個(gè)值
現(xiàn)看看返回一個(gè)值的吧桃序。
def firstvalue(a,b):
c = a + b
return c
print firstvalue(1,2)
結(jié)果:
3
- 返回多個(gè)值。
再看看返回多個(gè)值的:
def secondvalue(a,b):
c = a + b
return (a,b,c)
x,y,z = secondvalue(1,2)
print 'x:',x,'y:',y,'z:',z
結(jié)果:
x: 1 y: 2 z: 3