4. Python基础快速回顾(二):函数定义与参数、模块与包导入、文件读写(CSV/JSON)、异常处理基础
本章是Python基础快速回顾的第二部分,聚焦于构建可复用代码、组织项目结构、处理外部数据以及应对运行时错误的核心技能。这些知识是后续开发额度模型评分沙盘时,编写模块化、健壮且可维护代码的基石。
4.1 函数定义与参数
函数是组织代码、避免重复、提升可读性的基本单元。在评分沙盘中,我们会将数据清洗、特征计算、模型评分等逻辑封装成独立的函数。
4.1.1 函数定义与调用
使用 def 关键字定义函数,后跟函数名、参数列表和冒号。函数体需缩进。
def calculate_score(income, debt):
"""根据收入和负债计算一个简单的信用分数(文档字符串)"""
if income <= 0:
return 0
ratio = debt / income
if ratio < 0.3:
return 800
elif ratio < 0.6:
return 600
else:
return 300
# 调用函数
score = calculate_score(10000, 2000)
print(score) # 输出: 800
4.1.2 参数类型详解
Python函数的参数机制非常灵活,理解不同参数类型是编写通用函数的关键。
| 参数类型 | 定义方式 | 调用示例 | 说明 |
|---|---|---|---|
| 位置参数 | def func(a, b): |
func(1, 2) |
按顺序传递,必须提供 |
| 默认参数 | def func(a, b=10): |
func(1) 或 func(1, 5) |
调用时可省略,提供默认值 |
| 关键字参数 | def func(a, b): |
func(b=2, a=1) |
通过参数名指定,顺序可调 |
| 可变位置参数 | def func(*args): |
func(1, 2, 3) |
接收任意数量位置参数,打包为元组 |
| 可变关键字参数 | def func(**kwargs): |
func(name='Alice', age=30) |
接收任意数量关键字参数,打包为字典 |
实战提示:在评分沙盘中,
*args 和 **kwargs 常用于编写装饰器或封装通用数据处理函数,例如一个可以接受任意特征列名的评分函数。
4.1.3 作用域与 return
函数内部定义的变量默认为局部变量,外部无法访问。使用 global 关键字可在函数内修改全局变量,但应谨慎使用。函数通过 return 返回值,不写 return 则返回 None。
global_threshold = 600
def check_approval(score):
# 尝试修改全局变量(不推荐)
# global global_threshold
# global_threshold = 650
return score >= global_threshold
print(check_approval(700)) # 输出: True
4.2 模块与包导入
随着项目增长,将函数和变量分散到不同文件中是必要的。模块(单个 .py 文件)和包(包含 __init__.py 的文件夹)是Python组织代码的标准方式。
4.2.1 导入语法
| 导入方式 | 代码示例 | 使用方式 | 适用场景 |
|---|---|---|---|
| 直接导入模块 | import math |
math.sqrt(16) |
标准库或第三方库 |
| 导入特定对象 | from math import sqrt |
sqrt(16) |
仅需模块中少数函数 |
| 导入并起别名 | import pandas as pd |
pd.DataFrame() |
简化长模块名(如numpy, pandas) |
| 导入所有对象 | from math import * |
sqrt(16) |
不推荐,易导致命名冲突 |
4.2.2 包结构示例
在评分沙盘项目中,我们可能会这样组织代码:
scorecard_project/
├── main.py # 主程序入口
├── data/
│ ├── __init__.py
│ ├── loader.py # 数据加载函数
│ └── preprocessor.py # 数据预处理函数
├── models/
│ ├── __init__.py
│ ├── score_calculator.py # 评分计算函数
│ └── validator.py # 模型验证函数
└── utils/
├── __init__.py
└── config.py # 配置文件读取
导入实践:在
main.py 中,我们可以这样导入:from data.loader import load_application_datafrom models.score_calculator import calculate_credit_score
4.3 文件读写:CSV与JSON
评分沙盘的数据通常以CSV(结构化表格)和JSON(嵌套配置/结果)格式存储。Python内置的 csv 和 json 模块提供了便捷的读写接口。
4.3.1 CSV文件操作
CSV是最常见的表格数据格式。使用 csv.reader 和 csv.writer 进行读写。
import csv
# 写入CSV
with open('applicants.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['id', 'income', 'debt', 'score'])
writer.writerow([1, 50000, 10000, 700])
writer.writerow([2, 30000, 15000, 550])
# 读取CSV
with open('applicants.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
for row in reader:
print(row) # 每行是一个列表
DictReader/DictWriter:使用
csv.DictReader 和 csv.DictWriter 可以将行映射为字典,通过列名访问数据,代码更可读。
4.3.2 JSON文件操作
JSON常用于存储配置、模型参数或API响应。使用 json.dump 和 json.load 进行读写。
import json
# 写入JSON
config = {
"model_version": "v2.1",
"features": ["income", "debt", "age"],
"thresholds": {"low": 300, "medium": 600, "high": 800}
}
with open('config.json', 'w', encoding='utf-8') as f:
json.dump(config, f, indent=4, ensure_ascii=False)
# 读取JSON
with open('config.json', 'r', encoding='utf-8') as f:
loaded_config = json.load(f)
print(loaded_config['thresholds']['medium']) # 输出: 600
4.4 异常处理基础
程序运行中难免遇到错误(如文件不存在、类型错误、除零错误)。异常处理让程序能优雅地处理这些情况,而不是直接崩溃。
4.4.1 try-except 结构
将可能出错的代码放在 try 块中,捕获并处理异常。
try:
with open('missing_file.csv', 'r') as f:
data = f.read()
score = 100 / 0
except FileNotFoundError:
print("错误:文件未找到,使用默认配置。")
except ZeroDivisionError:
print("错误:除零操作,请检查数据。")
except Exception as e:
print(f"发生未知错误:{e}")
else:
print("文件读取成功,无异常发生。")
finally:
print("无论是否异常,此块都会执行(如关闭资源)。")
4.4.2 常见异常类型
| 异常类型 | 触发场景 | 评分沙盘中的典型场景 |
|---|---|---|
FileNotFoundError |
尝试打开不存在的文件 | 加载历史申请数据时路径错误 |
ValueError |
函数收到类型正确但值不合适的参数 | 将字符串 "abc" 转换为整数 |
TypeError |
对不支持该操作的类型执行操作 | 对 None 值调用 len() |
KeyError |
访问字典中不存在的键 | 从JSON配置中读取缺失的字段 |
ZeroDivisionError |
除数为零 | 计算负债收入比时收入为零 |
4.4.3 自定义异常与 raise
当业务逻辑出现问题时,可以主动抛出异常。
class InvalidScoreError(Exception):
"""自定义异常:分数超出有效范围"""
pass
def validate_score(score):
if not (0 <= score <= 1000):
raise InvalidScoreError(f"分数 {score} 不在 0-1000 范围内")
return True
try:
validate_score(1200)
except InvalidScoreError as e:
print(f"数据验证失败:{e}")
避坑指南:不要捕获所有异常而不做任何处理(如
except: pass),这会隐藏真正的bug。尽量捕获具体的异常类型,并在 except 块中记录日志或给出有意义的提示。
4.5 综合案例:安全的评分数据加载器
将本章知识点融合,编写一个健壮的数据加载函数,用于评分沙盘项目。
import csv
import json
import os
class DataLoadError(Exception):
"""数据加载自定义异常"""
pass
def load_score_data(csv_path, config_path):
"""
安全加载评分数据与配置。
参数:
csv_path: 申请人数据CSV文件路径
config_path: 评分配置JSON文件路径
返回:
(applicants_list, config_dict) 元组
"""
applicants = []
config = {}
# 加载配置
try:
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
except FileNotFoundError:
print(f"警告:配置文件 {config_path} 未找到,使用默认配置。")
config = {"threshold": 600}
except json.JSONDecodeError as e:
raise DataLoadError(f"配置文件格式错误:{e}")
# 加载CSV数据
try:
with open(csv_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
# 尝试转换数值字段
row['income'] = float(row.get('income', 0))
row['debt'] = float(row.get('debt', 0))
applicants.append(row)
except (ValueError, TypeError) as e:
print(f"跳过无效数据行 {row.get('id', 'unknown')}: {e}")
except FileNotFoundError:
raise DataLoadError(f"数据文件 {csv_path} 不存在。")
except Exception as e:
raise DataLoadError(f"读取CSV时发生未知错误:{e}")
return applicants, config
# 使用示例
try:
data, cfg = load_score_data('applicants.csv', 'config.json')
print(f"成功加载 {len(data)} 条记录,阈值为 {cfg.get('threshold')}")
except DataLoadError as e:
print(f"程序终止:{e}")
本章核心收获:
- 掌握
def定义函数及位置、默认、可变参数的使用。 - 理解模块与包的组织方式,熟练使用
import语句。 - 能够使用
csv和json模块进行文件读写。 - 运用
try-except-else-finally编写健壮的异常处理代码。