python3 函数:可变参数、关键字参数、命名关键字参数

包含两个位置参数的函数print_str

 
  1. def print_str(first, second):

  2. print(first)

  3. print(second)

  4.  
  5. if __name__ == "__main__":

  6. print_str("hello", "world")

如果只想传一个参数去调用print_str函数,执行print_str("hello"),此时会发生什么呢?

输出结果:

TypeError: print_str() takes exactly 2 arguments (1 given)

TypeError:CPython明确告知print_str函数是需要两个参数的,而你只为print_str函数传了一个参数,如何修改print_str函数为既可以传一个参数、也可以传入两个参数去调用呢?

可传递一个参数、或者更多个参数的函数print_str

将print_str函数的最后一个参数修改为可变参数(备注:也可使用默认参数),此时再次调用:print_str("hello"),看看结果是什么?

 
  1. def print_str(first, *second):

  2. print(first)

  3. print(second)

输出结果:

  1. hello

  2. ()

发现控制台输出的结果:传入的字符串"hello"打印出来了,没有传入参数的*second则打印的是一个tuple对象的字符串表示形式"()" (注意:()代表0个元素的tuple对象)

再做一个实验,为print_str函数多传几个参数?这次传入四个参数……看看会发生什么?

    print_str("hello","one","two","three")

输出结果:

  1. hello

  2. ('one', 'two', 'three')

发现传入的第二个参数"one",第三个参数“two”,第四个参数“three”全部成为可变参数组成的元组中的元素!

所有传入的参数,按照从左到右的顺序依次被使用,最左侧的参数先由位置参数(必选参数)去使用,剩余未使用的参数则是在方法的内部自动的被组装成为一个tuple对象!!!!!

调用print_str函数时直接传入一个 *参数会发生什么呢?

  1. numbers_strings = ("1","2","3","4","5")

  2.  
  3. def print_str(first, *second):

  4. print(first)

  5. print(second)

  6.  
  7. if __name__ == "__main__":

  8. print_str(*numbers_strings) #注意这里的*numbers_strings

  9. 输出结果:

  10. 1

  11. ('2', '3', '4', '5')

此时print_str(*numbers_strings) 语句等同于 print_str("1","2","3","4","5")语句,这个*numbers_strings称为元组的解包功能(一个*字符后面紧挨着一个tuple对象),numbers_strings自身是一个tuple对象,所以它称为元组的解包

没有可变参数的函数,使用元组解包,会发生什么呢?

  1. numbers_strings = ("1","2")

  2.  
  3. def print_str(first, second):

  4. print first

  5. print second

  6.  
  7. if __name__ == "__main__":

  8. print_str(*numbers_strings)

输出结果:

  1. 1

  2.  
  3. 2

此时我们发现print_str(*numbers_string)语句等同于print_str("1","2")语句。元组解包的过程中会将每一个元素依次放入到位置参数上!

参数名称前有两个**,称作关键字参数,也称作字典参数

  1. def printStr(**anything):

  2. print(anything)

  3.  
  4. printStr(first = 5, second = 100)

{'second': 100, 'first': 5}

关键字参数允许传入0个或多个包含参数名的参数,这些含有参数名的参数也被称作关键字参数,他们会在函数的内部自动组装为一个dict对象

函数调用时使用一个字典的解包(字典对象前面需加**,两个字符),它会把dictionary中每个的键值对元素,转换为一个一个的关键字参数传到函数中

  1. def printStr(first, **dict):

  2. print(str(first) + "\n")

  3. print(dict)

  4.  
  5.  
  6. printDic = {"name": "tyson", "age":"99"}

  7.  
  8.  
  9. printStr(100, **printDic)

  10.  
  11. #等同于

  12.  
  13. printStr(100, name = "tyson", age = "99")

总结

Python语法中,当*和**符号同时出现在函数定义的参数列表中时,说明参数列表可接受任意数量的参数,它们俩个统称为可变参数

*second表示任意个(包含0个)无名参数,又称为元组参数,当函数被调用时,传入的参数会在函数中自动组装成一个tuple对象后再使用(注意:就算你传递一个元素,也会在方法内部组装成一个tuple对象)

**anything表示任意个(包含0个)关键字参数,又称为字典参数,当函数被调用时,实际传入的参数会在函数内组装成一个dict对象

注意:二者同时存在,一定需要将*second放在**anything之前

注意:二者同时存在,一定需要将*second放在**anything之前

注意:二者同时存在,一定需要将*second放在**anything之前

(重要的事情说三遍)

注意事项

1、可变参数(元组参数或者字典参数),可以传0个参数,也可以传1个参数,还可以传多个参数

2、可变参数(元组参数或者字典参数),必须定义在普通参数(也称位置参数、也称必选参数)的后面

3、*参数必须定义在**参数的前面(元组参数与字典参数同时存在,元组参数一定需要在前)

  1. def printStr(普通参数,*参数,**参数):

  2. pass

4、*参数,虽然称为元组参数,千万不要直接传入一个tuple对象进去(如果传进去一个tuple对象,那么这个tuple对象会作为在函数内组装的tuple对象中一个元素),tuple对象记得一定要使用元组解包语法,解包语法:*turple

5、**参数,虽然称作字典参数,不要传入一个字典对象进去(一个字典对象只能算一个参数,此时会报错,因为它不符合关键字参数的语法规范),字典记得也是要做解包,解包语法: **dict

  1. def jsonify(*args, **kwargs):

  2. indent = None

  3. separators = (',', ':')

  4.  
  5. if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] or current_app.debug:

  6. indent = 2

  7. separators = (', ', ': ')

  8.  
  9. if args and kwargs:

  10. raise TypeError('jsonify() behavior undefined when passed both args and kwargs')

  11. elif len(args) == 1: # single args are passed directly to dumps()

  12. data = args[0] #注意看这里:对于元组参数的使用

  13. else:

  14. data = args or kwargs

  15.  
  16. return current_app.response_class(

  17. dumps(data, indent=indent, separators=separators) + '\n',

  18. mimetype=current_app.config['JSONIFY_MIMETYPE']

  19. )

===============================================================================================

阅读目录

回到目录

可变参数

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。

我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。

定义函数为:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

调用:

print(calc(1,2)) #5
print(calc(1,2,3,4)) #30

把list或tuple的元素变成可变参数传进去:

nums = [1, 2, 3]
nums_2 = (1, 2, 3, 4, 5)
print(calc(*nums)) #14
print(calc(*nums_2)) #55

*nums表示把nums这个list的所有元素作为可变参数传进去。

回到目录

关键字参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:

person('Michael', 30) #name: Michael age: 30 other: {}

也可以传入任意个数的关键字参数:

person('Bob', 35, city='Beijing')  #name: Bob age: 35 other: {'city': 'Beijing'}
person('Adam', 45, gender='M', job='Engineer') #name: Adam age: 45 other: {'job': 'Engineer', 'gender': 'M'}

关键字参数可以扩展函数的功能。比如,在person函数里,我们保证能接收到nameage这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。

也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra) #name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra

回到目录

命名关键字参数

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收cityjob作为关键字参数。这种方式定义的函数如下:

def person(name, age, *, city, job):
    print(name, age, city, job)

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。

调用方式如下:

person('Jack', 24, city='Beijing', job='Engineer') #Jack 24 Beijing Engineer

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

命名关键字参数必须传入参数名,如果没有传入参数名,调用将报错:

person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "E:/ru/231n/exer.py", line 4, in <module>
    person('Jack', 24, 'Beijing', 'Engineer')
TypeError: person() missing 2 required keyword-only arguments: 'city' and 'job'

由于调用时缺少参数名city和job,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。

命名关键字参数可以有缺省值,从而简化调用:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)

由于命名关键字参数city具有默认值,调用时,可不传入city参数:

person('Jack', 24, job='Engineer') #Jack 24 Beijing Engineer

使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:

def person(name, age, city, job):
    # 缺少 *,city和job被视为位置参数
    pass

猜你喜欢

转载自blog.csdn.net/u012308586/article/details/107693015