Skip to content

关于参数(下)

18 / 44

可以接收一系列值的位置参数

如果你在定义参数的时候在一个位置参数(Positional Arguments)前面标注了星号*那么这个位置参数可以接收一系列值在函数内部可以对这一系列值用 for ... in ... 循环进行逐一的处理

带一个星号的参数英文名称是 “Arbitrary Positional Arguments”,姑且翻译为随意的位置参数”。

还有带两个星号的参数一会儿会讲到英文名称是 “Arbitrary Keyword Arguments”,姑且翻译为随意的关键字参数”。

有些中文书籍把 “Arbitrary Positional Arguments” 翻译成可变位置参数”。事实上在这样的地方无论怎样的中文翻译都是令人觉得非常吃力的前面的这个翻译还好了我还见过把 “Arbitrary Keyword Arguments” 翻译成武断的关键字参数 —— 我觉得这样的翻译肯定会使读者产生说不明道不白的疑惑

所以入门之后就尽量只用英文是个好策略虽然刚开始有点吃力但后面会很省心很长寿 —— 是呀少浪费时间少浪费生命其实就相当于更长寿了呀

python
def say_hi(*names):
    for name in names:
        print(f'Hi, {name}!')
say_hi()
say_hi('ann')
say_hi('mike', 'john', 'zeo')
plaintext
Hi, ann!
Hi, mike!
Hi, john!
Hi, zeo!

say_hi() 这一行没有任何输出因为你在调用函数的时候没有给它传递任何值于是在函数内部代码执行的时候name in names 的值是 False所以for 循环内部的代码没有被执行

在函数内部是把 names 这个参数当作容器处理的 —— 否则也没办法用 for ... in ... 来处理而在调用函数的时候我们是可以将一个容器传递给函数的 Arbitrary Positional Arguments —— 做法是在调用函数的时候在参数前面加上星号 *

python
def say_hi(*names):
    for name in names:
        print(f'Hi, {name}!')

names = ('mike', 'john', 'zeo')
say_hi(*names)
plaintext
Hi, mike!
Hi, john!
Hi, zeo!

实际上因为以上的 say_hi(*names) 函数内部就是把接收到的参数当作容器处理的于是在调用这个函数的时候向它传递任何容器都会被同样处理

python
def say_hi(*names):
    for name in names:
        print(f'Hi, {name}!')

a_string = 'Python'
say_hi(*a_string)

a_range = range(10)
say_hi(*a_range)

a_list = list(range(10, 0, -1))
say_hi(*a_list)

a_dictionary = {'ann':2321, 'mike':8712, 'joe': 7610}
say_hi(*a_dictionary)
plaintext
Hi, P!
Hi, y!
Hi, t!
Hi, h!
Hi, o!
Hi, n!
Hi, 0!
Hi, 1!
Hi, 2!
Hi, 3!
Hi, 4!
Hi, 5!
Hi, 6!
Hi, 7!
Hi, 8!
Hi, 9!
Hi, 10!
Hi, 9!
Hi, 8!
Hi, 7!
Hi, 6!
Hi, 5!
Hi, 4!
Hi, 3!
Hi, 2!
Hi, 1!
Hi, ann!
Hi, mike!
Hi, joe!

在定义可以接收一系列值的位置参数时,建议在函数内部为该变量命名时总是用复数因为函数内部总是需要 for 循环去迭代元组中的元素这样的时候名称的复数形式对代码的可读性很有帮助 —— 注意以上程序第二行以中文为母语的人在这个细节上常常感觉不堪重负” —— 因为中文的名词没有复数 —— 但必须习惯。(同样的道理若是用拼音命名变量就肯定是为将来挖坑……)

注意一个函数中可以接收一系列值的位置参数只能有一个并且若是还有其它位置参数存在那就必须把这个可以接收一系列值的位置参数排在所有其它位置参数之后

python
def say_hi(greeting, *names):
    for name in names:
        print(f'{greeting}, {name.capitalize()}!')

say_hi('Hello', 'mike', 'john', 'zeo')
plaintext
Hello, Mike!
Hello, John!
Hello, Zeo!

为函数的某些参数设定默认值

可以在定义函数的时候为某些参数设定默认值这些有默认值的参数又被称作关键字参数(Keyword Arguments)。从这个函数的用户角度来看这些设定了默认值的参数就成了可选参数”。

python
def say_hi(greeting, *names, capitalized=False):
    for name in names:
        if capitalized:
            name = name.capitalize()
        print(f'{greeting}, {name}!')

say_hi('Hello', 'mike', 'john', 'zeo')
say_hi('Hello', 'mike', 'john', 'zeo', capitalized=True)
plaintext
Hello, mike!
Hello, john!
Hello, zeo!
Hello, Mike!
Hello, John!
Hello, Zeo!

可以接收一系列值的关键字参数

之前我们看到可以设定一个位置参数(Positional Argument),接收一系列的值被称作 “Arbitrary Positional Argument”;

同样地我们也可以设定一个可以接收很多值的关键字参数(Arbitrary Keyword Argument)。

python
def say_hi(**names_greetings):
    for name, greeting in names_greetings.items():
        print(f'{greeting}, {name}!')

say_hi(mike='Hello', ann='Oh, my darling', john='Hi')
plaintext
Hello, mike!
Oh, my darling, ann!
Hi, john!

既然在函数内部我们在处理接收到的 Arbitrary Keyword Argument 用的是对字典的迭代方式那么在调用函数的时候也可以直接使用字典的形式

python
def say_hi(**names_greetings):
    for name, greeting in names_greetings.items():
        print(f'{greeting}, {name}!')

a_dictionary = {'mike':'Hello', 'ann':'Oh, my darling', 'john':'Hi'}
say_hi(**a_dictionary)

say_hi(**{'mike':'Hello', 'ann':'Oh, my darling', 'john':'Hi'})
plaintext
Hello, mike!
Oh, my darling, ann!
Hi, john!
Hello, mike!
Oh, my darling, ann!
Hi, john!

至于在函数内部你用什么样的迭代方式去处理这个字典是你自己的选择

python
def say_hi_2(**names_greetings):
    for name in names_greetings:
        print(f'{names_greetings[name]}, {name}!')
say_hi_2(mike='Hello', ann='Oh, my darling', john='Hi')
plaintext
Hello, mike!
Oh, my darling, ann!
Hi, john!

函数定义时各种参数的排列顺序

在定义函数的时候各种不同类型的参数应该按什么顺序摆放呢对于之前写过的 say_hi() 这个函数

python
def say_hi(greeting, *names, capitalized=False):
    for name in names:
        if capitalized:
            name = name.capitalize()
        print(f'{greeting}, {name}!')

say_hi('Hi', 'mike', 'john', 'zeo')
say_hi('Welcome', 'mike', 'john', 'zeo', capitalized=True)
plaintext
Hi, mike!
Hi, john!
Hi, zeo!
Welcome, Mike!
Welcome, John!
Welcome, Zeo!

如果你想给其中的 greeting 参数也设定个默认值怎么办写成这样好像可以

python
def say_hi(greeting='Hello', *names, capitalized=False):
    for name in names:
        if capitalized:
            name = name.capitalize()
        print(f'{greeting}, {name}!')

say_hi('Hi', 'mike', 'john', 'zeo')
say_hi('Welcome', 'mike', 'john', 'zeo', capitalized=True)
plaintext
Hi, mike!
Hi, john!
Hi, zeo!

Welcome, Mike!
Welcome, John!
Welcome, Zeo!

greeting 这个参数虽然有默认值可这个函数在被调用的时候还是必须要给出这个参数否则输出结果出乎你的想象

python
def say_hi(greeting='Hello', *names, capitalized=False):
    for name in names:
        if capitalized:
            name = name.capitalize()
        print(f'{greeting}, {name}!')

say_hi('mike', 'john', 'zeo')
plaintext
mike, john!
mike, zeo!

设定了默认值的 greeting竟然不像你想象的那样是可选参数”!所以你得这样写

python
def say_hi(*names, greeting='Hello', capitalized=False):
    for name in names:
        if capitalized:
            name = name.capitalize()
        print(f'{greeting}, {name}!')

say_hi('mike', 'john', 'zeo')
say_hi('mike', 'john', 'zeo', greeting='Hi')
plaintext
Hello, mike!
Hello, john!
Hello, zeo!
Hi, mike!
Hi, john!
Hi, zeo!

这是因为函数被调用时面对许多参数,Python 需要按照既定的规则顺序判定每个参数究竟是哪一类型的参数

Order of Arguments

  1. Positional
  2. Arbitrary Positional
  3. Keyword
  4. Arbitrary Keyword

所以即便你在定义里写成

python
def say_hi(greeting='Hello', *names, capitalized=False):
    ...

在调用该函数的时候无论你写的是

python
say_hi('Hi', 'mike', 'john', 'zeo')

还是

python
say_hi('mike', 'john', 'zeo')

Python 都会认为接收到的第一个值是 Positional Argument —— 因为在定义中greeting 被放到了 Arbitrary Positional Arguments 之前

关于参数(下) | Reborn