Python 函数全解+闭坑指南,一篇就够
itomcoil 2025-03-29 18:46 8 浏览
引言
学完了python的基础数据类型,也算入门了,接下来就是python中最重要的概念之一:函数(function)。大家都知道python是面向对象的编程语言,语法简单,上手容易,关键是新人也不用太纠结面向对象这个概念,仅仅会用函数也可以帮助大家解决很多的问题,接下来我们就开启函数介绍之旅。
在 Python 编程世界里,函数可是极为关键的存在。今天,就让我们跟随小白和专家的对话,一起深入了解 Python 函数的奥秘。
小白(抬头仰望):专家专家,我知道 Python 里函数很重要,可函数到底是啥呀?
专家(低头沉思):简单来说,函数就是把一段代码封装起来,方便复用。你可以把它想象成一个神奇的小盒子,输入一些东西,经过处理后输出结果。比如我们常见的print()函数,输入要打印的内容,它就会在屏幕上输出。
小白(略显骄傲):经过学习,我写了一个简单的函数,实现了读取txt文件内容的功能,省了很多事呢。
#读取文件内容,循环打印每行的内容
def opentxt(file):
f = open(file,'r',encoding='utf8')
content = f.readlines()
for i in content:
print(i)
专家(竖起大拇指):嗯,别小看一个函数,能解决大问题。
函数基础四重奏
1. 函数的定义
# 标准创建格式
def 函数名称(参数):
函数体
return 返回值 or(yield 返回值)
- 参数:参数为非必须;如果需要传参,参数可以有多种类型:默认参数,位置参数,关键字参数,不定长参数等
- return语句可不添加,默认返回None; 执行到return语句,函数返回并结束执行。
- yield语句定义之后函数为生成器,可以参考之前文章python生成器介绍
2. 函数的调用
# 正确调用
函数名() #调用必须加括号,括号填参数或者不填参数
# 错误调用
函数名 #不加括号是无法调用的
3. 函数参数介绍
函数配置了定长参数(有明确的参数个数)
- 函数执行时必须传参,否则报错
#函数带一个参数
def sum_num(numlist):
print(f'值汇总结果:{sum(numlist)}')
#不传参数 执行函数会报错
sum_num()
#报错如下
Traceback (most recent call last):
File "/est.py", line 6, in
sum_num()
TypeError: sum_num() missing 1 required positional argument: 'numlist'
- 参数传多了会提示多传了参数
sum_num(1,2)
#报错如下
Traceback (most recent call last):
File "/test.py", line 5, in
sum_num(1,2)
TypeError: sum_num() takes 1 positional argument but 2 were given
- 位置参数:指函数在传递参数时有明确的前后位置关系,如果顺序错误可能会导致程序异常,所以大家写代码时一定要注意。
#函数有两个参数a和b
def division_twonum(a,b):
print(f'a/b:{a/b}')
#执行以下函数 传参0和5 执行pass
division_twonum(0,5)
#如果a和b搞错了顺序,会报错
division_twonum(5,0)
报错如下:分母不能为0
Traceback (most recent call last):
File "/test.py", line 13, in
division_twonum(5,0)
File "/test.py", line 10, in division_twonum
print(f'a/b:{a/b}')
ZeroDivisionError: division by zero
- 关键字参数:传入参数为key=value的形式,不关心前后位置关系。
比如上面的例子,执行以下函数,结果都是一样的。函数不关心a和b的位置。
division_twonum(a=0,b=5)
division_twonum(b=5,a=0)
- 默认值参数:在函数定义时指定默认值,指定默认值的参数可传可不传,不传递直接使用默认值。
def division_twonum(a,b=2):
print(f'a/b:{a/b}')
#参数b不传递 使用默认值
division_twonum(5)
打印结果
a/b:2.5
函数的不定长参数
- 参数定义包含*args,表示可以传入多个位置参数,被args接收为元组类型。
def sum_num(*nums):
print(f'nums : {nums}, type(nums)为{type(nums)}')
print(f'值汇总结果:{sum(nums)}')
#传入1到5 数字 执行函数
sum_num(1,2,3,4,5)
结果如下
nums : (1, 2, 3, 4, 5), type(nums)为
值汇总结果:15
- 参数定义包含**args,表示可以传入多个key=value 的关键字参数,被args接收为字典类型。
def sum_num(**nums):
print(f'nums : {nums}, type(nums)为{type(nums)}')
print(f'值汇总结果:{sum(nums.values())}')
#传入key=value的关键字参数 执行函数
sum_num(a=1,b=2,c=3)
结果如下
nums : {'a': 1, 'b': 2, 'c': 3}, type(nums)为
值汇总结果:6
- *args和 **args一起使用时,*args要放在前面。
def sum_num(*nums,**keys):
print(f'nums : {nums}, type(nums)为{type(nums)}')
print(f'keys : {keys}, type(keys)为{type(keys)}')
#传入key=value的关键字参数 执行函数
sum_num(1,2,3,4,5,a=1,b=2,c=3)
#结果
nums : (1, 2, 3, 4, 5), type(nums)为
keys : {'a': 1, 'b': 2, 'c': 3}, type(keys)为
专家提醒:使用关键字参数,能打乱参数顺序,使代码更易读。函数定义顺序:位置参数 → 默认参数 → 可变参数!
函数参数使用*分割
函数参数中使用*分割,表示*前面的参数为位置参数,后面的参数为关键字参数。
#举例 定义函数 有a,b,c,d4个参数,*位于中间
def printnum(a,b,*,c,d):
print(f'a,b : {a} {b}')
print(f'c,d : {c} {d}')
传入如下参数执行:
printnum(1,2,c=3,d=4)
#结果:
a,b : 1 2
c,d : 3 4
printnum(1,2,d=4,c=3)
#结果: 跟上面结果一样
a,b : 1 2
c,d : 3 4
如果传入如下参数执行会报错:
printnum(1,2,3,4)
#结果
Traceback (most recent call last):
File "/test.py", line 25, in
printnum(1,2,3,4)
TypeError: printnum() takes 2 positional arguments but 4 were given
4. 返回值与变量作用域
返回多个值
def analyze_data(data):
return min(data), max(data), len(data)
low, high, len = analyze_data([1,2,3])
print(f"最低:{low}, 最高:{high}, 长度:{len}")
Python 函数可返回多个值,本质是返回一个元组,通过解包能轻松获取各个值。
5 变量作用域
total = 0 # 全局变量
def add_coffee():
global total
count = 1 # 局部变量
total += count
add_coffee()
print(total) # → 1
# print(count) 局部变量外部不可访问
- 函数外部的是变量是全局变量,函数内部是局部变量(只能在函数内部使用)。
- 函数内可以使用全局变量,但是如果想修改全局变量需要添加global声明,如上面的global total
6 闭包函数
闭包函数是函数内部嵌套其他的函数。
def power_factory(exponent):
def power(base):
return base ** exponent
return power
square = power_factory(2) #返回的是内部函数power
print(square(5)) # → 25 执行内部函数 参数base=5
7 函数传参是值传递还是引用传递?
既不是值传递也不是引用传递,其实函数传递的是参数所指向的对象。
我们以参数为列表和字符串举例。列表为可变数据类型,字符串为不可变数据类型。
- 函数参数传入列表
listA = [1,4,3,2]
#打印列表的指向的对象的唯一内存地址
print(f'listA内存地址:{id(listA)}')
#定义一个函数 设置的形参需要传递一个列表
def sum_num(numlist):
#打印函数的参数传递后对应的内存地址
print(f'numlist内存地址:{id(numlist)}')
#对列表修改操作
numlist.append(5)
#打印修改后的列表
print(f'numlist:{numlist}')
#将列表listA传递给函数并执行函数
sum_num(listA)
#函数执行后打印列表listA
print(f'listA:{listA}')
函数执行结果:
listA内存地址:4504899072
numlist内存地址:4504899072
numlist:[1, 4, 3, 2, 5]
listA:[1, 4, 3, 2, 5]
结果显示函数外定义的列表和函数内传递的参数对应是同一个内存地址,当在函数内对参数进行修改时,因为列表是可变类型,是支持修改的,其实修改的是他们共同指向的对象,所以修改后打印的两个列表值是相同的。
- 函数参数传入字符串
#定义一个字符串
strA = 'hello python'
print(f'strA内存地址:{id(strA)}')
def printstr(str_a):
print(f'str_a内存地址:{id(str_a)}')
#修改字符串
str_a += '.'
print(f'str_a:{str_a}')
print(f'str_a 内存地址:{id(str_a)}')
#执行函数
printstr(strA)
#打印原变量信息
print(f'strA:{strA}')
print(f'strA 内存地址:{id(strA)}')
函数执行结果如下
strA内存地址:4504812144
str_a内存地址:4504812144
str_a:hello python.
str_a 内存地址:4504903536
strA:hello python
strA 内存地址:4504812144
结果显示函数外定义的字符串和函数内传递的参数对应是同一个内存地址,当在函数内对参数进行修改时,因为字符串是不可变的,不支持修改,所以函数内被修改后的参数指向了另一个内存地址,而函数外定义的字符串还是指向原来的对象。
警惕陷阱
可变默认参数
def add_item(item, lst=[]): #
lst.append(item)
return lst
# 正确做法:使用None
def add_item(item, lst=None):
lst = lst or []
lst.append(item)
return lst
可变对象作默认参数,会在函数定义时创建并复用,易出意外结果。用None作默认值,在函数内按需创建可变对象更安全。
全局变量污染
total = 0
def calculate():
total = 100 # 创建局部变量
# 正确做法:使用global声明
在函数内未声明global,直接给全局变量赋值,会创建同名局部变量,导致逻辑错误。修改全局变量需用global声明。
专家终极指南
- 参数传递是 "传对象引用":理解这一点,能避免参数传递时的误解。
- 返回多个值实际是返回元组:清楚其本质,有助于更好地处理返回值。
- 全局变量要慎用:过多使用易造成代码混乱,应尽量减少其使用。
- 闭包记得用 nonlocal:在闭包中修改外部变量,nonlocal必不可少。
小白:(跪了)原来函数有这么多学问!
专家:(扶起小白)记住:好的函数就像瑞士军刀 —— 功能明确,安全可靠!
相关推荐
- 点过的网页会变色?没错,这玩意把你的浏览记录漏光了
-
提起隐私泄露这事儿,托尼其实早就麻了。。。平时网购、换手机号、注册各种账号之类的都会咔咔泄露,根本就防不住。但托尼真是没想到,浏览器里会有一个看起来完全人畜无害的功能,也在偷偷泄露我们的个人隐私,而且...
- Axure教程:高保真数据可视化原型
-
本文将介绍如何制作Axure高保真数据可视化原型,供大家参考和学习。高保真数据可视化原型设计,称得上是Axure高阶水平。数据可视化在原型设计中是一个重要的分支,但是对于Axure使用者具有一定要求。...
- Flutter web开发中禁用浏览器后退按钮
-
路由采用的go-router路由框架:finalrootNavigatorKey=GlobalKey<NavigatorState>();finalGoRouterrouter...
- jQuery 控制属性和样式
-
标记的属性each()遍历元素:each(callback)方法主要用于对选择器进行遍历,它接受一个函数为参数,该函数接受一个参数,指代元素的序号。对于标记的属性而言,可以利用each()方法配合th...
- 微信小程序入门教程之二:页面样式
-
这个系列的上一篇教程,教大家写了一个最简单的Helloworld微信小程序。但是,那只是一个裸页面,并不好看。今天接着往下讲,如何为这个页面添加样式,使它看上去更美观,教大家写出实际可以使用的页...
- 如何在Windows11的任务栏中禁用和删除天气小部件图标?
-
微软该公司已在Windows11的任务栏中添加了一个天气小部件图标,作为小部件的入口点。这个功能与之前Win10上的新闻与资讯功能相同,但是有的用户不喜欢想要关闭,不知道如何操作,下面小编为大家带来...
- CSS伪类选择器大全:提升网页交互与样式的神奇工具
-
CSS伪类选择器是前端开发中不可或缺的强大工具,它们允许我们根据元素的状态、位置或用户行为动态地应用样式。本文将全面介绍常用的伪类选择器,并通过代码示例展示其实际应用场景。一、基础交互伪类1.超链接...
- 7个Axure使用小技巧
-
编辑导读:对于Axure原型工具,很少有产品经过系统学习,一般都是直接上手,边摸索边学习,这直接导致很多快捷操作被忽视。笔者在日常工作中总结出以下小技巧,希望对各位有帮助。之前整理了2期Axure的...
- JavaScript黑暗技巧:禁止浏览器点击“后退”按钮
-
浏览网页时,当从A页面点击跳转到B页面后,一般情况下,可以点击浏览器上的“后退”按钮返回A页面。如果进入B页面后,B页面想让访问者留下,禁止返回,是否可以实现呢?这简直是要控制浏览器的行为,虽然有些邪...
- 对齐PyTorch,一文详解OneFlow的DataLoader实现
-
撰文|赵露阳在最新的OneFlowv0.5.0版本中,我们增加了许多新特性,比如:新增动态图特性:OneFlow默认以动态图模式(eager)运行,与静态图模式(graph)相比,更容易搭建网...
- Python计算机视觉编程 第一章 基本的图像操作和处理
-
以下是使用Python进行基本图像操作和处理的示例代码:使用PIL库加载图像:fromPILimportImageimage=Image.open("image.jpg"...
- PyTorch 深度学习实战(31):可解释性AI与特征可视化
-
在上一篇文章中,我们探讨了模型压缩与量化部署技术。本文将深入可解释性AI与特征可视化领域,揭示深度学习模型的决策机制,帮助开发者理解和解释模型的内部工作原理。一、可解释性AI基础1.核心概念特征重要...
- 学习编程第177天 python编程 富文本框text控件的使用
-
今天学习的是刘金玉老师零基础Python教程第72期,主要内容是python编程富文本框text控件。一、知识点1.tag_config方法:利用某个别名作为标签,具体的对应标签的属性功能配置在后面参...
- 用Python讓電腦攝像頭實現掃二維碼
-
importsys#系統模組,用來存取命令列參數與系統功能importcv2#OpenCV,處理影像與相機操作importnumpyasnp#Numpy,用來處理數值與...
- 使用Transformer来做物体检测
-
作者:JacobBriones编译:ronghuaiyang导读这是一个Facebook的目标检测Transformer(DETR)的完整指南。介绍DEtectionTRansformer(D...
- 一周热门
- 最近发表
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)