14 函数参数

函数参数

1 形参与实参简介

形参指的是函数定义阶段的函数名后小括号中的变量(形式上的参数)。

实参指的是函数调用阶段传递给函数的实际的值。

形参相当于变量名,实参相当于变量值。
形参与实参的关系:

  1. 在函数调用阶段,实参被绑定给形参;
  2. 形参与实参的绑定关系只能存在于函数体内部,在调用时生效,在调用结束后解除。
def func(a, b):
	pass

# 形式1
func(1, 2)

# 形式2
a = 1
b = 2
func(a, b)

# 形式3
func(int(a), b)

2 形参与实参的具体使用

2.1 位置参数

按照从左到右的顺序依次定义的参数称为位置参数,包括位置形参和位置实参。
位置形参
处于函数定义阶段
特点:
位置形参必须被传值。
位置实参
处于函数调用阶段
特点:
按照从左到右的顺序依次传入的值,且传值的数量和顺序必须与位置形参一致。

2.2 关键字参数(实参)

在函数调用阶段,按照 key=value的形式传入的值。
特点:
指名道姓地给某个形参传值,可以不参照形参的顺序。

2.3 位置实参与关键字实参混合使用
  1. 位置实参必须放在关键字实参前面;
  2. 不能对同一个形参重复传值。
def func(x, y):
	pass

func(1, y=2)

func(x=1, 2)  # 报错 
func(1, x=1, y=2)  # 报错 相当于对形参x传两次值。
2.3 默认参数(形参)

在函数定义阶段,就已经被赋值的形参称为默认参数。
特点:
在定义阶段已经为默认形参赋值,在调用阶段可以不需要为默认形参赋值。

2.4 位置形参与默认形参混合使用
  1. 位置形参必须在默认形参之前;
  2. 默认形参的值是在函数定义阶段被赋值的,准确地说,被赋予的是值的内存地址;
  3. 默认值可以被指定为任意类型,但不推荐被指定为可变数据类型。
    原因:函数的理想状态是被设计成根据输入值可以预知执行结果的状态,如果默认值被指定为可变数据类型,则意味着在函数定义和调用阶段外可以去修改函数的执行结果,这是不被推荐的。
num = 12
def func(x, y=num):
	print(y)

num = 123
func(1)  # 12

上面的例子中在函数定义阶段默认形参y被赋值,即形参y存储了num的内存地址,指向了存储值12的内存空间,之后修改变量num并不影响形参y。

lst = [12]
def func(x, y=lst):
	print(y)

lst.append(123)
func(1)  # [12, 123]

上面的例子中在函数定义阶段默认形参y存储了lst的内存地址,指向了存储列表的内存空间,列表是可变数据类型。变量lst和形参y指向的内存空间中存储的是元素的内存地址。当通过变量lst修改列表时,内存地址不会发生变化,因此形参y可以感知到列表的变化。

改进

def func(x, lst=None):  # 保证形参均为不可变数据类型
	if lst is None:  # 在函数内部将参数初始化为列表
		lst = []

lst1 = [1, 2, 3]
func(1, lst1)

3 可变长度参数

在调用函数时传入的实参个数不固定,实参个数大于形参个数。
实参的作用是给形参传值,这意味着需要一种形参来接受多余的实参,包括位置实参和关键字实参。

3.1 用于形参
  1. 用来接收多余的位置实参
* + 形参名(args)

多余的位置实参被 * 保存为元组,然后将元组赋值给 * 后面的变量。

def add(start, *args):
	res = start
	for each_arg in args:
		res += each_arg
	return res

print(add(0, 1, 4, 5, 22, 666))  # 698
  1. 用来接收多余的关键字实参
** + 形参名(kwargs)

多余的关键字实参被 ** 保存为字典,然后将字典赋值给 ** 后面的变量 (kwargs)。

3.2 用于实参

实参前带 *,意味着先将 * 后面的参数打散,再按顺序传递给位置实参。
实参前带 **,意味着先将 ** 后面的参数打散,再传递给关键字实参。

def func(a, b, c):
	print(a, b, c)

func([1, 2, 3])  # 报错,形参个数与实参个数不一致
func(*[1, 2, 3])

str = 'abc'
func(*str)  # a b c
def func(a, b, c):
	print(a, b, c)

dic = {'a': 1, 'b': 2, 'c': 3}
func(*dic)  # a b c key
func(**dic)  # 1 2 3 key=value
3.3 混合

*args 必须位于 **kwargs 之前

def index(x, y, z):
	print(x, y, z)

def wrapper(*args, **kwargs):  # 形参带*/**,用于接收多余的实参
    index(*args, **kwargs)  # 实参带*/**,将接受到的实参打散,再分配给对应的形参

wrapper(1, 2, 3)  # 1 2 3
wrapper(y=2, z=3, x=1)  # 1 2 3

wrapper(1, z=3, y=2)  # 1 2 3 
内部相当于
=> wrapper(*(1, ), **{'y': 2, 'z': 3})
=> index(*(1, ), **{'y': 2, 'z': 3}) 
=> index(1, y=2, z=3)

wrapper()将接收到的参数原封不动地交给了其内部函数index(),因此为wrapper()传递的参数格式(位置,数量,关键字等)必须遵循其内部函数index()。

修改内部函数index,为其增加新的形参,此时外部函数wrapper无需修改。

def index(x, y, z, w):
	print(x, y, z, w)

def wrapper(*args, **kwargs):
    index(*args, **kwargs)

wrapper(1, 2, 3, 4)  # 1 2 3 4
wrapper(w=4, y=2, z=3, x=1)  # 1 2 3 4
wrapper(1, z=3, w=4, y=2)  # 1 2 3 4

4 练习

4.1 函数1

用户传入修改的文件名和要修改的内容,执行函数,完成修改操作。

def modify(filepath, raw_txt, new_txt):
    """
    用于修改文件
    :param filepath: 待修改的文件路径
    :param raw_txt: 待修改的字符串
    :param new_txt: 新字符串
    :return:
    """
    with open(filepath, mode='rt', encoding='utf-8') as f1:
        old_txt = f1.read()
    new_txt = old_txt.replace(raw_txt, new_txt)
    with open(filepath, mode='wt', encoding='utf-8') as f2:
        f2.write(new_txt)
4.2 函数2

统计传入字符串中【数字】、【字母】、【空格】以及 【其它】的个数

def count_str(str):
    """
    计算传入字符串中【数字】、【字母】、【空格】以及 【其它】的个数。
    :param str: 待统计的字符串
    :return:
    """
    if len(str) == 0:
        print('输入字符串为空。')
        return
    count_lst = ['【数字】', '【字母】', '【空格】', '【其它】']
    count_dict = dict.fromkeys(count_lst, 0)
    for each_str in str:
        if each_str.isdigit():
            count_dict['【数字】'] += 1
        elif each_str.isalpha():
            count_dict['【字母】'] += 1
        elif each_str == ' ':  # 这里不能使用isspace(), isspace()会判断空格、制表符和换行等
            count_dict['【空格】'] += 1
        else:
            count_dict['【其它】'] += 1
    res = ''
    for each_key in count_dict:
        res += '{key}的数量为{value}\n'.format(key=each_key, value=count_dict[each_key])
    print(res)
4.3 函数3

判断用户传入的对象(字符串、列表、元组)长度是否大于5。

def check_len(obj):
    """
    判断用户传入的对象(字符串、列表、元组)长度是否大于5
    :param obj: 用户传入的对象(字符串、列表、元组)
    :return: True-长度大于5
             False-长度不大于5
    """
    if len(obj) > 5:
        print('传入的{}的长度大于5'.format(type(obj)))
        return True
    else:
        print('传入的{}的长度不大于5'.format(type(obj)))
        return False
4.4 函数4

检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

def get_first_two(str):
    """
    检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
    :param str: 待处理的字符串
    :return: 处理后的字符串
    """
    if len(str) > 2:
        str = str[:2]
    return str
4.5 函数5

检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。

def get_odd_ele(obj):
    """
    检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者
    :param obj: 待处理的列表或元组
    :return: 新列表
    """
    res = list(obj)
    return res[1::2]
4.6 函数6

检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新字典返回给调用者。
dic = {“k1”: “v1v1”, “k2”: [11, 22, 33, 44]}
PS: 字典中的value只能是字符串或列表

def get_first_two(dic):
    """
    检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新字典返回给调用者。
    :param dic: 待处理的字典
    :return: 新字典
    """
    for each_key, each_value in dic.items():
        if len(each_value) > 2:
            dic[each_key] = each_value[:2]
    return dic
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值