百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Python 函数全解+闭坑指南,一篇就够

itomcoil 2025-03-29 18:46 23 浏览

引言

学完了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必不可少。

小白:(跪了)原来函数有这么多学问!

专家:(扶起小白)记住:好的函数就像瑞士军刀 —— 功能明确,安全可靠!

相关推荐

MySQL修改密码_mysql怎么改密码忘了怎么办

拥有原来的用户名账户的密码mysqladmin-uroot-ppassword"test123"Enterpassword:【输入原来的密码】忘记原来root密码第一...

数据库密码配置项都不加密?心也太大了吧!

先看一份典型的配置文件...省略...##配置MySQL数据库连接spring.datasource.driver-class-name=com.mysql.jdbc.Driverspr...

Linux基础知识_linux基础入门知识

系统目录结构/bin:命令和应用程序。/boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。/dev:dev是Device(设备)的缩写,该目录...

MySQL密码重置_mysql密码重置教程

之前由于修改MySQL加密模式为mysql_native_password时操作失误,导致无法登陆MySQL数据库,后来摸索了一下,对MySQL数据库密码进行重置后顺利解决,步骤如下:1.先停止MyS...

Mysql8忘记密码/重置密码_mysql密码忘了怎么办?

Mysql8忘记密码/重置密码UBUNTU下Mysql8忘记密码/重置密码步骤如下:先说下大概步骤:修改配置文件,使得用空密码可以进入mysql。然后置当前root用户为空密码。再次修改配置文件,不能...

MySQL忘记密码怎么办?Windows环境下MySQL密码重置图文教程

有不少小白在使用Windows进行搭建主机的时候,安装了一些环境后,其中有MySQL设置后,然后不少马大哈忘记了MySQL的密码,导致在一些程序安装及配置的时候无法进行。这个时候怎么办呢?重置密码呗?...

10种常见的MySQL错误,你可中招?_mysql常见错误提示及解决方法

【51CTO.com快译】如果未能对MySQL8进行恰当的配置,您非但可能遇到无法顺利访问、或调用MySQL的窘境,而且还可能给真实的应用生产环境带来巨大的影响。本文列举了十种MySQL...

Mysql解压版安装过程_mysql解压版安装步骤

Mysql是目前软件开发中使用最多的关系型数据库,具体安装步骤如下:第一步:Mysql官网下载最新版(mysql解压版(mysql-5.7.17-winx64)),Mysql官方下载地址为:https...

MySQL Root密码重置指南:Windows新手友好教程

如果你忘记了MySQLroot密码,请按照以下简单步骤进行重置。你需要准备的工具:已安装的MySQL以管理员身份访问命令提示符一点复制粘贴的能力分步操作指南1.创建密码重置文件以管理员...

安卓手机基于python3搜索引擎_python调用安卓so库

环境:安卓手机手机品牌:vivox9s4G运行内存手机软件:utermux环境安装:1.java环境的安装2.redis环境的安装aptinstallredis3.elasticsearch环...

Python 包管理 3 - poetry_python community包

Poetry是一款现代化的Python依赖管理和打包工具。它通过一个pyproject.toml文件来统一管理你的项目依赖、配置和元数据,并用一个poetry.lock文件来锁定所有依赖的精...

Python web在线服务生产环境真实部署方案,可直接用

各位志同道合的朋友大家好,我是一个一直在一线互联网踩坑十余年的编码爱好者,现在将我们的各种经验以及架构实战分享出来,如果大家喜欢,就关注我,一起将技术学深学透,我会每一篇分享结束都会预告下一专题最近经...

官方玩梗:Python 3.14(πthon)稳定版发布,正式支持自由线程

IT之家10月7日消息,当地时间10月7日,Python软件基金会宣布Python3.14.0正式发布,也就是用户期待已久的圆周率(约3.14)版本,再加上谐音梗可戏称为π...

第一篇:如何使用 uv 创建 Python 虚拟环境

想象一下,你有一个使用Python3.10的后端应用程序,系统全局安装了a2.1、b2.2和c2.3这些包。一切运行正常,直到你开始一个新项目,它也使用Python3.10,但需要...

我用 Python 写了个自动整理下载目录的工具

经常用电脑的一定会遇到这种情况:每天我们都在从浏览器、微信、钉钉里下各种文件,什么截图、合同、安装包、临时文档,全都堆在下载文件夹里。起初还想着“过两天再整理”,结果一放就是好几年。结果某天想找一个发...