共计 7337 个字符,预计需要花费 19 分钟才能阅读完成。
作者 | 弗拉德
起源 | 弗拉德(公众号:fulade_me)
定义函数
上面是一个打印问候语的简略函数,名为 greet_user():
def greet_user():
"""显示简略的问候语"""
print("Hello!")
greet_user()
这个示例演示了最简略的函数构造。应用关键字 def
来通知 Python 你要定义一个
函数。在这里,函数名为greet_user()
,它不须要任何信息就能实现其工作,因而括号是空的(即便如此,括号也必不可少)。最初,定义以冒号结尾。
紧跟在 def greet_user()
: 前面的所有缩进行形成了函数体。代码行print("Hello!"
) 是函数体内的惟一一行代码,greet_user()
只做一项工作:打印 Hello!。
因为这个函数不须要任何参数,因而调用它时只需输出 greet_user()
即可。和预期的一样,它打印Hello!
。
向函数传递信息
只需稍作批改,就能够让函数 greet_user()
不仅向用户显示Hello!
,还将用户的名字用作参数。
因而,可在函数定义 def greet_user()
的括号内增加 username
。通过在这里增加username
,就可让函数承受你给username
指定的任何值。当初,这个函数要求你调用它时给 username
指定一个值。调用 greet_user()
时,可将一个名字传递给它,如下所示:
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()
任意次,调用时无论传入什么样的名字,都会生成相应的输入。
实参和形参
后面定义函数 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()
函数时,咱们向它传递了实参 dog
和willie
。与第一次调用时一样,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
中。后果是咱们失去了一个名为 Hamster
的harry
:
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 晓得应该将实参 hamster
和harry
别离存储在形参 animal_type
和pet_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
可选值让函数可能解决各种不同情景的同时,确保函数调用尽可能简略。
本篇文章没有作业,下一篇咱们解说函数的高级用法