【Python】函数

文章目录

  • 前言
  • 一、函数的概念
  • 二、函数的定义格式
  • 三、函数的调用
    • [1. 函数的调用格式](#1. 函数的调用格式)
      • [1.1 格式](#1.1 格式)
      • [1.2 传参方式](#1.2 传参方式)
    • [2. 函数的调用方式](#2. 函数的调用方式)
      • [2.1. 链式调用](#2.1. 链式调用)
      • [2.2. 嵌套调用](#2.2. 嵌套调用)
      • [2.3. 递归调用](#2.3. 递归调用)
        • [2.3.1 递归的两个条件](#2.3.1 递归的两个条件)
        • [2.3.2 递归的优缺点](#2.3.2 递归的优缺点)
  • 四、函数的参数
    • [1. 默认参数(缺省参数)](#1. 默认参数(缺省参数))
    • [2. 变长参数](#2. 变长参数)
  • 五、变量的作用域
    • [1. 全局变量和局部变量](#1. 全局变量和局部变量)
    • [2. 函数中操作全局变量](#2. 函数中操作全局变量)
    • [3. `if`、`while`、`for`中的变量](#3. ifwhilefor中的变量)
  • 总结

前言

本文用于介绍Python中函数相关的概念,主要包括:函数的定义、函数的调用、函数的参数以及局部变量和全局变量等内容。


一、函数的概念

编程中的函数是一段可以被重复使用的代码片段,使用函数可以有效减少冗余代码,例如:

python 复制代码
# 1. 求1~100的和
sum = 0
for i in range(101):
    sum += i
print(f'1~100的和为{sum}') # 5050
# 2. 求100~300的和
sum = 0
for i in range(100, 301):
    sum += i
print(f'100~300的和为{sum}') # 40200
# 3. 求1~1000的和
sum = 0
for i in range(1001):
    sum += i
print(f'1~1000的和为{sum}') # 500500

这三段代码的处理逻辑是类似的,因此可以将重复的代码逻辑提取出来封装成一个函数,求和时直接调用该函数即可,例如:

python 复制代码
def Sum(begin, end):
    sum = 0
    for i in range(begin, end + 1):
        sum += i
    return sum
# 1. 求1~100的和
print(f'1~100的和为{Sum(1, 100)}') # 5050
# 2. 求100~300的和
print(f'100~300的和为{Sum(100, 300)}') # 40200
# 3. 求1~1000的和
print(f'1~1000的和为{Sum(1, 1000)}') # 500500

二、函数的定义格式

定义格式

python 复制代码
def 函数名(形参列表):
	函数体
	return语句

注意

  • 一个函数可以没有形参,也可以有多个形参;
  • 一个函数可以有一个或多个return语句,执行到return语句时函数会立即执行结束回到调用位置;
  • 由于Python是动态类型语言,函数的形参和返回值都不用声明类型,因此一个函数可以支持多种不同类型的参数调用。

返回值

Python中的一个函数可以有一个或多个返回值,当有多个返回值需要返回时,要使用,将它们分隔开,例如:

python 复制代码
def getSumAndDef(num1, num2):
    return num1 + num2, num1 - num2
a = 10
b = 20
Sum, Def = getSumAndDef(a, b)
print(f'{a} + {b} = {Sum}, {a} - {b} = {Def}') # 10 + 20 = 30, 10 - 20 = -10

Python中函数能返回多个值,本质是Python支持多元赋值。

如果函数调用者只想关注该函数的部分返回值,可以使用_忽略不关注的返回值,例如:

python 复制代码
def getSumAndDef(num1, num2):
    return num1 + num2, num1 - num2
a = 10
b = 20
_, Def = getSumAndDef(a, b)
print(f'{a} - {b} = {Def}') # 10 - 20 = -10

三、函数的调用

1. 函数的调用格式

1.1 格式

python 复制代码
返回值 = 函数名(实参列表)

注意

函数必须先定义再使用,函数定义后不会执行函数体内容,只有当函数被调用时才会执行。

1.2 传参方式

调用函数时,可以根据函数的形参列表,将实参列表中的数据按顺序依次传给对应的形参,例如:

python 复制代码
def func(x, y):
    print(x)
    print(y)

a = 10
b = 20
func(10, 20) # 10 20

也可以通过关键字参数来调整传参的顺序,显示指定当前实参传给哪个形参,例如:

python 复制代码
def func(x, y):
    print(x)
    print(y)

a = 10
b = 20
func(y = 10, x = 20) # 20 10

2. 函数的调用方式

2.1. 链式调用

链式调用是指:把一个函数的返回值作为调用另一函数时的参数进行传入

python 复制代码
def Sum(x, y):
    return x + y

a = 10
b = 20
print(Sum(a, b)) # 30

Sum函数的返回值作为print函数的参数进行传入

2.2. 嵌套调用

嵌套调用是指:在一个函数的函数体内部调用另一个函数

python 复制代码
def Sum(x, y):
    print(x) # 10
    print(y) # 20
    return x + y

a = 10
b = 20
print(Sum(a, b)) # 30

Sum函数中调用print函数

2.3. 递归调用

递归调用是一种特殊的嵌套调用,它指的是一个函数在函数体内部嵌套调用自己

python 复制代码
# 求一个数的阶乘
def factor(num):
    if num == 1:
        return num
    else:
        return num * factor(num - 1)

print(f'5的阶乘是{factor(5)}') # 120

factor函数内部嵌套调用了factor函数,这就是递归调用(一层一层进行递归调用,当满足递归结束条件时再逐层返回)

2.3.1 递归的两个条件
  1. 存在递归结束条件
  2. 每进行一次递归,都会逐渐逼近结束条件

如果不能满足这两个条件,就会出现无限递归的情况,最终导致栈溢出(Stack Overflow)。

函数调用时,需要在函数调用栈中借了每一层函数调用的信息,但是函数调用栈的空间是有限的,如果函数调用层次太多,就会超出栈的最大范围,导致栈溢出。

2.3.2 递归的优缺点
优点
  • 代码简洁:递归代码量通常比较少,对于天生具有递归结构的问题(树、图、分治、回溯、动态规划等),递归代码能直接映射问题定义,清晰反应自顶向下的分解过程。代码量通常远少于等价的循环+显示栈管理代码。
  • 思维直观,符合数学归纳法:明确基础条件和递推公式就可以解决问题。在解决数列、组合数学等问题时很方便
  • 简化复杂问题:将大问题分解为结构相同的小问题,是分支策略和回溯算法的基石,极大的降低了思考的复杂度
缺点
  • 调试和理解难度较大:递归的"层层深入再层层返回"的过程不直观,导致代码往往难以理解,很容易超出掌控范围
  • 栈溢出风险 :递归深度受限于调用栈大小,当递归过深时,会抛出Stack Overflow
  • 性能开销大:每次递归调用都涉及栈帧的创建(保存参数、局部变量。返回地址等),与纯循环相比较,时间和空间开销都更大。递归代码可以转换为等价的循环代码,并且通常情况下循环版本的代码执行效率会更高,因为函数调用也有开销。

四、函数的参数

1. 默认参数(缺省参数)

类似C++编程语言,Python也支持给函数的形参指定默认值,在调用函数时,可以不给缺省参数传参(它会使用默认值),例如:

python 复制代码
def factor(num = 3):
    if num == 1:
        return num
    else:
        return num * factor(num - 1)

print(f'5的阶乘是{factor(5)}') # 120
print(f'3的阶乘是{factor()}') # 6

可以看到,如果给函数传入实参,则函数会使用该实参,如果不给函数传入实参,则函数会直接使用默认值。
注意

在定义函数时,缺省参数需要放到普通参数的后面。

2. 变长参数

如果想让函数能接收任意个数的参数,可以在函数定义的形参名称前面添加*,这时函数将接收一个参数元组,可以通过形参名[下标]的方式访问传入的各个实参,例如:

python 复制代码
def Func(*arg):
    n = len(arg)
    for i in range(n):
        print(arg[i])
        
Func(1, 2, 4) # 1 2 4
Func(3, 4) # 3 4

五、变量的作用域

1. 全局变量和局部变量

每个变量都有自己的作用域:

  • 定义在函数外部的变量,其作用域是全局,称为"全局变量";
  • 定义在函数内部的变量,其作用域是函数体内,称为"局部变量"

注意

  • 局部变量只能在自己所在的函数体内生效;
  • 不同作用域内允许存在同名变量

2. 函数中操作全局变量

函数体内使用的变量会优先在局部域中查找,如果局部域中找不到,会去全局域中查找,例如:

python 复制代码
def Func():
    print(x)

x = 10
Func() # 10

如果在函数体内想要修改全局变量,需要使用global关键字,声明该变量是全局变量。否则Python编译器会认为该变量是在函数体内创建的同名局部变量,导致函数体内对该变量的修改无法同步到函数体外,例如:

python 复制代码
# 不使用global声明
def Func():
    x = 20
    print(x) # 20

x = 10
Func() # 20
print(x) # 10

# 使用global声明
def Func():
    global x
    x = 20
    print(x) # 20

x = 10
Func() # 20
print(x) # 20

3. ifwhilefor中的变量

ifwhilefor等语句块不会影响变量的作用域,即在这些语句块中定义的变量,在语句块外部也能正常使用,例如:

python 复制代码
for i in range(10):
    print(i)
    
print(i) # 9

总结

以上就是今天要讲的内容,本文介绍了Python中函数的相关概念。本文作者目前也是正在学习Python相关的知识,如果文章中的内容有错误或者不严谨的部分,欢迎大家在评论区指出,也欢迎大家在评论区提问、交流。

最后,如果本篇文章对你有所启发的话,希望可以多多支持作者,谢谢大家!

相关推荐
geovindu2 小时前
python: Command Pattern
开发语言·python·命令模式
Cosmoshhhyyy2 小时前
《Effective Java》解读第41条:用标记接口定义类型
java·开发语言
曲幽2 小时前
FastAPI实战:WebSocket长连接保持与心跳机制,从入门到填坑
javascript·python·websocket·keep-alive·fastapi·heartbeat·connection
锅包一切2 小时前
【蓝桥杯JavaScript基础入门】一、JavaScript基础
开发语言·前端·javascript·蓝桥杯
前路不黑暗@3 小时前
Java项目:Java脚手架项目的 B 端用户服务(十四)
android·java·开发语言·spring boot·笔记·学习·spring cloud
好学且牛逼的马3 小时前
从“混沌初开”到“有序统一”:Java集合框架发展历程与核心知识点详解
前端·数据库·python
wuqingshun3141594 小时前
什么是浅拷贝,什么是深拷贝,如何实现深拷贝?
java·开发语言·jvm
a1117764 小时前
快速制作 虚拟形象项目 MotionPNGTuber
python·live2d
一切尽在,你来4 小时前
AI大模型应用开发前置知识:Python迭代器和生成器深入详解
python·langchain·ai编程