1.函数的参数
函数的参数可以分为位置参数(必选参数),默认参数,可变参数,关键字参数,命名关键字参数,这5种参数可以组合起来使用,除了可变参数和命名关键字参数无法混合使用,参数定义的顺序必须是:位置参数、默认参数、可变参数/命名关键字参数和关键字参数。
例子如下:

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

以下分别是默认参数,可变参数,关键字参数以及可变关键字参数的例子:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 默认参数,age 和 city 就是默认参数,而name,gender则是位置参数,也是必选参数
def enroll(name, gender, age = 6, city = 'Beijing'):
    print('name:', name,'gender:', gender,'age:', age,'city:', city)


# Test
enroll('Jack', 'B')              # Prints "name: Jack gender: B age: 6 city: Beijing"
enroll('Tom', 'A',age = 25)      # Prints "name: Tom gender: A age: 25 city: Beijing"

# 可变参数
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum += n * n
    return sum

# Test
print(calc(1,2,3))  # Prints "14"
nums = [1,2,3]
# Python 允许在list或tuple前添加*,把list或tuple的元素变成可变参数传进去
print(calc(*nums))  # Prints "14"


# 关键字参数,关键字参数kw
def person(name, age, **kw):
    print('name:', name, 'age:', age,'other:',kw)

# Test
person('Bob', 35)   # Prints "name: Bob age: 35 other: {}"
person('Adam', 25, city = 'Beijing')    # Prints "name: Adam age: 25 other: {'city': 'Beijing'}"
extra = {'city': 'Beijing', 'job': 'Engineer'}
# 可以在dict前加**将dictionary中的元素传入函数的**kw中 
# 作为关键字参数的dict中的key值必须是string
person('Jack', 24 , **extra)    # Prints "name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}"

# 命名关键字参数,可以限制关键字参数的名字
def person1(name, age, *, city, job):
    print(name, age, city, job)

# Test
# 命名关键字参数必须传入参数名,否则会视为位置参数
person1('Jack', 24, city ='Beijing', job='Engineer') # Prints "Jack 24 Beijing Engineer"

默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
要注意定义可变参数和关键字参数的语法:
*args是可变参数,args接收的是一个tuple;
**kw是关键字参数,kw接收的是一个dict。
以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过args传入:func((1, 2, 3));
关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过kw传入:*func({‘a’: 1, ‘b’: 2})*。
使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数不要忘了写分隔符*,否则定义的将是位置参数。