我们已经了解了最基本的函数,下面将要学习更多函数的特性。例如使用函数返回值,如何在不同的函数间传递不同的数据结构等。
参数缺省值
我们初次介绍函数的时候,用的是下述例子:
def thank_you(name):
# This function prints a two-line personalized thank you message.
print("nYou are doing good work, %s!" % name)
print("Thank you very much for your efforts on this project.")
thank_you('Adriana')
thank_you('Billy')
thank_you('Caroline')
上述代码中,函数都能正常工作。但是在不传入参数时,函数就会报错。如下所示:
def thank_you(name):
# This function prints a two-line personalized thank you message.
print("nYou are doing good work, %s!" % name)
print("Thank you very much for your efforts on this project.")
thank_you('Billy')
thank_you('Caroline')
thank_you()
出现这个错误是合乎情理的。函数需要一个参数来完成它的工作,没有这个参数就没办法工作。
这就引出了一个问题。有时候你想在不传参数的时候让函数执行默认的动作。你可以通过设置参数的缺省值实现这个功能。缺省值是在函数定义的时候确定的。如下所示:
def thank_you(name='everyone'):
# This function prints a two-line personalized thank you message.
# If no name is passed in, it prints a general thank you message
# to everyone.
print("nYou are doing good work, %s!" % name)
print("Thank you very much for your efforts on this project.")
thank_you('Billy')
thank_you('Caroline')
thank_you()
在函数中有多个参数,且其中一些参数的值基本不变时,使用参数缺省值是非常有帮助的。它可以帮助函数调用者只关注他们关心的参数。
位置参数
使用函数的很重要的一点就是如何向函数中传递参数。我们已经学到的都是最简单的参数传递,只有一个参数。接下来我们了解一下如何传递两个以上的参数。
我们创建一个包含 3 个参数的函数,包含一个人的名,姓和年纪。如下所示:
def describe_person(first_name, last_name, age):
# This function takes in a person's first and last name,
# and their age.
# It then prints this information out in a simple format.
print("First name: %s" % first_name.title())
print("Last name: %s" % last_name.title())
print("Age: %dn" % age)
describe_person('brian', 'kernighan', 71)
describe_person('ken', 'thompson', 70)
describe_person('adele', 'goldberg', 68)
在这个函数中,参数是 first_name , last_name , age 。它们被称为位置参数。Python 会根据参数的相对位置为它们赋值。在下面的调用语句中:
describe_person('brian', 'kernighan', 71)
我们给函数传递了 brian, kernighan, 71 三个值。Python 就会根据参数位置将 first_name 和 brian 匹配,last_name 和 kernighan 匹配,age 和 71 匹配。
这种参数传递方式是相当直观的,但是我们需要严格保证参数的相对位置。
如果我们混乱了参数的位置,就会得到一个无意义的结果或报错。如下所示:
def describe_person(first_name, last_name, age):
# This function takes in a person's first and last name,
# and their age.
# It then prints this information out in a simple format.
print("First name: %s" % first_name.title())
print("Last name: %s" % last_name.title())
print("Age: %dn" % age)
describe_person(71, 'brian', 'kernighan')
describe_person(70, 'ken', 'thompson')
describe_person(68, 'adele', 'goldberg')
这段代码中,first_name 和 71 匹配,然后调用 first_name.title() ,而整数是无法调用 title() 方法的。
关键字参数
Python 中允许使用关键字参数。所谓关键字参数就是在调用函数时,可以指定参数的名字给参数赋值。改写上述代码,示例如下:
def describe_person(first_name, last_name, age):
# This function takes in a person's first and last name,
# and their age.
# It then prints this information out in a simple format.
print("First name: %s" % first_name.title())
print("Last name: %s" % last_name.title())
print("Age: %dn" % age)
describe_person(age=71, first_name='brian', last_name='kernighan')
describe_person(age=70, first_name='ken', last_name='thompson')
describe_person(age=68, first_name='adele', last_name='goldberg')
这样就能工作了。Python 不再根据位置为参数赋值。而是通过参数名字匹配对应的参数值。这种写法可读性更高。
混合位置和关键字参数
有时候混合使用位置和关键字参数是有意义的。我们还是用上述例子,增添一个参数继续使用位置参数。如下所示:
def describe_person(first_name, last_name, age, favorite_language):
# This function takes in a person's first and last name,
# their age, and their favorite language.
# It then prints this information out in a simple format.
print("First name: %s" % first_name.title())
print("Last name: %s" % last_name.title())
print("Age: %d" % age)
print("Favorite language: %sn" % favorite_language)
describe_person('brian', 'kernighan', 71, 'C')
describe_person('ken', 'thompson', 70, 'Go')
describe_person('adele', 'goldberg', 68, 'Smalltalk')
我们假设每个人调用这个函数的时候都会提供 first_name 和 last_name。但可能不会提供其他信息。因此 first_name 和 last_name 使用位置参数,其他参数采用关键字参数的形式。如下所示:
def describe_person(first_name, last_name, age=None, favorite_language=None, died=None):
"""
This function takes in a person's first and last name, their age,
and their favorite language.
It then prints this information out in a simple format.
"""
print("First name: %s" % first_name.title())
print("Last name: %s" % last_name.title())
# Optional information:
if age:
print("Age: %d" % age)
if favorite_language:
print("Favorite language: %s" % favorite_language)
if died:
print("Died: %d" % died)
# Blank line at end.
print("n")
接受任意数量的参数
利用关键字参数我们可以灵活处理各种调用语句。然而,我们还有其他一些问题需要处理。我们考虑一个函数,接收两个数字参数,并打印数字之和。示例如下:
def adder(num_1, num_2):
# This function adds two numbers together, and prints the sum.
sum = num_1 + num_2
print("The sum of your numbers is %d." % sum)
# Let's add some numbers.
adder(1, 2)
adder(-1, 2)
adder(1, -2)
这个函数运行良好。但是如果我们传入3个参数呢,看起来这种情况也应该是可以作算术运算的。如下所示:
def adder(num_1, num_2):
# This function adds two numbers together, and prints the sum.
sum = num_1 + num_2
print("The sum of your numbers is %d." % sum)
# Let's add some numbers.
adder(1, 2, 3)
出乎意料,函数出错了。为什么呢?
这是因为无论采用什么形式的参数,函数只接受2个参数。事实上在这种情况下,函数只能恰好接受2个参数。怎么样才能解决参数个数问题呢?
接受任意长度的序列
Python 帮助我们解决了函数接受参数个数的问题。它提供了一种语法,可以让函数接受任意数量的参数。如果我们在参数列表的最后一个参数前加一个星号,这个参数就会收集调用语句的剩余参数并传入一个元组。(剩余参数是指匹配过位置参数后剩余的参数)示例如下:
def example_function(arg_1, arg_2, *arg_3):
# Let's look at the argument values.
print('narg_1:', arg_1)
print('arg_2:', arg_2)
print('arg_3:', arg_3)
example_function(1, 2)
example_function(1, 2, 3)
example_function(1, 2, 3, 4)
example_function(1, 2, 3, 4, 5)
你也可以使用 for 循环来处理剩余参数。
def example_function(arg_1, arg_2, *arg_3):
# Let's look at the argument values.
print('narg_1:', arg_1)
print('arg_2:', arg_2)
for value in arg_3:
print('arg_3 value:', value)
example_function(1, 2)
example_function(1, 2, 3)
example_function(1, 2, 3, 4)
example_function(1, 2, 3, 4, 5)
我们现在就可以重写 adder() 函数,示例如下:
def adder(num_1, num_2, *nums):
# This function adds the given numbers together,
# and prints the sum.
# Start by adding the first two numbers, which
# will always be present.
sum = num_1 + num_2
# Then add any other numbers that were sent.
for num in nums:
sum = sum + num
# Print the results.
print("The sum of your numbers is %d." % sum)
# Let's add some numbers.
adder(1, 2)
adder(1, 2, 3)
adder(1, 2, 3, 4)
接受任意数量的关键字参数
Python 也提供了一种接受任意数量的关键字参数的语法。如下所示:
def example_function(arg_1, arg_2, **kwargs):
# Let's look at the argument values.
print('narg_1:', arg_1)
print('arg_2:', arg_2)
print('arg_3:', kwargs)
example_function('a', 'b')
example_function('a', 'b', value_3='c')
example_function('a', 'b', value_3='c', value_4='d')
example_function('a', 'b', value_3='c', value_4='d', value_5='e')
上述代码中,最后一个参数前有两个星号,代表着收集调用语句中剩余的所有键值对参数。这个参数常被命名为 kwargs 。这些参数键值对被存储在一个字典中。我们可以循环字典取出参数值。如下所示:
def example_function(arg_1, arg_2, **kwargs):
# Let's look at the argument values.
print('narg_1:', arg_1)
print('arg_2:', arg_2)
for key, value in kwargs.items():
print('arg_3 value:', value)
example_function('a', 'b')
example_function('a', 'b', value_3='c')
example_function('a', 'b', value_3='c', value_4='d')
example_function('a', 'b', value_3='c', value_4='d', value_5='e')
def example_function(**kwargs):
print(type(kwargs))
for key, value in kwargs.items():
print('{}:{}'.format(key, value))
example_function(first=1, second=2, third=3)
example_function(first=1, second=2, third=3, fourth=4)
example_function(name='Valerio', surname='Maggio')
此前我们创建过一个描述人的信息的函数。但是我们只能传递有限的信息,因为参数的个数在定义时已经被限制。现在利用刚刚学习的知识,我们可以传递任意数量任意形式的信息,如下所示:
def describe_person(first_name, last_name, **kwargs):
# This function takes in a person's first and last name,
# and then an arbitrary number of keyword arguments.
# Required information:
print("First name: %s" % first_name.title())
print("Last name: %s" % last_name.title())
# Optional information:
for key in kwargs:
print("%s: %s" % (key.title(), kwargs[key]))
# Blank line at end.
print("n")
describe_person('brian', 'kernighan', favorite_language='C')
describe_person('ken', 'thompson', age=70)
describe_person('adele', 'goldberg', age=68, favorite_language='Smalltalk')
describe_person('dennis', 'ritchie', favorite_language='C', died=2011)
describe_person('guido', 'van rossum', favorite_language='Python')