定义函数
一个简单的函数结构:其中name为形参,传入的‘Tang’为实参。
def greet_user(name):
"""显示简单的问候语"""
print("Hello! " + name)
greet_user('Tang')
Hello! Tang
第二行代码被称为文档字符串的注释,描述了函数是做什么的。用三引号括起,Python使用它们生成有关程序中函数的文档。
传递实参
向函数传递实参的方式很多,可以使用位置实参,这要求实参的顺序与形参的顺序相同。也可以使用关键字实参,其中每个实参都有变量名和值组成。还可以使用列表和字典。
位置实参
def describe_pet(pet_type,pet_name):
"""描述宠物信息"""
print("I have a " + pet_type + ", it's name is " + pet_name)
describe_pet('dog','John')
I have a dog, its name is John
关键字实参
关键字实参是传递给函数的名称-值对。使用关键字实参可以不用考虑函数调用中实参的顺序,还清楚地指出了函数调用中各个值的用途。
def describe_pet(pet_type,pet_name):
"""描述宠物信息"""
print("I have a " + pet_type + ", it's name is " + pet_name)
describe_pet(pet_name='John',pet_type='dog')
I have a dog, its name is John
默认值
编写函数时可给每个形参指定默认值。在调用函数中给形参提供了实参时,Python将使用指定的实参值。否则将使用形参的默认值。因此给形参指定默认值后,可在函数调用中省略相应的实参。
def describe_pet(pet_name,pet_type='dog'):
"""描述宠物信息"""
print("I have a " + pet_type + ", it's name is " + pet_name)
describe_pet('John')
I have a dog, it's name is John
需要注意的是函数定义中修改了形参的顺序。由于给pet_type指定了默认值,无需通过实参来制定宠物类型,因此在函数调用中只包含一个实参——宠物的名字。然而,Python依然将这个实参视为位置实参,因此如果函数调用中只包含宠物的名字,这个实参将关联到函数定义中的第一个形参。所以需要调换参数的顺序。即使用默认值时,函数定义的形参列表中必须先列出没有默认值的形参,再列出有默认值的形参。如果在有默认值的形参后面定义了没有默认值的形参编译器会报错。
混合使用
在函数调用时可以混合使用位置实参、关键字实参和默认值,通常由很多种的函数调用方式。譬如下面的调用方式都是可以的。
def describe_pet(pet_name,pet_type='dog'):
"""描述宠物信息"""
print("I have a " + pet_type + ", it's name is " + pet_name)
describe_pet('John')
describe_pet(pet_name='John')
describe_pet('John','dog')
describe_pet(pet_name='John',pet_type='dog')
describe_pet(pet_type='dog',pet_name='John')
describe_pet('John',pet_type='dog')
但是下面的调用方式不正确,第一句问题在于给同一个形参pet_name赋了两个值,第二句问题在于位置实参不能出现在关键字实参的后面。即如果调用时混用位置实参和关键字实参那么关键字实参一定要在位置实参的后面。
# describe_pet('dog',pet_name='John')
# describe_pet(pet_name='John','dog')
返回值
Python函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。同时Python函数可以返回多个值。
def build_two_persons(name_one,age_one,name_two,age_two):
person_one = {
'name':name_one,
'age':age_one,
}
person_two = {
'name': name_two,
'age': age_two,
}
return person_one,person_two
person_one,person_two = build_two_persons('John',23,'Mike',18)
print(person_one)
print(person_two)
{'name': 'John', 'age': 23}
{'name': 'Mike', 'age': 18}
传递列表
将列表传递给函数后,函数就可对其进行修改。在函数中对列表所做的任何修改都是永久性的。
def change_list(list):
del list[0]
list = [1,2,3]
change_list(list)
print(list)
[2, 3]
禁止函数修改列表
有时我们不希望函数更改列表,为解决这个问题可向函数传递列表的副本而不是原件。这样函数所做的任何修改都只影响副本而不影响原件。切片表示法[:]创建列表的副本。
def change_list(list):
del list[0]
list = [1,2,3]
change_list(list[:])
print(list)
[1, 2, 3]
传递任意数量的实参
下面的函数只有一个形参,但不管调用语句提供了多少实参这个形参都能将它们收入囊中。
def make_pizza(*toppings):
"""打印顾客点的所有配料"""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms','green peppers','extra cheese')
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
形参名*toppings中的星号让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中,即便只收到一个实参时也是如此。
结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
使用任意数量的关键字实参
有时候需要接收任意数量的实参,但与先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键-值对——调用语句提供了多少就接受多少。譬如下面的例子创建用户简介,你知道将受到用户的相关信息但又不确定会是什么样的信息。
def build_profile(first,last,**user_info):
"""创建一个字典,其中包包含我们知道的用户的一切"""
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for key,value in user_info.items():
profile[key] = value
return profile
user_profile = build_profile('Zheng','Tang',location='Beijing',age=24)
print(user_profile)
{'first_name': 'Zheng', 'last_name': 'Tang', 'location': 'Beijing', 'age': 24}
形参**user_info中的两个星号让Python创建一个名为user_info的空字典,并将收到的所有名称-值对都封装到这个字典中。在函数中可以向访问其他字典一样访问user_info。