Python 极简教程(十八)函数(2)参数

我们在编写代码时,如果要调用别人写的函数,一般我们不需要关心这些函数是如何实现的,只需要关注如何使用这个函数。
那么怎么才能知道如何使用呢?也就是我们必须要知道这个函数需要哪些参数,参数都代表什么,哪些参数是必须写的,哪些是不用管的,最后关注其返回的结果如何,这样就能正确的使用该函数。

比如我们前面讲过的range函数:

range(10)
range(1,10)
range(1, 10, 2)

我们看在传参数的时候,数量不同会得到不同的结果。其实这就是 Python 在函数定义的时候提供的各种参数形式。这种形式非常灵活,且功能强大。

在 Python 中,有多种参数形式,分别是位置参数(必选参数),默认参数,可变参数和关键字参数(不同的教程叫法不太一样)。

位置参数

也叫做必选参数,也就是说在函数定义的时候声明的参数,在调用的时候就必须全部给予实参,并且必须按照参数定义的顺序赋值。

比如下例,我们都知道求圆的面积和周长必须要用到 半径 r 和圆周率 π ,现在实现一个函数,提供半径 r 和 圆周率 π,返回面积(πr2)和周长(2πr)

def circle(r, pi):
	area = pi * r ** 2
	perimeter = 2 * pi * r
	return area, perimeter

当我们调用 circle() 函数的时候,必须同时提供 r 和 π 两个参数,否则就会报错,当然多了也不行。

>>> circle(4)
TypeError: circle() missing 1 required positional argument: 'pi'

也就是说参数不能多也不能少,必须按照函数定义的参数个数依次赋值,才能正常调用该函数。

>>> circle(4, 3.14)
(50.24, 25.12)

如果顺序反了就得不到你想到的结果了!

>>> circle(3.14, 4)
(39.4384, 25.12)

如果你非要反着用(不按顺序),请使用 参数名=参数值 的形式。

>>> circle(pi=3.14, r=4)
(50.24, 25.12)

对于没有任何标识的参数,我们就称之为 位置参数

默认参数

刚才的 circle() 函数,我们在用的时候必须同时传入 r 和 π 两个参数。但是我们发现 π 也就是圆周率,一般都是固定的用两位小数 3.14。

那么我们就没必要每次调用这个函数都要输这个 π,毕竟圆周率不是谁想改就能改的。但是偶尔我们需要使用小数点后面 4 位或者 6 位以求得更精确的面积和周长。那么如何实现呢?

对于函数的参数,绝大部分情况使用固定的值,在少数情况需要改该参数的值,那么我们可以设置为默认参数

简而言之,就是给参数赋一个默认值。这样当我们没有特殊需要的时候,该参数直接用默认值,而当你有特殊需要的时候,又可以通过提供新的值来实现你的需求。而且当你没有特殊需要的时候,还可以少传一个参数,使用起来更方便。

我们来改造一下上面的 circle() 函数:

def circle(r, pi=3.14):     # 给参数赋一个默认值即可
	area = pi * r ** 2
	perimeter = 2 * pi * r
	return area, perimeter

那么我们调用改造后的函数:

# 没有特殊需要的时候
>>> circle(4)
(50.24, 25.12)

# 精度要求更高的时候
>>> circle(4, 3.14159265358)
(50.26548245728, 25.13274122864)

是不是很方便!

灵活使用默认参数,会大大增加函数调用者的体验 :】

可变参数

参数收集

在某些情况下,我们需要输入不确定数量的参数(其实一般初级编程用不上),那么根据上面我们说的参数必须按照顺序和个数传入,那么这种情况要怎么处理呢?

在 Python 中提供了参数收集的机制,在函数定义时,指定可变参数(参数收集),在函数调用的时候就可以提供任意数量的参数。

比如,我们要写一个函数,用于保存任意多的用户姓名:

def collect_names(*name):
  print('收集到的姓名:', name)

没错,就是在参数前面加个星号*,在函数内部使用这个参数即可。我们看看结果是什么?

>>> collect_names('nemo', 'nano', 'tato', 'jim', 'kid')   # 你想传多少都可以!
收集到的姓名: ('nemo', 'nano', 'tato', 'jim', 'kid')

从结果我们可以看出,通过参数收集到的任意参数,传入函数内部就变成了一个元组,元组嘛,当然可以存任意多的数据了。

当然收集到元组如何用,就看你的需求了!

除了上面的直接收集参数的形式,还有一种收集 参数名=参数值的传参形式,而通过这种方式收集到的参数在内部构成一个字典。

如下例,写一个函数,收集一个人的信息。

def person(**attr):
  print('用户的信息:', attr)

调用的结果:

>>> person(name='nemo', age=18, sex='男', height=180)
用户的信息: {'name': 'nemo', 'age': 18, 'sex': '男', 'height': 180}

收集到内部形成一个字典,然后你要操作就随你咯。比如:

def person(**attr):
  for k in attr.keys():
    print('用户的%s信息:%s' % (k, attr.get(k)))

>>> person(name='nemo', age=18, sex='男', height=180)
用户的name信息:nemo
用户的age信息:18
用户的sex信息:男
用户的height信息:180

也就是说你收集到了用户的信息后,根据你的需要从字典中提取数据并处理。

参数收集的逆向过程

其实上面讲的参数收集,在你日常编码过程中使用相对较少,反倒其逆向过程用得更多。
那什么是参数收集的逆向过程呢?

参数收集是在函数调用时,传入任意多的参数,在函数内部形式一个元组或字典。而逆向过程,是先有一个元组(或任意序列)或字典,在函数调用时传入该序列或字典。

那么这有何用处呢?可以简化函数调用,并增加函数的可读性。
首先我们看第一种参数收集的逆向过程(元组):
比如用上面的 circle 函数的例子,我们在一个数据文件中存储了多个需要求面积和周长的数据。然后提取出来后放在一个二维的元组中,我们需要调用该函数逐一运算。代码如下:

data = ((4, 3.14), (6, 3.1415), (11, 3.14))
for i in data:
  circle(i[0], i[1])

好在我们这里只有两个参数,如果参数更多一些,比如5个6个,那么你要怎么写 fun(i[0], i[1], i[2]....)编不下去了。。。急需一个更简单方便的方式,正好。。。

data = ((4, 3.14), (6, 3.1415), (11, 3.14))
for i in data:
  circle(*i)  # 在变量前加一个星号就搞定啦

我们来看一下,当 i 的值为(4, 3.14),那么这是一个元组,用星号能起什么作用呢?星号相当于拆解,把元组拆解成单个的元素,再分别按顺序赋值给 circle() 函数的各个参数。circle(*i) 等同于 circle(4, 3.14)。

同样字典形式的参数收集也可以逆向来用。这个就更有用啦。比如我们连接 mysql 数据的时候(这里我只举函数调用的例子,数据库的使用在 Python 基础学完后再深究),使用到的函数有很多的参数:

db = connect(host=127.0.0.1, port=3306, user='root', password='123456', db='happy')  # 需要的话还有参数需要赋值

那么对于这种情况,我们可以写一个字典作为数据库连接的配置:

db_config = {
  'host': '127.0.0.1',
  'port': 3306,
  'user': 'root',
  'password': '123456',
  'db': 'happy'
}

db = connect(**db_config)

这里两个星号的作用,把字典拆解为单个的 参数名=参数值 的形式分别赋值给函数的各个参数。

虽然代码看起来更多一些,但是可读性更强,维护起来也更容易些,可以把这个字典放在配置文件中维护,其他需要用到的地方直接引入这个字典即可。

关键字参数

最后还剩一个关键字参数,关键字参数在函数定义时是一种参数的限制条件。

定义为关键字参数的参数,在调用时,必须以 参数名=参数值的形式赋值,不能直接写参数值。

def person(name, age, *, sex, height):
  print('用户的姓名为:', name)
  print('用户的年龄为:', age)
  print('用户的性别为:', sex)
  print('用户的身高为:', height)

上面例子中函数参数中的星号看到了么?星号后面的参数 sexheight 就是关键字参数了。

注意星号不用赋值也不算一个参数,星号属于一个标识用来区分普通参数和关键字参数。

在函数调用时,sex 和 height 两个关键字参数,必须以 sex=‘男’ 和 height=180 这种形式赋值,否则就会报错。

>>> person('nemo', 18, '男', 180)  # 提示只需要两个位置参数,但是给了4个
TypeError: person() takes 2 positional arguments but 4 were given

>>> person('nemo', 18)  # 提示缺少两个关键字参数
TypeError: person() missing 2 required keyword-only arguments: 'sex' and 'height'

>>> person('nemo', 18, sex='男', height=180)  # 只有这样才能正确调用
用户的姓名为: nemo
用户的年龄为: 18
用户的性别为: 男
用户的身高为: 180
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值