五种传参姿势一次讲透——从老实排队到 *args 万能收纳29.1 位置参数与关键字参数两种基本姿势def print_info(name, age, city): print(f{name}, {age}岁, 来自{city}) # 姿势1: 位置参数 —— 按顺序对应老实排队 print_info(小刚, 25, 成都) # 姿势2: 关键字参数 —— 指名道姓顺序随意 print_info(city成都, name小刚, age25) # 混用: 位置在前、关键字在后反过来报语法错误 print_info(小刚, city成都, age25)什么时刻采用关键字参数呢? 第①种情形, 倘若参数数量较多≥4个, 那么通过指名道姓的方式即可防止错位现象发生第②种情形, 要是仅仅只想给后面的某一个参数传递对应的值, 并且甘愿忽略之前带有默认值的参数下一节会继续讲到该项内容这样做。关于如何提升其可读性, 口诀如此表述: 在调用的位置呈现那关键字参数, 本质上已然自带了说明书——举个例子倘若类似(小刚, city成都)这样摆放, 能够让人一眼就明晰, 弄清楚谁到底是哪种参数。29.2 默认值参数默认值# 默认值参数必须排在普通参数后面 def make_coffee(kind, sugar2, size中杯): print(f{size}{kind}咖啡, {sugar}份糖) make_coffee(拿铁) # 拿铁不传糖和杯型 → 全用默认 make_coffee(美式, sugar0) # 只改糖 make_coffee(摩卡, 3, 大杯) # 按位置全传 # 默认值陷阱: 可变默认值列表/字典会被所有调用共享! def add_item(item, box[]): # 千万别这么写! box.append(item) return box print(add_item(苹果)) # [苹果] print(add_item(香蕉)) # [苹果, 香蕉] —— 两次调用的盒子是同一个!算作仅一次的是默认值于函数定义之际, 会在多次调用之间“记住历史”的是可变默认值、{}——此乃面试经典题目。正确的写法为, 默认值采用None, 于函数体内若box为None: box等于现开新款盒子。29.3 可变参数*args 与 **可变参数# *args: 把多余的位置参数打包成元组名字随意星号才是主角 def calc_sum(*nums): print(f收到: {nums}, 类型: {type(nums).__name__}) return sum(nums) print(calc_sum(1, 2)) # 收到 (1, 2) —— 元组 print(calc_sum(1, 2, 3, 4, 5)) # 15: 来多少收多少 # 普通参数和 *args 混搭: 前面的按位置吃, 剩下的全归 * def greet_all(hello, *names): for n in names: print(f{hello}, {n}!) greet_all(早, 小明, 小红, 小刚) # **kwargs: 把多余的关键字参数打包成字典 def show_profile(**info): print(info) # {name: 小明, age: 18, vip: True} show_profile(name小明, age18, vipTrue)把 *args 当做收银台的传送带: 无论你购买1件商品, 还是30 件商品后, 都一并滚动到带子上, 形成元组, 之后才统一结算账目。**好比快递填表: 像是“姓名等于 xx、电话等于 xx、地址等于 xx”此类“键等于值”的对应关系, 不管接到多少字段, 都会被收取收纳进一张表, 也就是字典之中。其中一项接纳排队等候的人们, 另一个收纳所填造的表单。星号具备双重人格, 于定义之处def f(*args), 呈现为“打包”态势, 此即把分散的参数汇聚成为元组的情形在调用之处f(*)呢, 则形成“解包”状态, 那便是把列表逐个拆解为单独个体的且作为参数传入的局面。同一标点符号而意味相反, 其对应场景完全依靠位置予以区分界定, 另于函数进阶章中将进一步展开其更多样的玩法表现。定义一个函数 f, 它有参数 a, 参数 b 默认值为 10, 还有可变参数 args 以及字典形式可变参数。要做的就是依次去调用 f(1) 、f(1, 2) 、f(1, 2, 3, x 4) —— 然后分别去看各参数能拿到什么样的值? 在纸上写下答案之后再去进行验证。要是这道题目弄明白了, 那么对于参数传递这块你的能力就算是达到要求了答案是: a 等于 1, b 等于 10, args 是一个空元组a 等于 1, b 等于 2, args 是一个空元组a 等于 1, b 等于 2, args 是包含 3 的元组, 字典中键 x 的值是 4。️ 本课练习练习 1: 书写具备 (name, hobby, city地球) 这样参数的函数, 以三种方式分别做一次调用: 纯粹依照位置进行调用, 纯粹凭借关键字进行调用以既有位置又有关键字的混合方式调用city 使用默认给定的值。像这样的混合调用, 比如 (小明, hobby) 的形式, 其中 name 是按照位置来确定的参数, hobby 是按照关键字来确定的参数, city 不进行传入而是使用默认值。且要注意规则为, 位置参数全都必须在处于关键字参数的前面。依照要求进行改写: 开展练习 2, 着手去写函数, 该函数要以 (base, exp 2) 这种形式来计算 base 的 exp 次方, 接着对 (3)、那个 (3, 3)、按照 (base 2, exp 10) 这种模式进行测试。按照 base 与 exp 进行某种运算, 从而去体会默认值所具有的语义, 最常见的情形是要让调用者能够省事, 而特殊的情形依旧是可以进行定制的。当 exp 的值等于 2 的时候就意有所指, 那就是平时所进行的是算平方的操作, 然而只是在偶尔的时候才会去进行算高次这种操作。构造函数 (*nums) 用以返回传入数字里的最大值, 此过程不许运用内置的 max 函数, 需通过手动比较来达成, 并且要对传入 3 个数与传入 6 个数的情况进行测试。首先, 将nums作为起始而后, 对于nums中的每一个n而言, 如果n大于某个值, 那么就将其与n进行关联。千万不要遗漏“没有参数”这种边界状况哟——可以在一开始的时候, 通过if not nums来进行None方面的防御。练习 4: 思索并且证实: print 函数缘何能够接纳任意数量的参数? 也就是说 print 函数在接收参数数量这件事情上有什么特别之处? 就是像在 print(abc) 这种表达形式下它是合法的这种情况它的签名究竟隐匿存有什么?看一看: help(print), 输出结果显示——print它是这样的存在: 分隔字符串用sep , 结束符是end\n, 并能够接受不定数量参数也就是*args , 还有省略号表示后面可能还有其他参数, 咱们一直使用的print, 从第一课开始就在用的这个家伙, 实际上是*args加上关键字默认值的组合运用方式。你一直以来都是可变参数的使用者呀, 直到现在才算知道它的确切名称了。