Python3 基础教程

Python3 函数

🎉摘要:本文全面解析 Python3 函数核心知识,涵盖函数定义与调用、参数传递(默认、关键字、不定长)、常用内置函数、高阶函数(lambda、map、filter、reduce)及变量作用域规则。通过丰富示例帮助开发者掌握函数编写技巧,提高代码复用率与可读性,适合 Python 初学者进阶学习。

说到函数,大家可能会想到数学中的函数,函数是数学中最重要的一个模块,贯穿整个数学。

在 Python3 中,函数的应用非常广泛。在前面我们已经多次接触过函数,例如,用于输出的 print() 函数、用于输入的 input() 函数,以及用于生成一系列整数的 range() 函数。但这些都是 Python3 内置的标准函数,可以直接使用。

除了可以直接使用的标准函数之外,Python3 还支持自定义函数,即通过将一段常用的代码片段定义为函数,已达到一次编写、多次调用的目的。使用函数可以提高代码的重复利用率。

定义和调用函数

定义函数也称为创建函数,可以理解为创建一个具有某种用途的工具。Python3 中,使用 def 关键字实现函数定义,具体语法格式如下:

def 函数名(参数列表):
    """函数文档字符串(可选,用于说明函数功能)"""
    函数体(要执行的代码)
    return 返回值(可选)

详细说明:

  • def:定义函数的关键字,定义函数必须以这个关键字开头。

  • 函数名:需遵循变量命名规则(小写、下划线分隔,如 calculate_sum),最好能见名知意。

  • 参数列表:定义函数的“输入”信息,可以没有参数,也可以有一个 / 多个参数。

  • 函数体:缩进的代码块,必须缩进,通常 4 个空格,是函数的核心逻辑。

  • return:定义函数的“输出”,执行到 return 会立即结束函数,没有 return 则默认返回 None。

  • 文档字符串:用三引号包裹,可通过 函数名.__doc__ 或 help(函数名) 查看,方便他人理解函数功能。

当函数定义好后,需要通过 函数名(参数) 的方式调用,函数才会执行。下面通过示例进行说明:

示例 1:没有参数、没有返回值的函数

# 定义函数:打印问候语
def say_hello():
    """打印简单的问候语"""
    print("你好!欢迎学习Python函数")

# 调用函数(必须调用才会执行)
say_hello()

示例2:带参数、无返回值的函数

# 定义函数:打印指定人的问候语
def say_hello_to(name):
    """向指定的人打印问候语
    参数:
        name: 字符串,要问候的人的名字
    """
    print(f"你好,{name}!")

# 调用函数:传入参数"小明"
say_hello_to("小明")

# 再次调用:传入参数"小红"(函数可重复调用)
say_hello_to("小红")

示例3:带参数、有返回值的函数

# 定义函数:计算两个数的和
def calculate_sum(a, b):
    """计算两个数的和并返回结果
    参数:
        a: 数字(整数/浮点数)
        b: 数字(整数/浮点数)
    返回:
        a + b 的结果
    """
    total = a + b
    return total  # 返回计算结果

# 调用函数:接收返回值
result1 = calculate_sum(3, 5)
print("3+5的结果是:", result1)

result2 = calculate_sum(10.5, 20.3)
print("10.5+20.3的结果是:", result2)

函数调用的注意事项如下:

  • 调用时参数数量要匹配:如果函数定义了 2 个参数,调用时不传 / 少传 / 多传都会报错(除非参数定义了默认值)。

  • 函数必须先定义后调用(除非用函数嵌套 / 装饰器等高级用法)。

  • return 可以返回多个值(本质是元组)。

默认参数(调用时可省略)

定义函数参数时,可以使用“参数名=默认值”的方式为函数参数指定默认值,例如:

# 定义函数:计算两个数的和,b默认值为0
def calculate_sum(a, b=0):
    return a + b

# 调用1:只传a,使用b的默认值
print(calculate_sum(10))  # 输出:10

# 调用2:传a和b,覆盖默认值
print(calculate_sum(10, 20))  # 输出:30

关键字参数

指调用定义的函数时按参数名传递参数,而且传递参数的顺序可以与定义顺序不一致,例如:

# 定义函数:打印个人信息
def print_info(name, age):
    print(f"姓名:{name},年龄:{age}")

# 关键字参数调用(顺序无关)
print_info(age=18, name="小李")  # 输出:姓名:小李,年龄:18

不定长参数

指函数可以接收数量不确定的参数,这在需要处理灵活输入的场景中非常实用。如对 N 个数字求和、拼接 N 个字符串等。

*args 不定长位置参数

*args 会把传入的多个位置参数打包成一个元组(tuple),函数内部可以像操作元组一样遍历它。

注意,*args 只是约定俗成的命名,你可以改成 *params 等,但推荐用 *args 保持可读性。

示例1:计算任意个数的数字之和

def calculate_sum(*args):
    """计算任意个数的数字之和"""
    total = 0
    # 遍历args(元组),累加每个元素
    for num in args:
        total += num
    return total

# 传2个参数
print(calculate_sum(1, 2))  # 输出:3

# 传5个参数
print(calculate_sum(10, 20, 30, 40, 50))  # 输出:150

# 不传参数(也能正常执行,返回0)
print(calculate_sum())  # 输出:0

注意,*args 可以和固定参数配合使用 ,但是 *args 必须放在固定位置参数之后,否则会报错。例如:

# 注意,*args 必须放在固定参数 name 的后面
def print_info(name, *args):
    """先打印姓名,再打印任意个其他信息"""
    print(f"姓名:{name}")
    print("其他信息:", args)

# 先传固定参数"小明",再传任意个参数
print_info("小明", 18, "男", "北京")

**kwargs 不定长关键字参数

**kwargs 会把传入的多个关键字参数(key=value 形式)打包成一个字典(dict),函数内部可以像操作字典一样获取 key 和 value。

注意:

(1)kwargs 是约定俗成的命名,也可改,但推荐保留。

(2)调用时必须用 key=value 的形式传参。

示例1:打印任意个键值对形式的个人信息

def print_person(**kwargs):
    """打印任意个个人信息(键值对形式)"""
    for key, value in kwargs.items():
        print(f"{key}:{value}")

# 传2个关键字参数
print_person(name="小红", age=20)
# 输出:
# name:小红
# age:20

# 传3个关键字参数
print_person(name="小刚", gender="男", city="上海", hobby="篮球")
# 输出:
# name:小刚
# gender:男
# city:上海
# hobby:篮球

示例2:将固定参数、*args、**kwargs 配合使用,注意:参数顺序必须遵循:固定位置参数 → *args → 关键字参数 → kwargs,如下:

def func(a, b, *args, c=0, **kwargs):
    print("固定位置参数a:", a)
    print("固定位置参数b:", b)
    print("不定长位置参数args:", args)
    print("默认关键字参数c:", c)
    print("不定长关键字参数kwargs:", kwargs)

# 调用
func(1, 2, 3, 4, 5, c=10, x=100, y=200)

# 输出:
# 固定位置参数a: 1
# 固定位置参数b: 2
# 不定长位置参数args: (3, 4, 5)
# 默认关键字参数c: 10
# 不定长关键字参数kwargs: {'x': 100, 'y': 200}

如果已有列表 / 元组、字典,想传给 *args / **kwargs,可以用拆包符号 * / **,例如:

def calculate_sum(*args):
    """计算任意个数的数字之和"""
    total = 0
    # 遍历args(元组),累加每个元素
    for num in args:
        total += num
    return total

# 列表拆包传给 *args
nums = [1, 2, 3, 4]
print(calculate_sum(*nums))  
# 等价于 calculate_sum(1,2,3,4),输出:10

或者

def print_person(**kwargs):
    """打印任意个个人信息(键值对形式)"""
    for key, value in kwargs.items():
        print(f"{key}:{value}")
        
# 字典拆包传给 **kwargs
person_info = {"name": "小兰", "age": 19, "city": "广州"}
print_person(**person_info)
# 等价于 print_person(name="小兰", age=19, city="广州")

内置函数

Python3 的内置函数(Built-in Functions) 是指 Python3 解释器启动时就默认加载、无需额外导入任何模块就能直接使用的函数。

它们是 Python3 语法的一部分,为开发者提供了最基础、最常用的功能(如类型转换、数值计算、序列操作等),可以理解为 Python3 给你 “预装” 好的工具。

数学计算函数

下面这些内置数学函数不需要导入任何模块就可以使用:

  • abs(x)  返回数字的绝对值

  • round(x[, n])  四舍五入,n 是保留的小数位数(默认 0)

  • max(iter)  返回可迭代对象(列表 / 元组等)的最大值

  • min(iter)  返回可迭代对象的最小值

  • sum(iter)  计算可迭代对象中元素的和

  • pow(x, y)  计算 xy(等价于 x**y)

示例:

# 绝对值
print(abs(-10.5))  # 输出:10.5

# 四舍五入
print(round(2.675, 2))  # 注意:浮点数精度问题,输出2.67(而非2.68)
print(round(2.685, 2))  # 输出2.69

# 最大值/最小值
print(max(10, 5, 8, 12))  # 输出:12
print(min([3.14, 2.71, 1.618]))  # 输出:1.618

# 求和
print(sum(range(1, 101)))  # 1到100求和,输出:5050

# 幂运算
print(pow(10, 3))  # 10的3次方,输出:1000

类型转换函数

类型转换函数用于将一种数据类型转换为另一种数据类型的内置函数,是日常开发中最常用的基础工具之一。

(1)基础类型转换:用于转换 Python 最基础的数值、字符串类型,是最常用的转换函数。

  • int(x)  转为整数(可转数字 / 数字字符串)

  • float(x)  转为浮点数(可转数字 / 数字字符串)

  • str(x)  转为字符串(几乎可转所有类型)

  • bool(x)  转为布尔值(空 / 0 为 False,其余 True)

示例:

# int() 转换:注意小数会直接截断(不是四舍五入)
num1 = int(9.9)  # 截断小数部分
print(f"int(9.9) = {num1}")  # 结果:int(9.9) = 9

num2 = int("-45")  # 支持正负数字字符串
print(f'int("-45") = {num2}')  # 结果:int("-45") = -45

# num3 = int("abc")  # 非数字字符串会报错:ValueError

# float() 转换:支持整数/数字字符串
f1 = float(10)
print(f"float(10) = {f1}")  # 结果:float(10) = 10.0

f2 = float("6.78")
print(f'float("6.78") = {f2}')  # 结果:float("6.78") = 6.78


# str() 转换:万能的字符串转换
s1 = str(True)
print(f's1 = {s1}')  # 结果:s1 = True

s2 = str({"name": "小明"})
print(f's2 = {s2}')  # 结果:s2 = {'name': '小明'}

# bool() 转换,记住“空/0 为 False,非空/非0 为 True”
b1 = bool("")  			# 空字符串 → False
b2 = bool([])  			# 空列表 → False
b3 = bool(0.0)  		# 0.0 → False
b4 = bool("hello")  	# 非空字符串 → True
print(f'b1 = {b1}, b2 = {b2}, b3 = {b3}, b4 = {b4}')
# 结果:b1 = False, b2 = False, b3 = False, b4 = True

(2)容器类型转换:这类函数用于转换列表、元组、集合、字典等容器类型,核心是将 “可迭代对象” 转为目标容器。

  • list(x)  转为列表(x 需是可迭代对象)

  • tuple(x)  转为元组(x 需是可迭代对象)

  • set(x)  转为集合(去重,x 需是可迭代对象)

  • dict(x)  转为字典(x 需是键值对格式的可迭代对象)

示例:

# list() 转换:所有可迭代对象都能转列表
lst1 = list(range(3))  # 范围转列表 → [0,1,2]
print(f'lst1 = {lst1}');

lst2 = list({"a":1, "b":2})  # 字典转列表(只取键)→ ['a','b']
print(f'lst2 = {lst2}');

# tuple() 转换:转后不可修改
tup1 = tuple([1,2,3])  # 列表转元组 → (1,2,3)
print(f'tup1 = {tup1}');

tup2 = tuple("hello")  # 字符串转元组 → ('h','e','l','l','o')
print(f'tup2 = {tup2}');

# set() 转换:自动去重
s1 = set([1,2,2,3])  # 去重 → {1,2,3}
print(f's1 = {s1}');

# dict() 转换:需传入键值对格式(列表套元组/元组套列表)
d1 = dict([("name", "小红"), ("age", 20)])  # 列表套元组 → {'name':'小红','age':20}
print(f'd1 = {d1}');

d2 = dict(zip(["a","b"], [1,2]))  # zip 生成键值对 → {'a':1, 'b':2}
print(f'd2 = {d2}');

(3)进制转换函数

  • bin(x):将整数转为二进制字符串(前缀 0b)

  • oct(x):将整数转为八进制字符串(前缀 0o)

  • hex(x):将整数转为十六进制字符串(前缀 0x)

示例:

print(bin(10))  # 二进制 → 0b1010
print(oct(10))  # 八进制 → 0o12
print(hex(10))  # 十六进制 → 0xa

字节 / 字符串转换:

  • ytes(x, encoding):将字符串转为字节串(需指定编码)

  • str(x, encoding):将字节串转回字符串(需指定编码)

示例:

# 字符串转字节串
b = bytes("你好", encoding="utf-8")
print(b)  # b'\xe4\xbd\xa0\xe5\xa5\xbd'

# 字节串转字符串
s = str(b, encoding="utf-8")
print(s)  # 你好

更多内置函数请参考 https://docs.python.org/zh-cn/3.14/reference/index.html#reference-index 手册。

高阶函数

lambda表达式

Lambda 表达式(也叫匿名函数)是 Python3 中一种简洁的、小型的、可一次性使用的匿名函数,它没有正式的函数名,核心优势是轻量、灵活,常配合列表推导、高阶函数(如 map/filter/sorted)使用。

Lambda 表达式不需要用 def 关键字定义函数名,适合写一行就能完成的简单逻辑。

语法如下:

lambda 参数列表: 表达式

语法说明:

  • lambda:关键字,标识这是一个匿名函数;

  • 参数列表:和普通函数一样,支持位置参数、默认参数(不支持关键字参数 / 可变参数);

  • 表达式:函数的返回值(只能是单个表达式,不能有循环、条件分支(三元表达式除外)、赋值语句等)

Lambda 核心特性如下:

(1)只能有一个表达式,Lambda 的返回值就是表达式的结果,不能写多行逻辑,比如:

# 合法:单个表达式
f = lambda x: x * 2 + 1
print(f(3))  # 输出:7

# 非法:包含多条语句/赋值
# f = lambda x: y = x*2; return y  # 报错:SyntaxError

(2)支持的参数类型,和普通函数兼容基础参数形式,比如:

# 无参数
lambda: "hello"  	# 调用:() → 输出 "hello"

# 单个参数
lambda x: x **2		# 调用:(5) → 输出 25

# 多个参数
lambda x, y: x / y  # 调用:(10,2) → 输出 5.0

# 默认参数
lambda x, y=10: x + y  # 调用:(5) → 输出 15;调用:(5,3) → 输出 8

(3)三元表达式配合 Lambda,虽然不能写 if-else 语句,但可以用三元表达式实现简单条件逻辑,比如:

# 判断数字正负
judge = lambda x: "正数" if x > 0 else ("负数" if x < 0 else "零")

print(judge(5))   # 输出:正数
print(judge(-3))  # 输出:负数
print(judge(0))   # 输出:零

示例1:按元组第二个元素排序

lst = [(1, 3), (4, 1), (2, 2)]
sorted_lst = sorted(lst, key=lambda x: x[1])
print(sorted_lst)  # 输出:[(4, 1), (2, 2), (1, 3)]

示例2:按字符串长度排序

words = ["apple", "banana", "cherry", "date"]
sorted_words = sorted(words, key=lambda s: len(s))
print(sorted_words)  # 输出:['date', 'apple', 'banana', 'cherry']

filter() 函数

filter() 函数用于过滤掉不符合条件的元素,只保留符合条件的。filter() 将返回一个迭代器,该迭代器可以转成列表 / 元组。

语法:

filter(判断函数, 可迭代对象)

其中:

  • 判断函数:返回布尔值(True/False),决定元素是否保留

  • 可迭代对象:待筛选的列表、元组等

示例1:筛选偶数

nums = [1, 2, 3, 4, 5, 6]

# 筛选偶数
even_nums = list(filter(lambda x: x % 2 == 0, nums))

print(even_nums)  # 输出:[2, 4, 6]

示例2:筛选非空字符串

str_list = ["", "apple", "  ", "banana", None]

# 先清洗空格,再筛选非空
non_empty_str = list(filter(lambda s: s.strip() if s else False, str_list))

print(non_empty_str)  # 输出:['apple', 'banana']

示例3:筛选字典列表(按条件过滤)

students = [
    {"name": "小明", "score": 85},
    {"name": "小红", "score": 92},
    {"name": "小刚", "score": 78}
]

# 筛选分数≥80的学生
pass_students = list(filter(lambda x: x["score"] >= 80, students))

print(pass_students)
# 输出:[{'name': '小明', 'score': 85}, {'name': '小红', 'score': 92}]

map() 函数

map() 用于对可迭代对象的每个元素执行相同操作,返回一个迭代器,该迭代器可以转成列表 / 元组。map() 函数常用于批量转换 / 处理数据,如类型转换、数值计算。

语法:

map(函数, 可迭代对象1, 可迭代对象2, ...)

其中:

  • 函数:对每个元素执行的操作,可以是普通函数或 lambda。

  • 可迭代对象:列表、元组、字符串等,支持多个,数量需与函数参数匹配。

示例1:批量转换类型,将字符串转换为整数

str_nums = ["1", "2", "3", "4"]
int_nums = list(map(int, str_nums))  # 转列表
print(int_nums)  # 输出:[1, 2, 3, 4]

示例2:批量计算每个数的平方

nums = [1, 2, 3, 4]
square_nums = list(map(lambda x: x**2, nums))
print(square_nums)  # 输出:[1, 4, 9, 16]

示例3:多可迭代对象,将两个列表对应元素相加

a = [1, 2, 3]
b = [4, 5, 6]
sum_ab = list(map(lambda x, y: x + y, a, b))
print(sum_ab)  # 输出:[5, 7, 9]

reduce() 函数

reduce() 函数用于对可迭代对象的元素进行累积计算(从左到右依次运算),最终返回一个值。常用于将序列“压缩”成一个值,如求和、求乘积、拼接字符串。

注意:Python3 中 reduce() 不再是内置函数,需要从 functools 导入。

语法:

reduce(累积函数, 可迭代对象[, 初始值])

其中:

  • 累积函数:接收两个参数(上一次的结果、当前元素),返回一个值

  • 可迭代对象:列表、元组、字符串等

  • 初始值:可选,首次计算时的 “上一次结果”

示例1:求列表元素的和(等价于 sum() 函数)

from functools import reduce

nums = [1, 2, 3, 4]
total = reduce(lambda x, y: x + y, nums)
print(total)  # 输出:10

示例2:求列表元素的乘积

from functools import reduce

nums = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, nums)
print(product)  # 输出:24

示例3:拼接字符串(等价于"".join())

from functools import reduce

chars = ["H", "e", "l", "l", "o"]
word = reduce(lambda x, y: x + y, chars)
print(word)  # 输出:Hello

示例4:带初始值的累积(初始值为10)

from functools import reduce

nums = [1, 2, 3, 4]
total_with_init = reduce(lambda x, y: x + y, nums, 10)
print(total_with_init)  # 输出:20(10+1+2+3+4)

作用域

作用域(Scope)指的是变量的可访问范围 —— 一个变量定义后,不是在代码的任何位置都能使用,只能在它的“作用域”内才能被访问。

在 Python3 中,有四种作用域(按优先级从高到低):

  • 局部作用域(Local):在函数 / 方法 / 类内部定义的变量,仅当前函数内可用。

  • 嵌套作用域(Enclosing):在嵌套函数中,外层函数的变量(仅内层函数可访问)。

  • 全局作用域(Global):模块(.py 文件)顶层定义的变量,整个模块可用。

  • 内置作用域(Built-in):Python 内置的变量 / 函数(如 print、len)。

注意,Python 在查找变量时,会按“局部作用域 -> 嵌套作用域 -> 全局作用域 -> 内置作用域”的顺序查找,找到即停止;找不到则报 NameError 错误。

全局变量(Global Variable)

在函数 / 类外部(模块顶层)定义的变量,属于全局作用域,整个模块内都能访问(包括函数内部)。例如:

# 全局变量:定义在函数外部
global_num = 100

def print_global():
    # 函数内部可以直接访问全局变量
    print("访问全局变量:", global_num)  # 输出:访问全局变量:100

print_global()
print("函数外部访问全局变量:", global_num)  # 输出:函数外部访问全局变量:100

如果在函数内修改全局变量,即直接在函数内给全局变量赋值,Python 会认为你在定义局部变量,而非修改全局变量,例如:

global_num = 100

def modify_global_wrong():
    # 错误:Python 认为这是定义局部变量,而非修改全局变量
    global_num = 200  # 这里实际创建了局部变量 global_num
    print("函数内局部变量:", global_num)  # 输出:函数内局部变量:200

modify_global_wrong()
print("全局变量未被修改:", global_num)  # 输出:全局变量未被修改:100

如何正确修改全局变量呢?需要使用 global 关键字声明变量为全局变量,例如:

global_num = 100

def modify_global_correct():
    global global_num  # 声明:使用的是全局变量 global_num
    global_num = 200   # 真正修改全局变量
    print("函数内修改后的全局变量:", global_num)  # 输出:函数内修改后的全局变量:200

modify_global_correct()
print("全局变量已修改:", global_num)  # 输出:全局变量已修改:200

局部变量(Local Variable)

在函数 / 类内部定义的变量,属于局部作用域,仅在当前函数内可用,函数外部无法访问。例如:

def define_local():
    # 局部变量:定义在函数内部
    local_num = 200
    print("函数内访问局部变量:", local_num)  # 输出:函数内访问局部变量:200

define_local()

# 错误:函数外部无法访问局部变量
# print("函数外部访问局部变量:", local_num)  
# 报错:NameError: name 'local_num' is not defined

注意,当局部变量和全局变量同名时,局部变量会覆盖全局变量(仅在函数内生效),例如:

num = 100  # 全局变量

def local_override_global():
    num = 200  # 局部变量,覆盖全局变量(仅函数内)
    print("函数内:", num)  # 输出:函数内:200

local_override_global()
print("函数外:", num)  # 输出:函数外:100(全局变量未变)

嵌套作用域(Enclosing):非局部变量

针对嵌套函数(函数内定义函数),外层函数的变量对内层函数来说是“嵌套作用域变量”,需用 nonlocal 关键字修改,例如:

def outer_func():
    enclosing_num = 100  # 嵌套作用域变量(外层函数的局部变量)
    
    def inner_func():
        nonlocal enclosing_num  # 声明:使用的是外层函数的变量
        enclosing_num = 200     # 修改嵌套作用域变量
        print("内层函数:", enclosing_num)  # 输出:内层函数:200
    
    inner_func()
    print("外层函数:", enclosing_num)  # 输出:外层函数:200

outer_func()

注意,global 是用于修改全局作用域变量,nonlocal 则是用于修改嵌套作用域变量。

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号