Python:函數(shù)

函數(shù)

Python的函數(shù)其實(shí)和Java的C的函數(shù)差不多欺殿,這里只講講和Java不同的地方。注意:函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會(huì)加一層棧幀宠进,每當(dāng)函數(shù)返回,棧就會(huì)減一層棧幀藐翎。

函數(shù)別名

函數(shù)名其實(shí)就是指向一個(gè)函數(shù)對(duì)象的引用材蹬,完全可以把函數(shù)名賦給一個(gè)變量,相當(dāng)于給這個(gè)函數(shù)起了一個(gè)“別名”:

# 變量a指向abs函數(shù)
a = abs
print(a(-2.1))
定義函數(shù)

在Python中吝镣,定義一個(gè)函數(shù)要使用def語句堤器,依次寫出函數(shù)名、括號(hào)末贾、括號(hào)中的參數(shù)和冒號(hào):闸溃,然后,在縮進(jìn)塊中編寫函數(shù)體拱撵,函數(shù)的返回值用return語句返回辉川。

def add(a,b):
    return a+b;

print(add(1,2))

如果沒有return語句,函數(shù)執(zhí)行完畢后也會(huì)返回結(jié)果拴测,只是結(jié)果為None乓旗。return None可以簡(jiǎn)寫為return。還有點(diǎn)和Java不一樣的是集索,函數(shù)必須定義在調(diào)用的前面屿愚,不然會(huì)報(bào)錯(cuò)汇跨。

  • 空函數(shù)
    如果想定義一個(gè)什么事也不做的空函數(shù),可以用pass語句:
# 定義了一個(gè)空函數(shù)
def add():
    pass

pass語句什么都不做渺鹦,那有什么用扰法?實(shí)際上pass可以用來作為占位符,比如現(xiàn)在還沒想好怎么寫函數(shù)的代碼毅厚,就可以先放一個(gè)pass塞颁,讓代碼能運(yùn)行起來。
pass還可以用在其他語句里吸耿,比如:

x = 2
if x>0:
    pass

缺少了pass祠锣,代碼運(yùn)行就會(huì)有語法錯(cuò)誤。

  • 參數(shù)檢查
    在Python里面咽安,當(dāng)我們調(diào)用函數(shù)的時(shí)候伴网,解釋器會(huì)幫我檢查函數(shù)參數(shù)的格式是否正確,不正確會(huì)報(bào)下面的錯(cuò)妆棒。
Traceback (most recent call last):
  File "F:/Pythonproject/test_dir/__init__.py", line 90, in <module>
    print(a(-2.1,0))
TypeError: abs() takes exactly one argument (2 given)

但是如果是自己調(diào)用的自己寫的函數(shù)或者是別人寫的話澡腾,那么假如我們傳入的參數(shù)類型不對(duì)的話,這個(gè)時(shí)候就很難讓調(diào)用者知道傳入的參數(shù)類型是錯(cuò)誤的糕珊,那么我們就需要為函數(shù)的參數(shù)做檢查了动分,對(duì)參數(shù)類型做檢查,只允許整數(shù)和浮點(diǎn)數(shù)類型的參數(shù)红选。數(shù)據(jù)類型檢查可以用內(nèi)置函數(shù)isinstance()實(shí)現(xiàn):

def add(a, b):
    if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
        raise TypeError('參數(shù)類型錯(cuò)誤')
    else:
        return a + b

add('A', 2)

添加了參數(shù)檢查后澜公,如果傳入錯(cuò)誤的參數(shù)類型,函數(shù)就可以拋出一個(gè)錯(cuò)誤:

Traceback (most recent call last):
  File "F:/Pythonproject/test_dir/__init__.py", line 113, in <module>
    add('A', 2)
  File "F:/Pythonproject/test_dir/__init__.py", line 109, in add
    raise TypeError('參數(shù)類型錯(cuò)誤')
TypeError: 參數(shù)類型錯(cuò)誤
  • 返回多個(gè)值
    在C或者java中喇肋,如果遇到需要返回不同結(jié)果的坟乾,一般都會(huì)用一個(gè)對(duì)象或者結(jié)構(gòu)體返回,但是在Python中函數(shù)可以返回多個(gè)值嗎蝶防?答案是肯定的
def get(a, b, c):
    return a, b, c

a, b, c = get(1, 2, 3)
print(a, b, c)

Python是怎么辦到的寝姿?其實(shí)這個(gè)和我們上一篇講到的tuple有關(guān)簸淀,函數(shù)返回其實(shí)是一個(gè)tuple役电,本質(zhì)還是一個(gè)返回值幻妓,看到的知識(shí)一個(gè)假象而已壶栋。

函數(shù)的參數(shù)

Python的函數(shù)定義非常簡(jiǎn)單跑杭,但靈活度卻非常大盯串。除了正常定義的必選參數(shù)外抚垄,還可以使用默認(rèn)參數(shù)躏鱼、可變參數(shù)和關(guān)鍵字參數(shù)氮采,使得函數(shù)定義出來的接口,不但能處理復(fù)雜的參數(shù)染苛,還可以簡(jiǎn)化調(diào)用者的代碼鹊漠。

  • 位置參數(shù)
def count(a, n):
    count = 1
    while n>0:
        n = n-1
        count = count * a
    return count

print(count(2,3))

對(duì)于count(a, n)函數(shù)主到,參數(shù)a, n就是一個(gè)位置參數(shù)。

  • 默認(rèn)參數(shù)
    上面代碼count函數(shù)躯概,假如有許多地方普遍用到的都是n=2這個(gè)值登钥,我們不想給count函數(shù)傳入兩個(gè)參數(shù),這個(gè)時(shí)候我們就可以給n一個(gè)默認(rèn)的值娶靡,而n也就是默認(rèn)參數(shù)了:
def count(a, n=2,c=3):
    count = 1
    while n>0:
        n = n-1
        count = count * a
    return count
# n與c都是默認(rèn)的牧牢,不用傳入
print(count(2))
# 按照順序的 指定n為3
print(count(2,3))
# 也可以指定調(diào)用的參數(shù)與確切的值
print(count(2,c = 6))

這么玩需要注意:一是必選參數(shù)在前,默認(rèn)參數(shù)在后姿锭,否則Python的解釋器會(huì)報(bào)錯(cuò)(思考一下為什么默認(rèn)參數(shù)不能放在必選參數(shù)前面)塔鳍;二是如何設(shè)置默認(rèn)參數(shù)。
當(dāng)函數(shù)有多個(gè)參數(shù)時(shí)呻此,把變化大的參數(shù)放前面轮纫,變化小的參數(shù)放后面。變化小的參數(shù)就可以作為默認(rèn)參數(shù)焚鲜。
下面有個(gè)有意思的代碼掌唾,帶你躺坑:

def test(t=[]):
    t.append('test')
    return t

print(test())
print(test())

['test']
['test', 'test']

這個(gè)代碼這么寫是有點(diǎn)問題的,不夠嚴(yán)謹(jǐn)忿磅,Python函數(shù)在定義的時(shí)候糯彬,默認(rèn)參數(shù)L的值就被計(jì)算出來了,即[]贝乎,因?yàn)槟J(rèn)參數(shù)t也是一個(gè)變量情连,它指向?qū)ο骩],每次調(diào)用該函數(shù)览效,如果改變了t的內(nèi)容却舀,則下次調(diào)用時(shí),默認(rèn)參數(shù)的內(nèi)容就變了锤灿,不再是函數(shù)定義時(shí)的[]了挽拔。

定義默認(rèn)參數(shù)要牢記一點(diǎn):默認(rèn)參數(shù)必須指向不變對(duì)象!

那么上面代碼改成下面這樣就不會(huì)有問題了:

def test(t=None):
    if t is None:
        t = []
    t.append('test')
    return t

print(test())
print(test())
  • 可變參數(shù)
    在Python函數(shù)中但校,還可以定義可變參數(shù)螃诅。顧名思義,可變參數(shù)就是傳入的參數(shù)個(gè)數(shù)是可變的状囱,可以是1個(gè)术裸、2個(gè)到任意個(gè),還可以是0個(gè)亭枷。
    如何實(shí)現(xiàn)這個(gè)問題袭艺?我們想到的是list或者tuple來做參數(shù),如下程序:
def add(x=None):
    if x is None:
        x = []
    sum = 0
    for n in x:
        sum = sum + n
    return sum

print(add([1,2,3,4]))

上面程序可以簡(jiǎn)化一下叨粘,這么寫猾编,但是會(huì)讓調(diào)用者不太明白參數(shù)的類型:

def add(x):
    sum = 0
    for n in x:
        sum = sum + n
    return sum

print(add([1,2,3,4]))

下面瘤睹,我們利用Python的可變參數(shù)來寫:

# 在參數(shù)面前加入*
def add(*x):
    sum = 0
    for n in x:
        sum = sum + n
    return sum

# 在調(diào)用的時(shí)候,參數(shù)可以是任何類型答倡,參數(shù)個(gè)數(shù)也可以是隨意的了
print(add(1,2,3,4))

有這么一種情況轰传,你可以這么調(diào)用傳遞參數(shù):

def add(*x):
    sum = 0
    for n in x:
        sum = sum + n
    return sum

s = [1,2,3,4]
# Python允許你在list或tuple前面加一個(gè)*號(hào),把list或tuple的元素變成可變參數(shù)傳進(jìn)去:
print(add(*s))
  • 關(guān)鍵字參數(shù)
    可變參數(shù)在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè)tuple瘪撇,關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動(dòng)組裝為一個(gè)dict获茬。
def infor(name,age,**other):
    print('name=',name,'age=',age,'other=',other)
    return

# 調(diào)用必填參數(shù)
infor('lisa',12)
# 傳任意個(gè)數(shù)的關(guān)鍵字參數(shù)
infor('ds',23,height = 176,city = 'hz')
# 傳一個(gè)dict的關(guān)鍵字參數(shù)
s = {'height' :'176','city' : 'hz'}
infor('ds',23,**s)

關(guān)鍵字參數(shù)有什么用?它可以擴(kuò)展函數(shù)的功能设江。比如锦茁,在infor函數(shù)里,我們保證能接收到name和age這兩個(gè)參數(shù)叉存,但是码俩,如果調(diào)用者愿意提供更多的參數(shù),我們也能收到歼捏。試想你正在做一個(gè)用戶注冊(cè)的功能稿存,除了用戶名和年齡是必填項(xiàng)外,其他都是可選項(xiàng)瞳秽,利用關(guān)鍵字參數(shù)來定義這個(gè)函數(shù)就能滿足注冊(cè)的需求瓣履。

  • 命名關(guān)鍵字參數(shù)
    在關(guān)鍵字參數(shù)中,如果我們要限定關(guān)鍵字的名字應(yīng)該如何辦练俐?Python提供了命名關(guān)鍵字參數(shù)袖迎。用法如下:
# 如果要限制關(guān)鍵字參數(shù)的名字,就可以用命名關(guān)鍵字參數(shù)腺晾,例如燕锥,只接收city和job作為關(guān)鍵字參數(shù)。
# 和關(guān)鍵字參數(shù)**other不同悯蝉,命名關(guān)鍵字參數(shù)需要一個(gè)特殊分隔符*归形,*后面的參數(shù)被視為命名關(guān)鍵字參數(shù)。這種方式定義的函數(shù)如下
def infor(name,age,*,height,city = 'hz'):
    print(name,age,height,city)
    return

# 注意鼻由,必須要寫上height與city暇榴,并且不可以拼錯(cuò),命名關(guān)鍵字參數(shù)可以有缺省值,從而簡(jiǎn)化調(diào)用
infor('lisa',12,height = '170',city = 'sh')

如果函數(shù)定義中已經(jīng)有了一個(gè)可變參數(shù)蕉世,后面跟著的命名關(guān)鍵字參數(shù)就不再需要一個(gè)特殊分隔符*了:

# 注意只能是可變參數(shù)蔼紧,不是關(guān)鍵字參數(shù),否則會(huì)報(bào)錯(cuò)
def infor(name,age,*other,height,city):
    print(name,age,height,city)
    return

# 注意狠轻,必須要寫上height與city奸例,并且不可以拼錯(cuò)
infor('lisa',12,height = '170',city = 'zh')
  • 如何組合這些參數(shù)?
    在Python中定義函數(shù)哈误,可以用必選參數(shù)哩至、默認(rèn)參數(shù)、可變參數(shù)蜜自、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù)菩貌,這5種參數(shù)都可以組合使用。但是請(qǐng)注意重荠,參數(shù)定義的順序必須是:必選參數(shù)箭阶、默認(rèn)參數(shù)、可變參數(shù)戈鲁、命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)仇参。
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

# 普通調(diào)用:
f1(1, 2)
# a = 1 b = 2 c = 0 args = () kw = {}
 f1(1, 2, c=3)
# a = 1 b = 2 c = 3 args = () kw = {}
 f1(1, 2, 3, 'a', 'b')
# a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
 f1(1, 2, 3, 'a', 'b', x=99)
# a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
 f2(1, 2, d=99, ext=None)
# a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

# 通過tuple和dict來調(diào)用:
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)
# a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
args = (1, 2, 3)
kw = {'d': 88, 'x': '#'}
f2(*args, **kw)
# a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

所以,對(duì)于任意函數(shù)婆殿,都可以通過類似func(*args, **kw)的形式調(diào)用它诈乒,無論它的參數(shù)是如何定義的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末婆芦,一起剝皮案震驚了整個(gè)濱河市怕磨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌消约,老刑警劉巖肠鲫,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異或粮,居然都是意外死亡导饲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門氯材,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渣锦,“玉大人,你說我怎么就攤上這事浓体∨萃Γ” “怎么了?”我有些...
    開封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵命浴,是天一觀的道長(zhǎng)娄猫。 經(jīng)常有香客問我,道長(zhǎng)生闲,這世上最難降的妖魔是什么媳溺? 我笑而不...
    開封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮碍讯,結(jié)果婚禮上悬蔽,老公的妹妹穿的比我還像新娘。我一直安慰自己捉兴,他們只是感情好蝎困,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開白布录语。 她就那樣靜靜地躺著,像睡著了一般禾乘。 火紅的嫁衣襯著肌膚如雪澎埠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天始藕,我揣著相機(jī)與錄音蒲稳,去河邊找鬼。 笑死伍派,一個(gè)胖子當(dāng)著我的面吹牛江耀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诉植,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼祥国,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了倍踪?” 一聲冷哼從身側(cè)響起系宫,我...
    開封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎建车,沒想到半個(gè)月后扩借,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缤至,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年潮罪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片领斥。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嫉到,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出月洛,到底是詐尸還是另有隱情何恶,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布嚼黔,位于F島的核電站细层,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏唬涧。R本人自食惡果不足惜疫赎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碎节。 院中可真熱鬧捧搞,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至晚树,卻和暖如春碗短,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背题涨。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留总滩,地道東北人纲堵。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像闰渔,于是被迫代替她去往敵國(guó)和親席函。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)名其實(shí)就是指向一個(gè)函數(shù)對(duì)象的引用冈涧,完全可以把函數(shù)名賦給一個(gè)變量茂附,相當(dāng)于給這個(gè)函數(shù)起了一個(gè)“別名”:a = ab...
    bjchenli閱讀 612評(píng)論 0 0
  • 調(diào)用函數(shù) 函數(shù)名,參數(shù)督弓,參數(shù)類型和個(gè)數(shù)要和定義時(shí)一樣营曼,如 數(shù)據(jù)類型轉(zhuǎn)換 函數(shù)名其實(shí)是一個(gè)函數(shù)對(duì)象的引用,可以把函數(shù)...
    齊天大圣李圣杰閱讀 393評(píng)論 0 1
  • python函數(shù)的參數(shù)是目前見過最復(fù)雜的參數(shù)了愚隧。 C語言里用的最多的可變參數(shù)函數(shù)就是scanf和printf了蒂阱,j...
    米耳閱讀 352評(píng)論 0 0
  • 一.函數(shù) 1.1 調(diào)用函數(shù): Python內(nèi)置了很多有用的函數(shù),我們可以直接調(diào)用狂塘。要調(diào)用一個(gè)函數(shù)录煤,需要知道...
    Mr_dvbkhm閱讀 798評(píng)論 0 1
  • 突然決定寫她是一個(gè)偶然的機(jī)會(huì),我準(zhǔn)備在廚房裝一個(gè)暖水寶荞胡,來了一位英俊的安裝工妈踊,不知怎的就突然聊到了她——我的同學(xué),...
    紅色的魚兒閱讀 433評(píng)論 0 10