【Python 1-13】Python手把手教程之——詳解函數和函數的使用

-bash

做者 | 弗拉德
來源 | 弗拉德(公衆號:fulade_me)ide

定義函數

下面是一個打印問候語的簡單函數,名爲greet_user():函數

def greet_user():
    """顯示簡單的問候語"""
    print("Hello!")
greet_user()

這個示例演示了最簡單的函數結構。使用關鍵字def來告訴Python你要定義一個
函數。在這裏,函數名爲greet_user(),它不須要任何信息就能完成其工做,所以括號是空的(即使如此,括號也必不可少)。最後,定義以冒號結尾。測試

緊跟在def greet_user():後面的全部縮進行構成了函數體。代碼行print("Hello!")是函數體內的惟一一行代碼,greet_user()只作一項工做:打印Hello!。 ui

因爲這個函數不須要任何參數,所以調用它時只需輸入greet_user()便可。和預期的同樣,它打印Hello!code

向函數傳遞信息

只需稍做修改,就可讓函數greet_user()不只向用戶顯示Hello!,還將用戶的名字用做參數。 orm

所以,可在函數定義def greet_user()的括號內添加username。經過在這裏添加username,就可以讓函數接受你給username指定的任何值。如今,這個函數要求你調用它時給username指定一個值。調用greet_user()時,可將一個名字傳遞給它,以下所示:ci

def greet_user(username):
    """顯示簡單的問候語"""
    print("Hello, " + username.title() + "!")
greet_user('Fulade')

代碼greet_user('Fulade')調用函數greet_user(),並向它提供執行print語句所需的信息。這個函數接受你傳遞給它的名字,並向這我的發出問候:字符串

Hello Fulade !

一樣,greet_user('sarah')調用函數greet_user()並向它傳遞sarah,打印Hello, Sarah!
你能夠根據須要調用函數greet_user()任意次,調用時不管傳入什麼樣的名字,都會生成相應的輸出。get

實參和形參

前面定義函數greet_user()時,要求給變量username指定一個值。調用這個函數並提供這種參數,它將打印相應的問候語。

在函數greet_user()的定義中,變量username是一個形參——函數完成其工做所需的一項信息。在代碼greet_user('Fulade')中,值Fulade是一個實參。

實參是調用函數時傳遞給函數的信息。咱們調用函數時,將要讓函數使用的信息放在括號內。在greet_user('Fulade')中,將實參Fulade傳遞給了函數greet_user(),這個值被存儲在形參username中。

傳遞實參

鑑於函數定義中可能包含多個形參,所以函數調用中也可能包含多個實參。向函數傳遞實參的方式不少,可以使用位置實參,這要求實參的順序與形參的順序相同;也可以使用關鍵字實參,其中每一個實參都由變量名和值組成;還可以使用列表和字典。下面來依次介紹這些方式。

位置實參

你調用函數時,Python必須將函數調用中的每一個實參都關聯到函數定義中的一個形參。所以,最簡單的關聯方式是基於實參的順序。這種關聯方式被稱爲位置實參。爲明白其中的工做原理,來看一個顯示寵物信息的函數。這個函數指出一個寵物屬於哪一種動物以及它叫什麼名字,以下所示:

def describe_pet(animal_type, pet_name):
    """顯示寵物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('hamster', 'harry')

這個函數的定義代表,它須要一種動物類型和一個名字。調用describe_pet()時,須要按順序提供一種動物類型和一個名字。

例如,在前面的函數調用中,實參hamster存儲在形參animal_type中,而實參harry存儲在形參pet_name中。在函數體內,使用了這兩個形參來顯示寵物的信息。

調用函數屢次

你能夠根據須要調用函數任意次。要再描述一個寵物,只需再次調用describe_pet()便可:

def describe_pet(animal_type, pet_name):
    """顯示寵物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')

第二次調用describe_pet()函數時,咱們向它傳遞了實參dogwillie。與第一次調用時同樣,Python將實參dog關聯到形參animal_type,並將實參willie關聯到形參pet_name

與前面同樣,這個函數完成其任務,但打印的是一條名爲Willie的小狗的信息。至此,咱們有一隻名爲Harry的倉鼠,還有一條名爲Willie的小狗:

I have a hamster.
My hamster's name is Harry.
I have a dog.
My dog's name is Willie.

調用函數屢次是一種效率極高的工做方式。咱們只需在函數中編寫描述寵物的代碼一次,而後每當須要描述新寵物時,均可調用這個函數,並向它提供新寵物的信息。即使描述寵物的代碼增長到了10行,你依然只需使用一行調用函數的代碼,就可描述一個新寵物。

在函數中,可根據須要使用任意數量的位置實參,Python將按順序將函數調用中的實參關聯到函數定義中相應的形參。

位置實參的順序很重要

使用位置實參來調用函數時,若是實參的順序不正確,結果可能出乎意料:

def describe_pet(animal_type, pet_name):
    """顯示寵物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('harry', 'hamster')

在這個函數調用中,咱們先指定名字,再指定動物類型。因爲實參harry在前,這個值將存儲到形參animal_type中;同理,hamster將存儲到形參pet_name中。結果是咱們獲得了一個名爲Hamsterharry

I have a harry.
My harry's name is Hamster.

若是結果像上面同樣搞笑,請確認函數調用中實參的順序與函數定義中形參的順序一致。

關鍵字實參

關鍵字實參是傳遞給函數的名稱—值對。你直接在實參中將名稱和值關聯起來了,所以向函數傳遞實參時不會混淆。

關鍵字實參讓你無需考慮函數調用中的實參順序,還清楚地指出了函數調用中各個值的用途。下面來從新編寫pets.py,在其中使用關鍵字實參來調用describe_pet()

def describe_pet(animal_type, pet_name):
    """顯示寵物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(animal_type='hamster', pet_name='harry')

函數describe_pet()仍是原來那樣,但調用這個函數時,咱們向Python明確地指出了各個實參對應的形參。看到這個函數調用時,Python知道應該將實參hamsterharry分別存儲在形參animal_typepet_name中。輸出正確無誤,它指出咱們有一隻名爲Harry的倉鼠。

關鍵字實參的順序可有可無,由於Python知道各個值該存儲到哪一個形參中。下面兩個函數調用是等效的:

describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='harry', animal_type='hamster')

默認值

編寫函數時,可給每一個形參指定默認值。在調用函數中給形參提供了實參時,Python將使用指定的實參值;不然,將使用形參的默認值。所以,給形參指定默認值後,可在函數調用中省略相應的實參。使用默認值可簡化函數調用,還可清楚地指出函數的典型用法。

例如,若是你發現調用describe_pet()時,描述的大都是小狗,就可將形參animal_type的默認值設置爲dog。這樣,調用describe_pet()來描述小狗時,就可不提供這種信息:

def describe_pet(pet_name, animal_type='dog'):
    """顯示寵物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(pet_name='willie')

這裏修改了函數describe_pet()的定義,在其中給形參animal_type指定了默認值dog。這樣,調用這個函數時,若是沒有給animal_type指定值,Python將把這個形參設置爲dog

I have a dog.
My dog's name is Willie.

請注意,在這個函數的定義中,修改了形參的排列順序。因爲給animal_type指定了默認值,無需經過實參來指定動物類型,所以在函數調用中只包含一個實參——寵物的名字。然而,Python依然將這個實參視爲位置實參,所以若是函數調用中只包含寵物的名字,這個實參將關聯到函數定義中的第一個形參。這就是須要將pet_name放在形參列表開頭的緣由所在。

如今,使用這個函數的最簡單的方式是,在函數調用中只提供小狗的名字:

describe_pet('willie')

這個函數調用的輸出與前一個示例相同。只提供了一個實參——willie,這個實參將關聯到函數定義中的第一個形參——pet_name。因爲沒有給animal_type提供實參,所以Python使用其默認值dog
若是要描述的動物不是小狗,可以使用相似於下面的函數調用:

describe_pet(pet_name='harry', animal_type='hamster')

因爲顯式地給animal_type提供了實參,所以Python將忽略這個形參的默認值。

等效的函數調用

因爲可混合使用位置實參、關鍵字實參和默認值,一般有多種等效的函數調用方式。請看下
面的函數describe_pets()的定義,其中給一個形參提供了默認值:

def describe_pet(pet_name, animal_type='dog'):

基於這種定義,在任何狀況下都必須給pet_name提供實參;指定該實參時可使用位置方式,也可使用關鍵字方式。若是要描述的動物不是小狗,還必須在函數調用中給animal_type提供實參;一樣,指定該實參時可使用位置方式,也可使用關鍵字方式。

下面對這個函數的全部調用均可行:

# 一條名爲Willie的小狗
describe_pet('willie')
describe_pet(pet_name='willie')
# 一隻名爲Harry的倉鼠
describe_pet('harry', 'hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster', pet_name='harry')

這些函數調用的輸出與前面的示例相同。

避免實參錯誤

等你開始使用函數後,若是遇到實參不匹配錯誤,不要大驚小怪。你提供的實參多於或少於函數完成其工做所需的信息時,將出現實參不匹配錯誤。
例如,若是調用函數describe_pet()時沒有指定任何實參,結果將如何呢?

def describe_pet(animal_type, pet_name):
    """顯示寵物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet()

Python發現該函數調用缺乏必要的信息,而traceback指出了這一點:

Traceback (most recent call last):
 File "pets.py", line 6, in <module>
 describe_pet()
 TypeError: describe_pet() missing 2 required positional arguments: 'animal_
type' and 'pet_name'

返回值

函數並不是老是直接顯示輸出,相反,它能夠處理一些數據,並返回一個或一組值。函數返回的值被稱爲返回值。在函數中,可以使用return語句將值返回到調用函數的代碼行。返回值讓你可以將程序的大部分繁重工做移到函數中去完成,從而簡化主程序。

返回簡單值

下面來看一個函數,它接受名和姓並返回姓名:

def get_formatted_name(first_name, last_name):
    """返回的姓名"""
    full_name = first_name + ' ' + last_name
    return full_name.title()
    musician = get_formatted_name('jimi', 'hendrix')
print(musician)

函數get_formatted_name()的定義經過形參接受名和姓。它將姓和名合而爲一,在它們之間加上一個空格,並將結果存儲在變量full_name中。而後,將full_name的值轉換爲首字母大寫格式,並將結果返回到函數調用行。調用返回值的函數時,須要提供一個變量,用於存儲返回的值。

在這裏,將返回值存儲在了變量musician中。輸出是姓名:

Jimi Hendrix

讓實參變成可選的

有時候,須要讓實參變成可選的,這樣使用函數的人就只需在必要時才提供額外的信息。可以使用默認值來讓實參變成可選的。
例如,假設咱們要擴展函數get_formatted_name(),使其還處理中間名。爲此,可將其修改爲相似於下面這樣:

def get_formatted_name(first_name, middle_name, last_name):
    """返回姓名"""
    full_name = first_name + ' ' + middle_name + ' ' + last_name
    return full_name.title()
musician = get_formatted_name('john', 'lee', 'hooker')
print(musician)

只要同時提供名、中間名和姓,這個函數就能正確地運行。它根據這三部分建立一個字符串,在適當的地方加上空格,並將結果轉換爲首字母大寫格式:

John Lee Hooker

然而,並不是全部的人都有中間名,但若是你調用這個函數時只提供了名和姓,它將不能正確地運行。爲讓中間名變成可選的,可給實參middle_name指定一個默認值——空字符串,並在用戶沒有提供中間名時不使用這個實參。
爲讓get_formatted_name()在沒有提供中間名時依然可行,可給實參middle_name指定一個默認值——空字符串,並將其移到形參列表的末尾:

def get_formatted_name(first_name, last_name, middle_name=''):
 """返回姓名"""
    if middle_name:
        full_name = first_name + ' ' + middle_name + ' ' + last_name
    else:
        full_name = first_name + ' ' + last_name
    return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)

在這個示例中,姓名是根據三個可能提供的部分建立的。因爲人都有名和姓,所以在函數定義中首先列出了這兩個形參。中間名是可選的,所以在函數定義中最後列出該形參,並將其默認值設置爲空字符串。

在函數體中,咱們檢查是否提供了中間名。Python將非空字符串解讀爲True,所以若是函數調用中提供了中間名,if middle_name將爲True。若是提供了中間名,就將名、中間名和姓合併爲姓名,而後將其修改成首字母大寫格式,並返回到函數調用行。

在函數調用行,將返回的值存儲在變量musician中;而後將這個變量的值打印出來。若是沒有提供中間名,middle_name將爲空字符串,致使if測試未經過,進而執行else代碼塊:只使用名和姓來生成姓名,並將設置好格式的姓名返回給函數調用行。

在函數調用行,將返回的值存儲在變量musician中;而後將這個變量的值打印出來。調用這個函數時,若是隻想指定名和姓,調用起來將很是簡單。若是還要指定中間名,就必須確保它是最後一個實參,這樣Python才能正確地將位置實參關聯到形參。
這個修改後的版本適用於只有名和姓的人,也適用於還有中間名的人:

Jimi Hendrix
John Lee Hooker

可選值讓函數可以處理各類不一樣情形的同時,確保函數調用盡量簡單。

本篇文章沒有做業,下一篇咱們講解函數的高級用法


公衆號

相關文章
相關標籤/搜索