python 函数、异常处理、文件操作、模块、包
函数
函数就是能实现一定功能的代码语句的集合。
def 函数名(参数):
函数体
# 关键字参数(可以不按顺序传参)
def add(a, b):
return a + b
add(b=1, a=2)
# 默认参数(不传参使用默认值)
def add(a, b, c = 3):
return a + b + c
add(1, 2)
add(1, 2, 4)
跟其他语言一样, Python 函数定义同样支持无形参、有形参、可变参数等;而函数可以有返回值,也可以没有返回值。
- 无形参—不需要参数输入
# 无形参,无返回值
def print_log():
print(''' Welcome to Kevin's class ! ''')
if __name__ == "__main__":
print_log()
- 有形参—函数接受用户参数
# 有一个形参,有返回值
def is_true(x):
return x > 0
# 有两个形参,有返回值
def min_number(x, y):
if x>=y:
x,y = y, x
return x
# 可变参数
# 有可变个形参, 有返回值
def sum_number(*args):
total = 0
for k in args:
total +=k
return total
# 可变个形参,接受key-value的形式, 无返回值
def count_student(**kwargs):
for k, v in kwargs.items():
print('{0} - {1}'.format(k, v))
if __name__ == "__main__":
print(is_true(-2))
total = sum_number(1, 2)
print(total)
min = min_number(1, 2)
print(min)
count_student(math='kevin', logic='emily')

函数的作用域
-
全局变量:在函数外面定义,整个文件都可以读取
-
局部变量:函数内部定义,函数执行完销毁
g_num = 100 # 全局变量
def func():
g_num = 10
return g_num # ✅可以读全局
func()
print(g_num) # 100
global 关键字
告诉 Python:这个变量是全局变量,函数内修改全局
g_num = 100 # 全局变量
def func():
global g_num
g_num = 10
return g_num # ✅可以读全局
func()
print(g_num) # 10
嵌套函数
函数里面嵌套函数,内层可以读取外层函数的局部变量,外层不能读取内层的局部变量。
def outer():
x = 20
def inner():
x = 999
inner()
print(x)
outer() # 20
nonlocal 关键字
修改使外层能够读取内部的局部变量
def outer():
x = 20
def inner():
nonlocal x
x = 999
inner()
print(x)
outer() # 999
异常处理
异常就是程序运行时发生错误,若不捕获,程序直接崩溃退出。如果做了异常处理,程序就不会中断,保证程序继续正常执行。
try:
# 可能出错的代码
代码块
except 异常类型1:
# 捕获对应异常后的处理
处理代码
except 异常类型2 as e:
# e 拿到异常对象,可打印错误信息
处理代码
else:
# ✅ try中没有发生异常才执行
正常执行代码
finally:
# 无论是否异常,一定执行(常用于关闭文件、释放资源)
必执行代码
简单示例:
try:
a = 1 / 0
except ZeroDivisionError as err:
print(f"捕获到错误:{err}")
else:
print("没有异常才走到这里")
finally:
print("永远执行,做资源清理")
主动抛出异常: raise
def check_age(age):
if age < 0:
raise ValueError("年龄不能是负数")
return age
try:
check_age(-5)
except ValueError as e:
print(e)
自定义异常
class MyBusinessError(Exception):
"""自定义业务异常"""
pass
try:
raise MyBusinessError("业务逻辑出错啦")
except MyBusinessError as e:
print(f"捕获自定义异常:{e}")
文件操作
Python 使用内置 open() 函数完成文件读写,不需要额外安装库,支持文本文件、二进制文件。传统的文件操作示例如下:
file = open('example.txt', 'r')
try:
# 处理文件内容
content = file.read()
finally:
# 关闭文件释放资源
file.close()
这种写法存在几个问题:
- 容易忘记关闭资源:如果没有 try-finally 块,可能会忘记调用 close()
- 代码冗长:简单的文件操作需要多行代码
- 异常处理复杂:需要手动处理可能出现的异常
with 语句
with 语句通过上下文管理协议(Context Management Protocol)解决了这些问题:
- 自动资源释放:确保资源在使用后被正确关闭
- 代码简洁:减少样板代码
- 异常安全:即使在代码块中发生异常,资源也会被正确释放
- 可读性强:明确标识资源的作用域
with open('example.txt', 'r') as file:
content = file.read()
print(content)
# 文件已自动关闭
| 模式 | 说明 |
|---|---|
| r | read 只读,文件不存在报错,默认模式 |
| w | write 只写,文件不存在创建;存在则清空原有内容 |
| a | append 追加,在文件末尾写入,不会清空旧内容 |
| r+ | 读写,文件必须存在,可读可写 |
| w+ | 读写,不存在创建,存在直接清空 |
| a+ | 追加读写,指针在末尾 |
| b | 二进制模式:rb、wb、ab,用于图片、视频、exe |
读取文件
with open('example.txt', 'r', encoding='utf-8') as file:
# 读取全部
context = file.read()
# 读取一行
line = file.readline()
# 读取所有行
lines = f.readlines()
写入文件
with open('example.txt', 'w', encoding='utf-8') as file:
file.write('hello world')
# 写入多行
lines = ["苹果\n", "香蕉\n", "橙子\n"]
f.writelines(lines)
二进制读写(图片、视频)
不要加 encoding 参数
with open('test.jpg', 'rb') as file:
data = file.read()
with open('copy.jpg', 'wb') as file:
file.write(data)
文件指针 seek /tell (了解)
with open("test.txt", "r", encoding="utf-8") as f:
print(f.tell()) # 获取当前文件指针位置
f.seek(5) # 跳到第5字节
print(f.read())
模块
模块是为了编写可维护的代码,而把函数分组放到不同文件里的行为。在 Python 中,一个 .py文件 就是一个模块,一个模块可以包括一个或多个功能,模块又可以被一个或多个其他模块引用。
- 提高编程效率,增强代码可维护性
把模块导入当前模块,当前模块即可拥有模块已经实现的功能。如果模块的功能本身需要更改,我们只需要更改模块定义的地方即可,其他地方都无须更改。
- 不同模块的函数名和变量名可以重名
有了模块,避免了函数名和变量名之间的冲突,例如如下的文件结构:
myproject
|--module1.py
|--module2.py
假设我在 module1.py 里和 module2.py 里,同时定义一个名字为 take_picture() 的函数。这两个不同模块的函数虽然都叫 take_picutre,但其行为可以不相同,也不会相互影响。
包
包(Package)可以用于解决模块名称相同的问题。包就是一个目录文件,它必须包含一个名为 __init__.py 的文件。
myproject
|-- web
|-- module.py
|-- __init__.py
|-- API
|-- module.py
|-- __init__.py
|-- __init__.py
在 web 层级和 API 层级它们都包含着名字相同的模块 module.py,以下列出不同包下的模块引用方式:
# 引入web目录下的包, 假设此目录下module.py里有类变量Module
from web.module import Module
# 引入API目录下的包,假设此目录下module.py里有类变量Module
from API.module import Module
模块的导入
- 直接导入
import module1
module1.take_picture()
- from...import 方式导入
有时候我们并不想把一个模块的所有功能都导入进来,假设我只想使用 take_picture 这一个方法,那么我可以使用 from...import 的方式:
from module1 import take_picture
take_picture()
- from...import* 方式导入(不推荐使用)
如果你想一次性地导入一个模块下的所有函数, 你可以使用如下方式:
from module1 import *
- 动态导入
但在实际应用中,也会有在程序运行时才知道要具体导入哪个模块的情况(例如,测试框架自动查找测试用例并导入测试用例所属的模块),这时就需要动态导入。
动态导入常常用 importlib 来完成,常用的动态导入有以下两种方式。
- 从模块直接导入
import importlib
#导入a.b模块
mod = importlib.import_module( "a.b")
- 根据模块名,文件名导入
import importlib.util
spec = importlib.util.spec_from_file_location("a.b", "/path/to/file.py")
md = importlib.util.module_from_spec(spec)
spec.loader.exec_module(md)
下面我来举个具体的例子, 假设现在我们的项目目录情况如下:
myproject
|-- tests
|-- a.py
|-- __init__.py
|-- b.py
在模块 a.py 里,我定义了一个函数:
def hello():
print('i am module a!')
然后在模块 b.py 中使用hello()函数
#b.py
import os
import glob
import importlib.util
def find_modules_from_folder(folder):
absolute_f = os.path.abspath(folder)
md = glob.glob(os.path.join(absolute_f, "**/*.py"))
return [(os.path.basename(f)[:-3], f) for f in md if os.path.isfile(f) and not f.endswith('__init__.py')]
def import_modules_dynamically(mod, file_path):
spec = importlib.util.spec_from_file_location(mod, file_path)
md = importlib.util.module_from_spec(spec)
spec.loader.exec_module(md)
return md
if __name__ == "__main__":
module = find_modules_from_folder('.')
for m in module:
mod = import_modules_dynamically(m[0], m[1])
mod.hello()
这个代码有点复杂,我先给定一个文件夹,然后通过函数 find_modules_from_folder 来得到这个文件夹下的模块,及其对应的文件路径,然后我再通过 spec_from_file_location 来动态加载。
常用内置模块
os 模块
用于与操作系统进行交互,提供了许多操作系统相关的功能,比如文件和目录操作、获取系统信息等。
# 导入了os模块
import os
# 打印当前命令所在的目录
print("当前命令所在的目录:", os.getcwd())
# 获取当前文件所在工作目录
print("__file__", __file__)
print("os.path.dirname(__file__): ", os.path.dirname(__file__))
# 创建一个新目录
new_dir_name = "new_directory"
if not os.path.exists(new_dir_name):
os.makedirs(new_dir_name)
print("创建文件成功")
# 列出当前目录下的所有文件和目录
files_and_dirs = os.listdir('.')
print("当前目录下的文件和目录:", files_and_dirs)
# 删除刚才创建的目录(需确保目录为空)
if os.path.exists(new_dir_name):
os.rmdir(new_dir_name)
sys 模块
提供了对 Python 解释器相关的一些变量和函数的访问,比如获取命令行参数、模块搜索路径等。
print("__file__", __file__)
import sys
# 获取命令行参数(不包括脚本名本身)
# 常见命令行参数的参数名称一般是以 - 开头,如 -h、-v 等,值就不是以 - 开头
arguments = sys.argv[1:] # 获取除了脚本名本身以外的所有参数
print("命令行参数:", arguments)
# 查看模块搜索路径,了解即可
module_paths = sys.path
print("模块搜索路径:", module_paths)
math 模块
包含了各种数学函数和常量,用于数学计算,比如三角函数、对数函数、幂函数等。
import math
# 计算圆的面积,半径为5
radius = 5
area = math.pi * radius ** 2
# area = math.pi * math.pow(radius, 2)
print("圆的面积:", area)
# 向上取整
print("向上取整:", math.ceil(3.15))
# 向下取整
print("向上取整:", math.floor(3.15))
# 四舍五入
print("四舍五入:", round(3.15), round(3.5))
random 模块
用于生成随机数,可以生成随机整数、随机浮点数、随机序列等。
import random
# 生成一个0到1之间的随机浮点数
random_float = random.random()
print("随机浮点数:", random_float)
# 一个随机整数 N,满足 a <= N <= b
random_int = random.randint(1, 100)
print("随机整数:", random_int)
# 随机打乱一个列表的顺序
my_list = [1, 2, 3, 4, 5]
random.shuffle(my_list)
print("打乱后的列表:", my_list)
# 随机取出列表中的一个数据
random_item = random.choice(my_list)
print("随机取出的元素:", random_item)
# 从字符串中随机选择一个字符
random_char = random.choice("hello")
print("随机字符:", random_char)
time 模块
用于处理时间相关的操作,比如获取当前时间、设置定时器、时间格式化等。
import time
# 获取当前时间的时间戳(从1970年1月1日00:00:00 UTC到当前时刻的秒数)
start_time = time.time()
print("当前时间戳:", start_time)
# 了解一段程序的执行时间,思路就是在程序开始前获取时间戳,在程序结束后获取时间戳,然后计算时间差
# 将时间戳转换为结构化的时间对象
struct_time = time.localtime(start_time)
print("结构化时间对象:", struct_time)
# 如果获取时间中年月日和时分秒
print("年:", struct_time.tm_year)
print("月:", struct_time.tm_mon)
print("日:", struct_time.tm_mday)
print("时:", struct_time.tm_hour)
print("分:", struct_time.tm_min)
print("秒:", struct_time.tm_sec)
print("周:", struct_time.tm_wday)
# 格式化时间,例如按照"年-月-日 时:分:秒"的格式
formatted_time = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
print("格式化时间:", formatted_time)
# 程序执行暂停3秒,在web自动化开发时比较常用
time.sleep(3)
print("程序执行暂停3秒")
end_time = time.time()
print("程序执行结束,总耗时:", end_time - start_time, "秒")
datetime 模块
是 time 模块的增强版,提供了更方便的日期和时间处理功能,比如创建日期时间对象、计算时间间隔等。
from datetime import datetime, timedelta
# 获取当前日期和时间
now = datetime.now()
print("当前日期和时间:", now)
# 创建一个指定日期和时间的对象
specific_date = datetime(2024, 12, 31, 23, 59, 59)
print("指定日期和时间:", specific_date)
d1 = datetime.fromisoformat("2024-12-31T23:59:59")
print("d1", d1)
d2 = datetime.strptime("2024年12月31日 23时59分59秒", "%Y年%m月%d日 %H时%M分%S秒")
print("d2", d2)
# 计算两个日期时间之间的时间间隔
time_difference = specific_date - now
print("时间间隔:", time_difference)
# 将时间间隔转换为秒
seconds = time_difference.total_seconds()
print("时间间隔(秒):", seconds)
# abs取绝对值
print("time_difference.days", time_difference.days, abs(time_difference.days))
# 在当前时间基础上增加1小时
new_time = now + timedelta(hours=1)
print("增加1小时后的时间:", new_time)
a = timedelta(hours=1, minutes=1, seconds=1, milliseconds=1, microseconds=1, days=1, weeks=1)
print("a", a)
json 模块
用于处理 JSON 数据,包括 JSON 数据的编码(将 Python 对象转换为 JSON 字符串)和解码(将 JSON 字符串转换为 Python 对象)。很多接口返回的都是 json 数据,如何去取出对应数据呢,就需要对 json 数据进行转化,一般是转换成字典。
json 格式的字符串,与 python 中的字典很相似,key 只能是字符串。
import json
# 将Python字典转换为JSON字符串
my_dict = {"name": "Alice", "age": 30}
json_string = json.dumps(my_dict)
print("JSON字符串:", json_string, type(json_string))
# 将JSON字符串转换为Python字典
new_dict = json.loads(json_string)
print("转换后的字典:", new_dict, type(new_dict))
# 字符串,长得像字典
my_dict_str = '{"name": "Alice", "age": 30}'
print("my_dict_str的类型", type(my_dict_str))
# 错误的将字符串当成字典来使用
# print("错误的将字符串当成字典来使用", my_dict_str['name'])
# 此时可以使用,json.loads只能符合json格式的字符串进行转换
new_dict1 = json.loads(my_dict_str)
print("转换后的字典new_dict1:", new_dict1)
print("转换后的字典new_dict1['name']:", new_dict1['name'])
# 这是一个非json格式的字符串
str = "acb"
# 无法转换
j = json.loads(str)
print(j)
# 将一个列表字符串转成成列表对象。
str = '["a", "b", "c"]'
lst = json.loads(str)
print("lst", lst, lst[0])
re 模块
用于正则表达式的处理,包括匹配、搜索、替换等操作,在文本处理中非常有用。
import re
# 匹配字符串中是否存在数字
string = "ab2c123de1f"
match_result = re.search(r'\d', string) # \d表示数字,是正则表达式的写法
if match_result:
print("字符串中存在数字")
else:
print("字符串中不存在数字")
# 替换字符串中的所有数字为"*"
new_string = re.sub(r'\d', '*', string)
print("替换后的字符串:", new_string)

浙公网安备 33010602011771号