Python 函数(二)
一、可变参数、不可变参数
什么是可变类型,什么又是不可变类型? 这里我们首先要了解一个东西,在计算机程序中我们定义一个变量,并对其存储一个数值。这里有两个关键概念:内存地址 和 对象数值。内存地址如0xa23c87a(举例,实际长度根据cpu位数不同而不同)为一个位置点。存储地址对应的存储块里面记录的值为变量的数值(是有长度的,跟存储是内容有关)。
1. 可变类型
即上面中对象对应的值(["H“,“E“,“L“,“L“,“O“])可以被修改且内存地址不变的时候那么,该变量为可变类型。如上面为一个列表类型,我么可以对其中下标为1的“E” 进行修改为其他字符,list1[1] = “H”,那么它的新值为[“H“,“H“,“L“,“L“,“O“];
2. 不可变类型
如果上面的对象是一个字符串类型 如“HELLO”,我们虽然可以通过下标进行访问如str[1]打印出来“E”,但是我们如果通过str[1] 进行赋值,则会报错。你可能会任务 那我可以通过str = “new str”,不是也可以进行修改吗,没错。这样也可以修改 ,但是上面提到的他的内存地址将会发生改变。所以当内存地址不变时,数值无法改变的为不可变类型。
由此可见,可变类型与不可变类型主要区别在当一个对象的内存地址不变的时候,其值可以修改的为可变类型,其值不可改变的为可变类型。
3. python中可变类型与不可变类型种类
不可变类型:
- 整型
- 浮点型
- 字符串
- 元组
可变类型:
- 列表
- 字典
- 集合
二、可变参数与不可变参数作为函数实参
这里其实和其他语言相似,按址传值,和按值传值一样的意思。
1.可变参数作为函数实参
当可变参数作为函数实参时,在函数内部对函数可变参数进行修改时,我们传入的对象值将发生改变,在函数结束后,传入的可变参数值会在函数外部同步发生改变,因为传入的参数的内存地址没有发生改变,而其存储的数据发生了改变。
2. 不可变参数作为函数实参
def is_change_val(lst):
lst += lst
list1 = ['H', 'E', 'L', 'L', 'O']
print(f"入参为:{list1}, 内存位置为:{id(list1)}") #['H', 'E', 'L', 'L', 'O']
is_change_val(list1)
print(f"执行函数后,值为{list1}, 内存地址为:{id(list1)}") #['A', 'E', 'L', 'L', 'O']
print("===============")
str1 = "happy 2023"
print(f"入参为:{str1} , 内存位置为:{id(str1)}")
is_change_val(str1)
print(f"执行函数后,值为{str1}, 内存地址为:{id(str1)}")
"""打印:
入参为:['H', 'E', 'L', 'L', 'O'], 内存位置为:2878479782144
执行函数后,值为['H', 'E', 'L', 'L', 'O', 'H', 'E', 'L', 'L', 'O'], 内存地址为:2878479782144
===============
入参为:happy 2023 , 内存位置为:2878480171824
执行函数后,值为happy 2023, 内存地址为:2878480171824
"""
注意: 我们在上面定义的函数中,运算逻辑为 lst += lst, 这种是对lst的地址中的值进行直接修改。
如果修改为lst = lst +lst,则会先计算右边计算出一个新的值,然后会将新的地址付给lst。此时lst的作用域仅为函数内部并为一个局部变量,不会影响外部传入的值。
def is_change_val(lst):
lst = lst+lst
list1 = ['H', 'E', 'L', 'L', 'O']
print(f"入参为:{list1}, 内存位置为:{id(list1)}") #['H', 'E', 'L', 'L', 'O']
is_change_val(list1)
print(f"执行函数后,值为{list1}, 内存地址为:{id(list1)}") #['A', 'E', 'L', 'L', 'O']
print("===============")
str1 = "happy 2023"
print(f"入参为:{str1} , 内存位置为:{id(str1)}")
is_change_val(str1)
print(f"执行函数后,值为{str1}, 内存地址为:{id(str1)}")
"""
入参为:['H', 'E', 'L', 'L', 'O'], 内存位置为:2629047406848
执行函数后,值为['H', 'E', 'L', 'L', 'O'], 内存地址为:2629047406848
===============
入参为:happy 2023 , 内存位置为:2629047796528
执行函数后,值为happy 2023, 内存地址为:2629047796528
"""
三、递归函数
递归是一种编程思想,主要特点为函数内部调用自己,递归函数需要有一个出口。典型场景为变量文件夹下所有文件夹及子文件夹和文件。
代码举例:计算N以内的数字累加和。
def num_sum(num):
if num == 1:
return 1
else:
return num + num_sum(num - 1)
print(num_sum(4)) #10
四、 lambda 表达式
lambda 表达式即为 函数的另一种书写方式,但仅仅局限于 原函数只有一行代码,一个返回值,结构比较简单的函数。用于缩短代码,不太用去单独定义函数。
1. lambda 语法
function1 = lambda 参数列表 : 表达式
lambda 实现 一个返回指定值的函数:
fixnum = lambda: 520
print(fixnum()) # 520
lambda 实现两数想加:
num_sum = lambda a, b : a+ b
print(num_sum(1, 4)) # 5
lanbda 定义默认参数的函数:
defarg = a , b, c=100: a+b+c
print(1, 2) # 103
三目运算使用lambda实现函数封装
fn1 = lambda a, b: a if a > b else b
print(fn1(100, 200))
list 排序中使用lambda
students = [
{'name': 'TOM', 'age': 20},
{'name': 'ROSE', 'age': 19},
{'name': 'Jack', 'age': 22}]
# 按name值降序排列
students.sort(key=lambda x: x['name'], reverse=True)
print(students)
使用不定长参数与 键值对参数
lambda *args: 表达式
lambda **kwargs: 表达式
五、 高阶函数
什么是高阶函数: 当一个函数的参数为另一个函数的时候,则这个函数为高阶函数。即有参数为函数参数时该函数就是高阶函数。这里这种用法有点和JavaScript类似,函数可以作为参数传入。java 等语言不具有这种特点。
python内置高阶函数:
1. map(fun, list)
对list中的每一个元素调用函数fun,将同样size大小的新列表作为map函数返回值返回。
举例:
list1 = [1, 2, 3, 4]
result = map(fun, list1)
print(type(result)) # <class 'map'>
print(list(result)) # [1, 4, 9, 16]
2. reduce(func, list)
reduce函数的参数有两个,他会将list中的值第一次拿 索引为 n和n+1 的传入计算,并返回一个结果x,将结果x与索引为n+2的进行计算,直到上一次func函数的结果X与索引为length-1的元素进行计算。
如计算列表数值累加:
from functools import reduce
my_list = [1, 2, 3, 4, 5]
def f(x1, x2):
return x1 + x2
result = reduce(f, my_list)
print(result) # 16
3. filter(fun, list)
filter第一个函数参数为 入参为一个 返回值为boolean类型的函数,会将list中每一个元素带入到fun中计算,返回True的元素将会被保留下来,作为新列表中的一项返回。
过滤列表中的偶数:
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def f(x):
return x % 2 == 0
result = filter(f, my_list)
print(list(result)) # [2, 4, 6, 8, 10]
4. sort用法
list.sort(func,[reverse]), sort⽤来对容器中元素进⾏排序.为list的一个内置函数。
l = ['abcdef','ghf','treh']
l.sort(key=lambda ele:len(ele))
print(l) # ['ghf', 'treh', 'abcdef']