python手把手50天就业(七) 函数lambda 拆包

工程师们大家好,配套免费视频(平时上班周末录制)

在实际生活中,一家做汽车的工厂。
要完成一个完整的汽车,需要很多步骤,比如组装发动机,组装轮胎,喷漆等等
我们可以看到,这些工厂都会把这些各种功能拆分为单独的车间,有很多好处,
比如:方便管理,避免交叉(一交叉就容易乱),易于新员工上手(你刚入行,只是面对轮胎比你面对整个车压力要小很多)...那么在程序中其实也一样,一个系统,会包含很多的功能,我们也应该借鉴现实生活的例子,把这些功能单独的分开。

1.函数

函数:就是具有某项功能作用的代码集合。

首先定义函数:先从概念理解 下面在学习格式
函数一:{组装发动机(30行代码)
}
函数二:{组装轮胎(40行代码)
}
函数三:{喷漆(50行代码)
}然后组装一个车:
调用函数一: 完成发动机
调用函数二: 完成轮胎
调用函数三: 完成喷漆
最后完整的车出厂
。。。。。。好处:
1.重用:比如喷漆,不仅仅是可以给汽车,还有很多东西都需要喷漆,把喷漆独立出来,在其他地方使用的时候就可以直接调用函数3
(因为它是一个函数,是一个整体,你写在一起就没法单独调出来)
2.安全:如果我写在一起,你想要我喷漆的代码,因为我没有把他独立出来不得不把所有代码都给你,那么暴露越多越危险
3.可维护性强:喷漆出了问题,我找函数3 50行代码,轮胎出问题我找函数二。。。如果写在一起我面对的就是120行代码,
然后去找到出错的。肯定工作量更大,我还得区分代码
4.易上手:对新入职的员工,我让你改下喷漆的代码,你只需要看函数三,
。。。。。

在python中函数需要先定义,才能使用。如同上面,需要有函数一二三,才能去调用

格式:

def 函数名(参数):代码块代码块return xxxdef是关键字,固定写法
注意代码块缩进格式

1.1函数名

满足前面说的标识符规则,尽量见名知意:

1.由数字、字⺟、下划线组成
2.不能数字开头
3.不能使⽤内置关键字
4.严格区分⼤⼩写

1.2参数/拆包

函数是为了完成功能,比如上面调用函数三可以喷漆,你调用我函数三的时候应该给我一个车身,我才知道喷在哪里,

也就是调用函数的时候,需要给函数什么,这就是参。当然根据功能的不同,参数可以没有,可以有很多

没有参数的函数:

def aaa():print('我是一个没有参数的函数')print('调用我可以完成一个特定的功能')# 调用aaa函数
aaa()

位置参数:

def aaa(name, age):print('我是一个有两个参数的函数')print(f'接收到参数name:{name},参数age:{age}')# 调用aaa函数 根据位置会直接把张三给到name,10给到age
aaa('张三',10)# 注意:传递和定义参数的顺序及个数必须⼀致。

关键字参数:

def aaa(name, age):print('我是一个有两个参数的函数')print(f'接收到参数name:{name},参数age:{age}')# 调用aaa函数 如果根据参数名字来传递参数 那么久可以不用遵守位置
aaa(age=10, name='张三')  # 指定了哪个值给哪个参数

缺省参数:

def aaa(name, age=10):print('我是一个有两个参数的函数')print(f'接收到参数name:{name},参数age:{age}')# 调用aaa函数 如果根据参数名字来传递参数 那么久可以不用遵守位置
aaa(name='张三')  # 不传递age参数 那么age就采用默认的值10aaa(name='张三', age=5)  # 传递了参数了5 就会覆盖掉10

也可以混用:

def aaa(name, address, age=10):print('我是一个有两个参数的函数')print(f'接收到参数name:{name},参数age:{age},地址是:{address}')# name采用位置匹配 第一个匹配第一个 address采用名字匹配 age采用默认值
aaa('张三', address='成都')

不定长参数:

不定⻓参数也叫可变参数。⽤于不确定调⽤的时候会传递多少个参数(不传参也可以)的场景

def aaa(*args):print(args)  # 传递的张三跟10 会被args装为一个元组 ('张三', 10)print(args[0])  # 通过元组的取值可以得到张三aaa('张三', 10)# 也可以混用
def bbb(name, *args):print(f'获得参数name:{name}')print(args) # (10, 20) 因为张三匹配了第一个namebbb('张三', 10, 20) # 不能包含关键字 
# bbb('张三', 10, age = 20) TypeError: bbb() got an unexpected keyword argument 'age'

包含关键字的不定长参数:

def aaa(**kwargs):print(kwargs)  # 传递的参数会形成一个字典{'age': 10, 'name': '张三', 'address': '成都'}print(type(kwargs))  # print(kwargs['name'])  # 能获得里面的值 张三print(kwargs.get('name'))  # 最好这样写 没有name不会报错aaa(age=10, name='张三', address='成都')# 也可以混用
def bbb(name, *args, **kwargs):print(name)  # 张三print(args)  # (10, 25, 30)print(kwargs)  # {'age': 10, 'address': '成都'}bbb('张三', 10, 25, 30, age=10, address='成都')

*解包:

def aaa(name, age, address):print(name)print(age)print(address)# 先定义一个元组
my_args = ('张三', 10, '成都')
# 在调用的时候直接传递元组,那么aaa参数会以为你只传递了一个参数
# 会把my_args赋值给name 导致后面两个参数没值就会报错
# 因为python的变量 类型由等号后面推出来的 所以定义的时候不知道name是什么类型
#  aaa(my_args) 报错 TypeError: aaa() missing 2 required positional arguments: 'age' and 'address'
aaa(*my_args)  # 这样写 表示解包这个元组 元组三个值正好对应 aaa方法的三个参数,相当于aaa('张三',10,'成都')

解包**

def aaa(name, age, address):print(name)print(age)print(address)# 定义一个字典dict
dict1 = {'name': '张三', 'age': 10, 'address': '成都'}
# aaa(dict1) 不能这样写 这样的话就把dict1作为一个参数了给了name
aaa(**dict1)  # 这样写就会解包 相当于 aaa(name='张三',age=10,address='成都')

*号拆包其他用法

a, b, *c = 1, 2, 3, 4
print(a)
print(b)
print(c)  # [ 3, 4] 把匹配剩下的直接转成一个lista, *b, c = 1, 2, 3, 4
print(a)
print(b)  # [2, 3]
print(c)# 以后在字符串截取的时候可以用
a, b, *c = '天青色等烟雨'
print(a)  # 天
print(b)  # 青
print(c)  # ['色', '等', '烟', '雨']a, b = 1, 2  # 其实这也是一个解包的过程 因为后面其实是一个元组
print(a)
print(b)# 字典只能得到key
a, b = {'name': '张三', 'age': 10}
print(a)
print(b)list1 = [1, 2, 3]
list2 = range(3, 6)
# 合并两个列表  不能用+号 因为list不能直接加range
list3 = [*list1, *list2]
print(list3)  # [1, 2, 3, 3, 4, 5]a = {"a": 1, "b": 2}
b = {"c": 3, "d": 4}
# 合并两个字典
c = {**a, **b}
print(c)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}# 利用拆包交换两个变量的值
a, b = 1, 2
a, b = b, a
print(a)
print(b)# 自动解包支持一切可迭代对象

1.3引用传递

可变类型:

def aaa(arg):print(arg)  # [1, 2, 3] print(f'arg的地址值:{id(arg)}')  # arg的地址值:1961858261512arg[0] = 5  # 修改arg的值 会影响到list1list1 = [1, 2, 3]
print(list1)  # [1, 2, 3]
print(f'list1的地址值(引用值):{id(list1)}')  # list1的地址值(引用值):1961858261512
# 将list1作为参数传递到aaa方法,其实是传递的list1的地址值
aaa(list1)print('------在方法aaa中修改了值后-----')
# 也就是把list1的地址值给了arg 所以arg跟list1的地址相同
# 那么修改arg就是在他们相同的地址修改 所以list1也会改变
print(list1)  # [5, 2, 3]
print(id(list1))  # 1961858261512# 因为list是可变类型

不可变类型:

def aaa(arg):print(arg)  # abcprint(f'arg的地址值:{id(arg)}')  # arg的地址值:2194960348864# 修改arg的值不会影响到外面 因为arg类型为字符串# 字符串是不可变类型,当你一个新值得时候 它宁愿新建一个字符串# 也就是调用方法的时候 把str1的地址给了arg 然后又把bbc的地址给了arg# 但是不影响str1arg = 'bbc'print(arg)  # bbcprint(f'arg的地址值:{id(arg)}')  # arg的地址值:2194960371816str1 = 'abc'
print(str1)  # abc
print(id(str1))  # 2194960348864
aaa(str1)
print(str1)  # 还是abc
print(id(str1))  # 2194960348864

总结:

可变类型 : 列表,字典,集合
不可变类型:整型,浮点型,字符串,元组

1.4变量作用域

局部变量:所谓局部变量是定义在函数体内部的变量,即只在函数体内部⽣效

比如:

def abc():num = 10  # num定义在abc内部 属于当前abc方法的局部变量 只能在abc内部访问到print(num)print(num)  # 这里会报错 无法访问

全局变量

num = 10  # 把num定义在这里 就是全局变量 在方法内部跟外面都能访问def abc():print(num)print(num)  # 这里也能访问

global关键字

num = 10  # 把num定义在这里 就是全局变量 在方法内部跟外面都能访问def abc():# 1.假如我希望调用abc的时候 这个num的改变影响到外面的改变global num  # 表示引用全局变量numnum = 20  # 这里定义了局部变量print(num)  # 这里打印按照就近原则 打印是20def bbc():print(f'前面abc改变了全局的值导致这里访问num也会改变:{num}')abc()
# 2.当假如global后就是20了
print(num)  # 没有加global这里访问的是外面的num 10
bbc()
# 先不加global 再加上global查看

1.5函数返回值

def abc():print('abc方法被调用了')return 'hello abc'result = abc()
print(f'调用abc方法后获得返回值:{result}')
# 也可以写多个return 根据逻辑来返回
def abc(age):print('abc方法被调用了')if age > 10:return '传入的年龄大于10岁'else:return '传入的年龄小于等于10岁'result = abc(20)
print(f'得到abc方法的返回值:{result}')
# 当然也可以返回其他类型的值 比如元组
def abc():a = 10b = 20return a, bresult = abc()
print(f'abc方法的返回值:{result}')
# 也可以拆分
a, b = abc()
print(a)
print(b)

2.高阶函数/lambda表达式

不仅可以把列表、整数、小数等赋值给变量,也可以把方法赋值给变量

def abc():print('我是abc方法')# 这样就是调用abc方法 并把返回值赋值给f
# f = abc()
# 这样就是把abc这个方法的地址值,赋值给了f
f = abc
# 那么f 就是个方法,我们就可以调用f方法了
f()

那么一个变量,也可能是个方法了

def abc(x,y) 中参数x或者y不仅可以是数据类型,也有可能是方法咯

于是我们就把一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

比如:

def aa(x):return x * 2f = aa  # 把aa方法赋值给f变量# 这里的第三个参数就是一个方法了 代表了aa方法
def cc(x, y, f):return f(x) + f(y)result = cc(1, 2, f)
print(result)  # 得到的结果就是6# 这里cc方法接受的第三个参数是一个方法 就称cc为高阶函数

map

map(func, lst),将传⼊的函数变量func作⽤到lst变量的每个元素中,并将结果组成新的列表(Python2)/ 迭代器(Python3)返回。

list1 = [1, 2, 3, 4]def f(x):return x ** 2# 将list1 的每个元素都用f方法加工得到返回值 一个map
result = map(f, list1)
print(result)  # 
print(list(result))  # [1, 4, 9, 16] 强转为list集合
print(list1)  # 原来的list不变

这里我们想用一下内置的map方法就不得不去定义一个函数f,如果这个f方法在其他地方没用的话,感觉就没必要定方法

那么这里就可以用匿名函数来实现,就是lambda表达式,修改上面的代码

list1 = [1, 2, 3, 4]result = map(lambda x: x ** 2, list1)
print(result)
print(list(result))
print(list1)# 也能达到与上面相同的效果
'''
lambda x: x ** 2 就是一个匿名函数
lambda:是关键字固定写法
x:是函数的参数 其实就是list1的每个值 参数的写法跟方法一模一样 因为lambda只是个匿名函数 也是函数
x**2:是函数的返回值
'''

reduce

reduce(func,lst),其中func必须有两个参数。每次func计算的结果继续和序列的下⼀个元素做累积计 算。

注意:reduce()传⼊的参数func必须接收2个参数

import functools  # 版本升级后 使用reduce需要引入这个list1 = [1, 2, 3, 4]# 需要两个参数
def f(x, y):return x + y# 得到result是10
# reduce是把元素1 元素2 放入函数f
# 在把得到的结果跟元素3放入f 以此类推
result = functools.reduce(f, list1)
print(result)# 也可以用lambda表达式
reduce = functools.reduce(lambda x, y: x + y, list1)
print(reduce)  # 结果一样 这里x,y就是两个参数了 

filter

filter(func, lst)函数⽤于过滤序列, 过滤掉不符合条件的元素, 返回⼀个 filter 对象。如果要转换为列表, 可以使⽤ list() 来转换。

list1 = [1, 2, 3, 4]
result = filter(lambda x: x > 1, list1)
print(result)  # 对象
print(list(result))  # [2, 3, 4] 强转为list
print(list1)  # 原来的集合不会改变

sorted

array = [{"age": 20, "name": "a"}, {"age": 20, "name": "b"}, {"age": 10, "name": "c"}]'''
sorted方法三个参数
sorted(iterable, key=None, reverse=False) 
iterable:表示要排序的序列 比如列表
key:表示自定义方式 可以省略
reverse=True 表示降序 可以省略  默认升序 
'''
# 按照每组元素的age 升序  x参数代表array列表的每一个元素
l = sorted(array, key=lambda x: x['age'])
# [{'age': 10, 'name': 'c'}, {'age': 20, 'name': 'a'}, {'age': 20, 'name': 'b'}]
print(l)
# 原来数组不变
print(array)# 按照每组元素的age 升序,年龄相同按照名字降序
# [{'age': 10, 'name': 'c'}, {'age': 20, 'name': 'b'}, {'age': 20, 'name': 'a'}]
# 注意下面加了个负号
sorted1 = sorted(array, key=lambda x: (-x['age'], x['name']), reverse=True)
print(sorted1)


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部