Python 使用中学习各种语法错误与异常处理,有助于我们快速定位问题

1. 语法错误 (Syntax Errors)

语法错误是代码编写时不符合 Python 语法规则的错误,在程序运行前就会被解释器检测到。

1.1、常见语法错误类型

# 1. 缺少冒号
if True  # 错误:缺少冒号
    print("Hello")

# 2. 缩进错误
def func():
print("Hello")  # 错误:函数体内缺少缩进

# 3. 括号不匹配
print("Hello"  # 错误:缺少右括号

# 4. 使用关键字作为变量名
class = "Math"  # 错误:class 是关键字

# 5. 无效的语法结构
for i in range(5)
    print(i)  # 错误:for 循环缺少冒号

2. 异常 (Exceptions)

异常是程序运行时发生的错误,即使语法正确也可能发生。

常见异常类型

    # 1. ZeroDivisionError: 除零错误
    result = 10 / 0

    # 2. TypeError: 类型错误
    result = "hello" + 5

    # 3. ValueError: 值错误
    number = int("abc")

    # 4. IndexError: 索引错误
    my_list = [1, 2, 3]
    item = my_list[5]

    # 5. KeyError: 键错误
    my_dict = {"a": 1, "b": 2}
    value = my_dict["c"]

    # 6. FileNotFoundError: 文件未找到
    with open("nonexistent.txt", "r") as f:
        content = f.read()

    # 7. AttributeError: 属性错误
    x = 10
    x.append(5)

3. 异常处理机制

3.1 try-except 基础

try:
    # 可能引发异常的代码
    number = int(input("请输入一个数字: "))
    result = 100 / number
    print(f"结果是: {result}")
except ValueError:
    print("错误:请输入有效的数字!")
except ZeroDivisionError:
    print("错误:不能除以零!")

3.2 捕获多个异常

try:
    # 可能引发异常的代码
    file = open("data.txt", "r")
    data = file.read()
    number = int(data.strip())
    result = 100 / number
except (FileNotFoundError, ValueError, ZeroDivisionError) as e:
    print(f"发生错误: {e}")
    print(f"错误类型: {type(e).__name__}")

3.3 else 和 finally 子句

def read_and_process_file(filename):
    try:
        file = open(filename, "r")
        data = file.read()
        number = int(data.strip())
    except FileNotFoundError:
        print("文件不存在")
        return None
    except ValueError:
        print("文件内容不是有效数字")
        return None
    else:
        # 如果没有异常发生,执行这里的代码
        print("文件读取成功")
        return number
    finally:
        # 无论是否发生异常,都会执行
        if 'file' in locals() and not file.closed:
            file.close()
            print("文件已关闭")

# 测试
result = read_and_process_file("data.txt")

3.4 捕获所有异常

try:
    # 可能引发异常的代码
    risky_operation()
except Exception as e:
    print(f"发生未知错误: {e}")
    # 记录日志或进行其他处理

4. 抛出异常 (Raising Exceptions)

4.1 使用 raise 抛出异常

def validate_age(age):
    if age < 0:
        raise ValueError("年龄不能为负数")
    if age > 150:
        raise ValueError("年龄不能超过150岁")
    return True

try:
    validate_age(-5)
except ValueError as e:
    print(f"验证失败: {e}")

4.2 重新抛出异常

def process_data(data):
    try:
        # 尝试处理数据
        result = int(data)
    except ValueError:
        print("数据格式错误,记录日志后重新抛出异常")
        # 记录日志后重新抛出原始异常
        raise

try:
    process_data("abc")
except ValueError as e:
    print(f"外层捕获到异常: {e}")

5. 自定义异常

class InsufficientFundsError(Exception):
    """自定义异常:余额不足"""
    
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        self.message = f"余额不足: 当前余额 {balance},需要 {amount}"
        super().__init__(self.message)

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance
    
    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount
        return self.balance

# 使用自定义异常
account = BankAccount(100)
try:
    account.withdraw(200)
except InsufficientFundsError as e:
    print(f"取款失败: {e}")

6. 实际案例分析

6.1、文件处理异常处理

import os

def safe_file_operations(filename):
    """
    安全的文件操作函数,包含完整的异常处理
    """
    file = None
    try:
        # 检查文件是否存在
        if not os.path.exists(filename):
            raise FileNotFoundError(f"文件 {filename} 不存在")
        
        # 尝试打开文件
        file = open(filename, 'r', encoding='utf-8')
        
        # 读取文件内容
        content = file.read()
        
        # 处理内容
        if not content:
            raise ValueError("文件内容为空")
            
        processed_content = content.upper()
        
        # 写入新文件
        output_filename = f"processed_{filename}"
        with open(output_filename, 'w', encoding='utf-8') as output_file:
            output_file.write(processed_content)
            
        print(f"文件处理完成,输出文件: {output_filename}")
        return processed_content
        
    except FileNotFoundError as e:
        print(f"文件错误: {e}")
        return None
    except PermissionError as e:
        print(f"权限错误: {e}")
        return None
    except UnicodeDecodeError as e:
        print(f"编码错误: {e}")
        return None
    except ValueError as e:
        print(f"数据错误: {e}")
        return None
    except Exception as e:
        print(f"未知错误: {e}")
        return None
    finally:
        # 确保文件被关闭
        if file and not file.closed:
            file.close()
            print("文件已安全关闭")

# 测试
safe_file_operations("test.txt")

6.2、 API 调用异常处理

import requests
import time

class APIClient:
    def __init__(self, base_url, max_retries=3):
        self.base_url = base_url
        self.max_retries = max_retries
        self.session = requests.Session()
    
    def make_request(self, endpoint, params=None, timeout=10):
        """
        安全的 API 请求方法,包含重试机制
        """
        url = f"{self.base_url}/{endpoint}"
        
        for attempt in range(self.max_retries):
            try:
                response = self.session.get(url, params=params, timeout=timeout)
                response.raise_for_status()  # 如果状态码不是200,抛出HTTPError
                return response.json()
                
            except requests.exceptions.Timeout:
                print(f"请求超时,第 {attempt + 1} 次重试...")
                if attempt == self.max_retries - 1:
                    raise Exception("API 请求超时,已达到最大重试次数")
                    
            except requests.exceptions.ConnectionError:
                print(f"连接错误,第 {attempt + 1} 次重试...")
                if attempt == self.max_retries - 1:
                    raise Exception("无法连接到服务器")
                    
            except requests.exceptions.HTTPError as e:
                if response.status_code == 404:
                    raise Exception("请求的资源不存在")
                elif response.status_code == 500:
                    print(f"服务器错误,第 {attempt + 1} 次重试...")
                    if attempt == self.max_retries - 1:
                        raise Exception("服务器内部错误")
                else:
                    raise Exception(f"HTTP 错误: {e}")
                    
            except requests.exceptions.RequestException as e:
                raise Exception(f"请求异常: {e}")
            
            # 等待后重试
            time.sleep(2 ** attempt)  # 指数退避
        
        raise Exception("未知错误")

# 使用示例
try:
    client = APIClient("https://api.example.com")
    data = client.make_request("users", {"id": 123})
    print("API 调用成功:", data)
except Exception as e:
    print(f"API 调用失败: {e}")

6.3、数据库操作异常处理

import sqlite3
import logging

class DatabaseManager:
    def __init__(self, db_path):
        self.db_path = db_path
        self.setup_logging()
    
    def setup_logging(self):
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s'
        )
        self.logger = logging.getLogger(__name__)
    
    def execute_query(self, query, params=None, fetch=False):
        """
        执行数据库查询,包含完整的异常处理
        """
        connection = None
        try:
            # 连接数据库
            connection = sqlite3.connect(self.db_path)
            cursor = connection.cursor()
            
            # 执行查询
            if params:
                cursor.execute(query, params)
            else:
                cursor.execute(query)
            
            # 如果是写操作,提交事务
            if query.strip().upper().startswith(('INSERT', 'UPDATE', 'DELETE')):
                connection.commit()
                self.logger.info("数据库操作已提交")
            
            # 如果需要获取结果
            if fetch:
                result = cursor.fetchall()
                return result
            else:
                return cursor.rowcount
                
        except sqlite3.OperationalError as e:
            self.logger.error(f"数据库操作错误: {e}")
            if connection:
                connection.rollback()
            raise Exception(f"数据库操作失败: {e}")
            
        except sqlite3.IntegrityError as e:
            self.logger.error(f"数据完整性错误: {e}")
            if connection:
                connection.rollback()
            raise Exception(f"数据违反完整性约束: {e}")
            
        except sqlite3.DatabaseError as e:
            self.logger.error(f"数据库错误: {e}")
            if connection:
                connection.rollback()
            raise Exception(f"数据库错误: {e}")
            
        except Exception as e:
            self.logger.error(f"未知错误: {e}")
            if connection:
                connection.rollback()
            raise Exception(f"操作失败: {e}")
            
        finally:
            # 确保连接被关闭
            if connection:
                connection.close()
                self.logger.info("数据库连接已关闭")

# 使用示例
def manage_user_database():
    db = DatabaseManager("test.db")
    
    # 创建表
    create_table_sql = """
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT UNIQUE NOT NULL,
        age INTEGER CHECK(age >= 0)
    )
    """
    
    try:
        db.execute_query(create_table_sql)
        print("表创建成功")
        
        # 插入数据
        insert_sql = "INSERT INTO users (name, email, age) VALUES (?, ?, ?)"
        db.execute_query(insert_sql, ("Alice", "alice@example.com", 25))
        print("数据插入成功")
        
        # 查询数据
        select_sql = "SELECT * FROM users WHERE age > ?"
        users = db.execute_query(select_sql, (20,), fetch=True)
        print("查询结果:", users)
        
    except Exception as e:
        print(f"数据库操作失败: {e}")

# 运行示例
manage_user_database()

7. 最佳实践总结

  1. 具体异常优先: 捕获具体的异常类型,而不是通用的 Exception
  2. 避免空 except: 不要使用空的 except 块,至少要记录日志
  3. 资源清理: 使用 finally上下文管理器确保资源被正确释放
  4. 异常信息明确: 提供清晰的错误信息,便于调试
  5. 适当重试: 对于临时性错误,实现适当的重试机制
  6. 日志记录: 记录异常信息,便于问题追踪
  7. 自定义异常: 为业务逻辑错误创建自定义异常类型

通过合理的异常处理,可以提高我们的程序的健壮性和可维护性。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐