23. Python的函数的参数传递

《Python编程的术与道:Python语言入门》视频课程
《Python编程的术与道:Python语言入门》视频课程链接:https://edu.csdn.net/course/detail/27845

函数的参数传递

Python 最好的特性之一是提供了极为灵活的参数处理机制。

在本节中,我们将学习有关函数的更多概念:如何在函数之间传递不同种类的数据结构。

默认参数值 (Default argument values)

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')
You are doing good work, Adriana!
Thank you very much for your efforts on this project.

You are doing good work, Billy!
Thank you very much for your efforts on this project.

You are doing good work, Caroline!
Thank you very much for your efforts on this project.

此函数如果没有传入值,则会失败:

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()
You are doing good work, Billy!
Thank you very much for your efforts on this project.

You are doing good work, Caroline!
Thank you very much for your efforts on this project.



---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-2-a796d32c586c> in <module>
      6 thank_you('Billy')
      7 thank_you('Caroline')
----> 8 thank_you()


TypeError: thank_you() missing 1 required positional argument: 'name'

如果希望即使没有传递信息,函数默认执行某些操作,可以通过在定义函数时指定默认值来执行此操作:

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()
You are doing good work, Billy!
Thank you very much for your efforts on this project.

You are doing good work, Caroline!
Thank you very much for your efforts on this project.

You are doing good work, everyone!
Thank you very much for your efforts on this project.

当你的函数中有许多参数时,这个特别有用,其中一些参数几乎总是具有相同的值。 这允许使用该函数的人仅指定其使用该函数所特有的值。

位置参数 (Positional Arguments )

我们学习使用函数的大部分内容涉及如何将值从调用语句传递给函数本身。 刚才看到的例子很简单,因为函数只需要一个参数来完成它的工作。 让我们看一个需要两个参数才能完成工作的函数。

让我们创建一个包含三个参数的简单函数。 我们创建一个函数,它接收一个人的名字和姓,然后打印出这个人信息。

下面是这个函数的一个简单实现:

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: %d\n" % age)

describe_person('ken', 'thompson', 31)
describe_person('rob', 'pike', 30)
describe_person('alan', 'kay', 28)
First name: Ken
Last name: Thompson
Age: 31

First name: Rob
Last name: Pike
Age: 30

First name: Alan
Last name: Kay
Age: 28

此函数中的参数是first_namelast_nameage。 这些称为位置参数(positional arguments ),因为Python知道按给定函数值的顺序分配每个参数的值。 在调用语句中

describe_person('ken', 'thompson', 31)

将值ken,thompson和31发送给函数。 Python将第一个值ken与第一个参数first_name相匹配。 它将第二个值thompson与第二个参数 last_name相匹配。 最后,它将第三个值31与第三个参数age相匹配。

我们必须确保以正确的顺序获取参数。

如果弄乱了顺序,会得到无意义的结果或错误:

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: %d\n" % age)

describe_person(31, 'ken', 'thompson')
describe_person(30, 'rob', 'pike')
describe_person(28, 'allan', 'kay')
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-5-3ce556e5b6be> in <module>
      7     print("Age: %d\n" % age)
      8 
----> 9 describe_person(31, 'ken', 'thompson')
     10 describe_person(30, 'rob', 'pike')
     11 describe_person(28, 'allan', 'kay')


<ipython-input-5-3ce556e5b6be> in describe_person(first_name, last_name, age)
      3     #  and their age.
      4     # It then prints this information out in a simple format.
----> 5     print("First name: %s" % first_name.title())
      6     print("Last name: %s" % last_name.title())
      7     print("Age: %d\n" % age)


AttributeError: 'int' object has no attribute 'title'

这会失败,因为Python尝试将值31与参数first_name匹配,值ken与参数 last_name匹配,值thompson与参数age匹配。 然后当它尝试打印值 first_name.title()时,它意识到它不能对整数使用title() 方法。

关键字参数 (Keyword arguments)

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: %d\n" % age)

describe_person(age=31, first_name='ken', last_name='thompson')
describe_person(age=30, first_name='rob', last_name='pike')
describe_person(age=28, first_name='alan', last_name='kay')
First name: Ken
Last name: Thompson
Age: 31

First name: Rob
Last name: Pike
Age: 30

First name: Alan
Last name: Kay
Age: 28

这是有效的,因为Python不必按位置将值与参数匹配。 它将值31与参数age匹配,因为值31明确标记为与该参数一起使用。 这种语法打字多些,但它使代码非常易读。

相较于使用位置参数赋值,使用关键字来赋值会让你的赋值语句逻辑变得更加的清晰。

带有默认参数的关键字参数函数可以很容易的添加新的行为,尤其适合向后兼容。

混合位置和关键字参数

有时候混合位置和关键字参数很有意义。 在前面的示例中,我们可以期望此函数始终采用名字和姓。 在开始混合位置和关键字参数之前,我们对一个人的描述中添加另一条信息。 让我们回过头来暂时只使用位置参数:

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: %s\n" % favorite_language)

describe_person('ken', 'thompson', 31, 'C')
describe_person('rob', 'pike', 30, 'Go')
describe_person('alan', 'kay', 28, 'Smalltalk')
First name: Ken
Last name: Thompson
Age: 31
Favorite language: C

First name: Rob
Last name: Pike
Age: 30
Favorite language: Go

First name: Alan
Last name: Kay
Age: 28
Favorite language: Smalltalk

现在开始考虑包含一些可能不适用于所有人的信息。 我们可以通过保留名字和姓的位置参数来解决这个问题,但是希望对其他参数使用关键字参数。

def describe_person(first_name, last_name, age=None, favorite_language=None, married=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 married:
        print("Married: %d" % married)
    # Blank line at end.
    print("\n")

describe_person('ken', 'thompson', favorite_language='C')
describe_person('alan', 'kay', age=28, favorite_language='Smalltalk')
describe_person('dennis', 'ritchie', favorite_language='C', married=2011)
describe_person('guido', 'van rossum', favorite_language='Python')
First name: Ken
Last name: Thompson
Favorite language: C


First name: Alan
Last name: Kay
Age: 28
Favorite language: Smalltalk


First name: Dennis
Last name: Ritchie
Favorite language: C
Married: 2011


First name: Guido
Last name: Van Rossum
Favorite language: Python

每个人都需要名字和姓,但是其他是可选的。 此代码利用Python关键字 None,它充当变量的空值。 这样,用户可以*地提供他们关心的任何额外值。 任何未接收值的参数没有显示。 Python按名称匹配这些额外值,而不是按位置匹配。 这是定义函数的一种常见且有用的方法。

接受任意数量的参数

让我们考虑一个接收两个数字的函数,并打印出两个数字的总和:

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)
The sum of your numbers is 3.
The sum of your numbers is 1.
The sum of your numbers is -1.

此函数似乎运作良好。 但是,如果将三个数字传递给它呢?

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)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-10-09e4d34bec44> in <module>
      5 
      6 # Let's add some numbers.
----> 7 adder(1, 2, 3)


TypeError: adder() takes 2 positional arguments but 3 were given

这个函数失败了,因为无论使用什么位置和关键字参数的混合,该函数只写两个接受两个参数。 实际上,以这种方式编写的函数只能使用两个参数。

接受任意长度的序列

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)
arg_1: 1
arg_2: 2
arg_3: ()

arg_1: 1
arg_2: 2
arg_3: (3,)

arg_1: 1
arg_2: 2
arg_3: (3, 4)

arg_1: 1
arg_2: 2
arg_3: (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)
arg_1: 1
arg_2: 2

arg_1: 1
arg_2: 2
arg_3 value: 3

arg_1: 1
arg_2: 2
arg_3 value: 3
arg_3 value: 4

arg_1: 1
arg_2: 2
arg_3 value: 3
arg_3 value: 4
arg_3 value: 5

现在可以重写 adder()函数来接受两个或多个参数,并打印这些数字的总和:

def adder(*nums):
    """This function adds the given numbers together and prints the sum."""
    
    s = 0 
    for num in nums:
        s = s + num
    # Print the results.
    print("The sum of your numbers is %d." % s)
    
# Let's add some numbers.
adder(1, 2, 3)
The sum of your numbers is 6.

接受任意数量的关键字参数

Python还提供了接受任意数量的关键字参数的语法。

**kwargs

**语法类似,但仅适用于关键字参数。

它将它们收集到一个新的字典中,其中参数名是键,其值是相应的字典值。

def print_arguments(**kwargs):
    print(kwargs)

print_arguments(name='Bob', age=25, job='dev')
{'name': 'Bob', 'age': 25, 'job': 'dev'}

下面的第三个参数在它前面有两个星号,它告诉Python收集调用语句中所有剩余的键值参数。 这个参数通常被称为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')
arg_1: a
arg_2: b

arg_1: a
arg_2: b
arg_3 value: c

arg_1: a
arg_2: b
arg_3 value: c
arg_3 value: d

arg_1: a
arg_2: b
arg_3 value: c
arg_3 value: d
arg_3 value: 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)
<class 'dict'>
first:1
second:2
third:3
example_function(first=1, second=2, third=3, fourth=4)
<class 'dict'>
first:1
second:2
third:3
fourth:4
example_function(name='Valerio', surname='Maggio')
<class 'dict'>
name:Valerio
surname:Maggio
上一篇:python里的输入与输出


下一篇:Dataframe 统计某一列数据出现的次数以及种类