红魔咖啡馆

头发越掉越多,头发越掉越少

0%

【Python】Python基础补全

字符串格式化

%格式化

基本语法:模板字符串 % (值1, 值2,...)

模板字符串里的占位符以%+类型说明符表示,具体占位符如下

占位符 含义
%s 字符串
%r 原始调用(repr())
%d 十进制整数
%f 浮点数

%占位符还支持通过格式说明符控制输出格式,语法如下:

%[宽度][.精度][类型]

  • 宽度指定输出字符串的最小长度,不足用空格填充,默认右对齐
  • 精度:对浮点数表示小数位数,对字符串表示最大长度
  • 左对齐:宽度前加-实现左对齐

不好用

str.format()

基本语法与参数

基本语法:模板字符串.format(参数1, 参数2, ..., 关键字参数1=值1, ...)

模板字符串中使用{}占位符在模板中预留位置

位置参数:占位符中可以用数字指定参数索引,或省略按顺序匹配

1
2
3
4
5
# 按顺序匹配
print("Name: {}, Age: {}".format("lihua", 18)) 

# 按索引指定(可重复/乱序)
print("Second: {1}, First: {0}, First again: {0}".format("A", "B"))

关键字参数:占位符中也可以直接用关键字参数名

1
print("User: {name}, ID: {id}".format(name="lihua", id=114514))

混合使用:可以混合使用,但是位置参数必须在关键字参数前

1
print("{}: {name} ({age})".format("person", name="lihua", age=18))

格式规范和类型转换

format方法支持通过:在占位符中添加格式规范,语法形如{[名称/索引]:[格式规范]}

  • 对齐和宽度:

    • <是左对齐
    • >是右对齐
    • ^是居中对齐
    • 符号后可以添加数字指定对齐后的字符串长度
  • 浮点数精度:{:.位数f}

  • 千位分隔符:{:,},只适用于数字

  • 类型转换符:{!类型},指定类型转换,类似于%s或%r,对应字母一样

  • 特定类型格式化:

    • 日期:{:%Y-%m-%d %H:%M}
    • 百分比:{:.位数%}

嵌套与自定义

  • 可以嵌套列表和字典:
1
2
3
4
stu = {"name": "lihua", "age": 18}
classes = ["class1", "class2"]

print("Name: {s['name']}, Hobby: {c[0]}".format(s=stu, c=classes))
  • 可以调用对象方法:可以调用无参数的对象方法
1
2
text = "hello world"
print("{.upper()}".format((text)))
  • 自定义格式化逻辑:在类中实现__format__方法,可以自定义对象的格式化行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius
    
    # 自定义格式化:支持 'c'(摄氏度)和 'f'(华氏度)
    def __format__(self, format_spec):
        if format_spec == 'f':
            fahrenheit = self.celsius * 9/5 + 32
            return f"{fahrenheit:.1f}°F"
        else:  # 默认摄氏度
            return f"{self.celsius:.1f}°C"

temp = Temperature(25)
print("Temp: {t:c}".format(t=temp))  # 输出:Temp: 25.0°C
print("Temp: {t:f}".format(t=temp))  # 输出:Temp: 77.0°F

f-string

格式化字符字面值,在字符串前加fF前缀,在字符串中用{}嵌入变量或表达式

它的性能更快,安全性更高

基本语法与格式控制

f"模板字符串, {变量/表达式}会被替换为值"

1
2
3
name = 'lihua'
age = 18
print(f"name: {name}, age: {age}")

格式控制语法:{表达式:格式规范}

与format相同的格式规范

高级特性

f-string 支持在{}中嵌入任意合法的Python表达式,包括函数调用、三目运算等

  • 函数调用:直接在占位符中调用函数
1
2
3
4
def hello(name):
    return f"hello {name}"
name = 'lihua'
print(f"{hello(name)}")
  • 三目运算:
1
2
score = 80
print(f{'pass' if score>=60 else 'failed'})
  • 嵌套结构访问:
1
2
3
stu = {"name": "lihua", "age": 18}
classes = ["class1", "class2"]
print(f"student: {stu['name']}, class: {class[0]}")
  • 多行f-string:使用三引号支持多行模板
1
2
3
4
5
6
7
8
9
name = 'lihua'
age = 18
score = 80
bio = f"""
student info:
- name: {name}
- age: {age}
- score: {'pass' if score>=60 else 'failed'}
"""

异常处理

Python对异常的表现

当发生异常时,python会生成一个异常对象,包含错误类型、描述和发生位置

若未捕获,程序终止并打印回溯信息(Traceback),显示异常类型和发生位置

常见异常

常见异常类型如下:

异常类型 说明
SyntaxError 语法错误
NameError 使用了未定义的变量
TypeError 操作或函数应用于不适当类型
ValueError 参数类型正确,但值不合法
IndexError 索引超出序列范围
KeyError 字典中不存在指定键
AttributeError 对象没有指定属性或方法
ZeroDivisionError 除数为 0
FileNotFoundError 文件不存在
IOError / OSError 输入输出操作错误
ImportError 导入模块失败
ModuleNotFoundError 找不到指定模块
EOFError 输入到达文件末尾
RuntimeError 一般运行时错误
MemoryError 内存不足
OverflowError 数值运算结果超出范围
RecursionError 递归层数超过限制
AssertionError assert 断言失败
StopIteration 迭代器没有更多元素
KeyboardInterrupt 用户按下 Ctrl+C 中断程序

处理异常的语法

Python使用try-catch语句块捕获并处理异常,结构如下:

1
2
3
4
5
6
7
8
9
10
try:
    risk_operation()
except 异常类型1:
    # 处理异常1的代码
except 异常类型2 as e:
    # 处理异常2的代码,e是异常对象
else:
    # 无异常时执行的代码(可选)
finally:
    # 无论是否有异常都执行的代码(可选)

获取异常信息

使用as e捕获异常对象,进而提取异常详情

1
2
3
4
5
6
try:
    int('a')
except ValueError as e:
    print("异常类型: ", type(e))
    print("异常描述: ", e)
    print("异常参数: ", e.args)

捕获多个异常

  • 一个try后可以接多个catch,处理不同异常
  • 使用except Exception捕获所有非系统退出类异常

异常的主动触发与传递

主动触发异常

使用raise可以手动触发异常,用于验证合法性或标记未实现的功能

1
2
3
4
5
6
7
8
9
def register(username):
    if len(username) < 3:
        # 主动触发 ValueError
        raise ValueError(f"用户名 '{username}' 太短,至少需要3个字符")
    print(f"'{username}' 注册成功")

try:
    register("ab")  # 长度不足,触发异常
except ValueError as e:

重新抛出异常

捕获异常后,若无法处理,可以用raise重新抛出,让上层代码处理,此时raise不带参数

1
2
3
4
5
6
7
8
9
10
11
12
ef read_data(filename):
    try:
        with open(filename, "r") as f:
            return f.read()
    except FileNotFoundError as e:
        print(f"read_data 函数捕获到错误:{e}")
        raise  # 重新抛出异常,让调用者处理

try:
    data = read_data("nonexist.txt")
except FileNotFoundError as e:
    print(f"主程序处理错误:{e}")

异常的传递

若函数内发生异常且未捕获,异常会向上传递至调用者,直至被捕获或程序崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def f3():
    print("进入f3")
    x = int("abc")    # ValueError
    print("离开f3")

def f2():
    print("进入f2")
    f3()
    print("离开f2")

def f1():
    print("进入f1")
    f2()
    print("离开f1")

try:
    f1()
except ValueError as e:
    print("捕获异常:", e)

结果为:

1
2
3
4
进入f1
进入f2
进入f3
捕获异常: invalid literal for int() with base 10: 'abc'

如果想要在中间层处理后继续传递,使用raise

自定义异常

定义

当内置异常无法满足要求时,可以继承Exception类自定义异常

1
2
3
4
5
6
7
8
9
10
11
# 定义自定义异常(继承 Exception)
class InvalidAgeError(Exception):
    """当年龄不合法时触发的异常"""
    def __init__(self, age, message="年龄必须在 0-120 之间"):
        self.age = age
        self.message = message
        super().__init__(self.message)  # 调用父类构造函数

    # 可选:自定义异常描述
    def __str__(self):
        return f"{self.message},实际输入:{self.age}"

触发

1
2
3
4
5
6
7
8
9
10
def check_age(age):
    if not (0 <= age <= 120):
        # 触发自定义异常
        raise InvalidAgeError(age)
    print(f"年龄 {age} 合法")

try:
    check_age(150)  # 超出范围,触发异常
except InvalidAgeError as e:
    print("检查失败:", e)  # 输出:检查失败:年龄必须在 0-120 之间,实际输入:150

继承

自定义异常可以继承,用于创建更细分的异常类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 基础异常
class ValidationError(Exception):
    pass

# 细分异常(继承自 ValidationError)
class TooSmallError(ValidationError):
    pass

class TooLargeError(ValidationError):
    pass

def validate_number(n):
    if n < 0:
        raise TooSmallError(f"{n} 不能小于 0")
    if n > 100:
        raise TooLargeError(f"{n} 不能大于 100")
    print(f"{n} 验证通过")

try:
    validate_number(-5)
except TooSmallError as e:
    print("处理过小错误:", e)
except TooLargeError as e:
    print("处理过大错误:", e)
except ValidationError as e:  # 捕获所有子类异常
    print("处理其他验证错误:", e)

文件操作

基础文件操作

open()函数是文件操作的入口,用于打开文件返回文件对象,语法如下:

1
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
  • file是文件路径,传入字符串或Path对象
  • mode是打开模式,决定读写权限和文件类型
  • encoding是文本模式下的编码格式

文件打开模式

  • 只读:r
  • 只写:w
  • 追加:a
  • 读写(保留原内容):r+
  • 读写(清空原内容):w+
  • 追加+读:a+

基础操作

需要遵循“打开->操作->关闭”的流程,防止资源泄露

一般使用with语句(即上下文管理器)自动关闭文件,无需手动关闭

1
2
3
4
5
6
7
# 写入
with open('test.txt', 'w', encoding='utf-8') as f:
    f.write('hello world!\n')
# 读取
with open('test.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content)

二进制文件

二进制文件需要在操作后加一个b(有加号的在加号前)

1
2
3
with open('test.jpg', 'rb') as src, open('copy.jpg', 'wb') as dst:
    data = src.read()
    dst.write(data)

文件读取方式

方法 功能说明 适用场景
read() 无参:读取全部内容;
有参 n:读取至多 n 字节(二进制模式常用)
小文件(一次性处理全文);
二进制大文件分块处理(如网络传输、分片复制)
readline() 读取一行内容(含换行符 \n),支持指定字节限制 limit 按行处理文件(如日志解析、CSV逐行读取);超大行文件(指定 limit 控制内存)
readlines() 读取所有行,返回列表(每行作为元素,含换行符 \n 中等大小文件,需按行索引访问(如按行号提取内容)或批量处理所有行
迭代文件对象 (for line in f) 自动逐行读取,循环内每次返回一行(含换行符 \n),底层调用 readline() 大/超大文件(内存友好,无需一次性加载全部内容),仅需顺序处理行数

文件写入方式

方法 功能说明 适用场景
write(str) 写入字符串,返回写入的字符数 单次写入一个完整的字符串;需要精确控制写入内容(如构建自定义格式)
writelines(seq) 写入字符串序列(列表/元组等),不自动添加换行符 批量写入多个字符串;当序列中的每个元素己包含换行符,或不需要分隔符时
print(..., file=f) print 函数写入,可自动添加换行符(end 参数控制) 快速写入并自动换行;需要灵活控制输出格式(如自定义分隔符、末尾字符)

文件指针

方法/属性 功能说明
tell() 返回当前指针位置(字节数)
seek(offset, whence) 移动指针到指定位置:offset 偏移量(正数向后,负数向前);
whence 基准位置(0:文件开头,1:当前位置,2:文件末尾)

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
with open('test.txt', 'w+', encoding='utf-8') as f:
    f.write('0123456789')
    print('写后指针位置:', f.tell()) # 指针此时在文件末尾,输出10
    
    # 从当前位置移动
    f.seek(2,1) # 从当前位置开始计算,移动两位
    print(f.read())
    print(f.tell())
    
    # 从文件末尾移动
    f.seek(-3,2) # 从末尾开始计算,移动三位
    print(f.read())

文件属性和元数据

通过ospathlib库可以获取文件的元数据

  • Path():路径类,可以便捷创建路径
  • .exists():判断文件是否存在
  • .is_file():判断是否为文件
  • .is_dir():判断是否为目录
  • Path().mkdir(parents=True, exist_ok=True):创建目录,parents为自动创建上层目录,exist——ok为存在时不报错
  • .stat().st_size:文件大小(字节)
  • .stat().st_ctime:创建时间
  • .stat().st_mtime:最后修改时间