程序员圈子里有一句至理名言:“Don't Repeat Yourself (不要重复你自己)”。如果你发现自己正在疯狂地“复制粘贴”同一段代码,停下来!你的代码正在变得像老太婆的裹脚布一样又臭又长!今天,我们就来解锁Python里的“终极偷懒神器”——函数(Function)。学会它,你就能把复杂的代码打包成全自动的“榨汁机”,想喝果汁时,按个开关就行!
什么是函数?
在生活中,你想喝苹果汁,不需要自己去种苹果、切苹果、手动挤汁。你只需要买一台榨汁机,把苹果扔进去,按下开关,果汁就出来了。在Python里,函数就是这台榨汁机!
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。
Python函数分为内置函数和自定义函数。
内置函数是python语言本身自带的具有一定功能的函数。
如:print( ) 的作用是打印,int( )作用是转换等等。
当然程序员也可以自己创建函数,这被叫做用户自定义函数。
定义函数
deffunction(arg1, arg2):return'result''''• def (即define,定义)的含义是创建函数,也就是定义一个函数。• arg (即argument,参数)的含义是给函数创建参数。• return 即返回结果,不写的时候默认 return None'''
变量的作用域
在函数里还有一个有趣的规则:函数内部的事情,外面管不着! 也就是所谓的“局部变量”和“全局变量”。
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
用一句通俗的话说:你在公司(函数内)受的委屈(变量),不要带回自己家(函数外)!
defmy_company(): boss_tempers = "暴躁"# 这是公司内部的变量(局部变量)print(boss_tempers)my_company()# print(boss_tempers) # 如果你在外面想打印这个变量,Python会直接报错:我不认识他!# 借助关键词 global 可以在局部使用并更改全局变量boss_tempers = '心平气和'defmy_company():global boss_tempers# 局部,变量的 声明 必须在 使用 之前 boss_tempers = '暴躁'print(boss_tempers)print('前:', boss_tempers)my_company()print('后:', boss_tempers)
参数传递与类型
当你把一个变量传给函数时,Python有两种截然不同的态度,这取决于你传的是什么数据类型。
参数传递分为值传递和引用传递。
在 python 中,strings, tuples 和 numbers 是不可更改的对象,是值传递。
而 list,dict 则是可以修改的对象,是引用传递。
1. 值传递
针对不可变对象(如:数字、字符串、元组)。这就好比你把一份机密文件的复印件交给了函数。函数在里面怎么涂改、怎么撕毁,你手里的原件都毫发无损!
deftry_modify_string(s): s = s + ", 易听知识星球"# 函数试图偷偷篡改数据print(f"内部: {s}")my_string = "大家好"try_modify_string(my_string)print(f"外部: {my_string}") # 还是"大家好",没变!''' 解释原字符串:"大家好" ← 标签“my_string”执行s = s + ", 易听知识星球":新字符串:"大家好, 易听知识星球" ← 标签“s”(函数内部)原字符串:"大家好" ← 标签“my_string”(函数外部,没变)'''
2. 引用传递
针对可变对象(如:列表 List、字典 Dict)。
# 引用传递defreal_modify(param): param.append(4) # 直接在原列表上操作 param.extend([5, 6]) # 也是直接操作原列表print(f"输入: {param}")my_list = [1, 2, 3]real_modify(my_list)print(f"输出: {my_list}")''' 解释内存中: [1, 2, 3] ← 标签“my_list”和“param”都指着它执行append(4)后: [1, 2, 3, 4] ← 还是同一个列表,只是内容变了两个标签看到的都是修改后的内容!'''# ########## 坑 ###########deftry_modify(param): param = param + [4, 5, 6]print(f"输入: {param}")my_list = [1, 2, 3]try_modify(my_list)print(f"输出: {my_list}") # 输出: [1, 2, 3]'''param = param + [4, 5, 6] 干了三件事: 1. 创建新列表 [1, 2, 3, 4, 5, 6] 2. 把param标签从原列表撕下来 3. 把param标签贴到新列表上原列表 [1, 2, 3] 从头到尾都没变过,my_list标签一直指着它!'''
总结:想要通过函数修改可变对象,就用原地修改方法(append、extend、insert、remove等),别用赋值语句(=)!因为赋值语句是让参数指向新对象,而不是修改原对象。
参数类型
共分为四种参数:
- • 必备参数: 定义了几个参数,你就必须传几个,而且顺序不能乱,少一个多一个都会当场报错。
- • 关键字参数:允许函数调用时参数的顺序与声明时不一致
- • 默认参数:如果你不给它传值,它就会默默使用默认值。
- • 不定长参数:当你不知道会有多少个参数塞进来时,请祭出
*args 和 **kwargs 这两大杀器! - • *args:负责接收所有多出来的“无名”参数,打包成元组。
- • **kwargs:负责接收所有多出来的“带名字”参数,打包成字典。
另外,我们在定义函数时可以顺便指定参数的类型,在调用时如果参数类型不一致,在一些编译器内会有提示。
deffunc(a: int, b: str, c: list):pass
# --------- 1、 必备参数 ---------deffuncD(x):print("拿到了:", x)# funcD() # 报错!你没给东西!funcD('给你!') # 乖乖给值,正常运行# --------- 2、 关键字参数 ---------deffuncF(name: str, age: int):print(f'我是{name},今年{age}岁')funcF('张三', 20) # 乖乖按顺序传funcF(age=40, name='王舞') # 💥打乱顺序?没问题,指名道姓就行!# ⚠️ 致命雷区:先点名的,必须放后面!# funcF(name='赵四', 50) # 报错!带等号的关键字参数,必须放在没带等号的后面!# --------- 3、 默认参数 ---------deffuncG(name, age=18): # age=18 就是备胎print(f'我是{name},今年{age}岁')funcG('九儿', 20) # 有新欢(20),就用新欢funcG('小红') # 没传年龄,立刻启用备胎(18岁)# --------- 4、 不定长参数 ---------deffuncH(*args, **kwargs):print("多出来的无名兄弟:", args) # 是个元组print("多出来的带名家属:", kwargs) # 是个字典funcH(1, 2, 30, 40) # 全被 *args 吃了funcH(10, 20, a=1, b=2) # 10,20归args;a=1,b=2归kwargs# --------- 5、 啥都能接的“海王”函数 --------- deffuncSpe(a, b, *args, **kwargs):print("必备参数 a:", a)print("必备参数 b:", b)print("打包元组 args:", args)print("打包字典 kwargs:", kwargs)# 见证奇迹的时刻:funcSpe(1, 2, 3, 4, 5, aa=6, bb=['哈哈'], cc={'name':'张三'})# 结果:# a 拿走 1,b 拿走 2# 3,4,5 没名字,被 args 打包成 (3, 4, 5)# 后面的全带名字,被 kwargs 打包成字典!
返回值
函数返回值 return:该语句表示退出函数,在函数中可存在可不存在,当存在时向调用方返回一个表达式的值。不带参数值的return语句返回值为None。
defreal_salary():return10000# 把钱实打实地吐出来my_money = real_salary()print(f"拿去花,卡里有:{my_money}块!") # 成功拿到钱# -------- 用来结束函数 --------defborrow_money():whileTrue: answer = input("老板,借我100块钱行不?(输入 行/不行): ")if answer == "行": # 结束函数return"拿到100块,开心回家!"print("老板别这么抠嘛,再考虑考虑...")# 注意:因为上面有死循环和 return,这行代码永远、永远不可能被执行!print("这里的代码都等发霉了...")result = borrow_money()print("最终结果是:", result)
匿名函数
匿名函数,顾名思义,就是没有名字的函数。它专门用来处理那些“一句话就能搞定”的极其简单的计算。
lambda 参数 : 返回值
# 普通写法defnumbers_sum(arg1, arg2):return arg1 + arg2# 匿名函数写法numbers_sum = lambda arg1, arg2: arg1 + arg2# 调用 numbers_sum 函数print("相加后的值为 : ", numbers_sum(10, 20)) # 30# 配合内置函数当“辅助”employees = [ {"name": "张三", "salary": 3000}, {"name": "李四", "salary": 15000}, {"name": "王五", "salary": 8000}]# 告诉 sort 函数:排序的关键(key)是啥?employees.sort(key=lambda e: e['salary'])print(employees) # 结果按工资从低到高排序:# [{'name': '张三', 'salary': 3000}, {'name': '王五', 'salary': 8000}, {'name': '李四', 'salary': 15000}]
【点赞】+【推荐】你的每一次鼓励,都是小编熬夜掉头发写代码的动力!关注我,带你用最骚的姿势,学最实用的Python!下期我们讲【面向对象】...👋