深圳融克迪特科技有限公司 Logo,金融科技,量化交易,软件开发

深圳融克迪特科技有限公司

RONG CREDIT TECHNOLOGY CO., LTD.

基础入门

【Python 系列 第7讲】异常处理:避开空值和除零

本讲用最小样本演示空字符串、类型转换失败和除零风险如何打断收益率脚本,并通过 try/except 与条件判断做基础防护,让初学者开始建立先清洗、再计算的处理习惯。

2026-04-26 智铨研究 阅读时长 7 分钟

目录

  1. 本节目标
  2. 为什么要专门补一讲异常处理
  3. 故意准备一组带问题的价格样本
  4. 四步避开空值和除零
  5. 先把价格尝试转成浮点数
  6. 确认清洗后的列表再进入收益率计算
  7. 在计算收益率前判断上一日价格是否为 0
  8. 把异常和保护逻辑一起打印检查
  9. 怎样判断异常处理真的起作用了
  10. 空字符串没有进入清洗后的价格列表
  11. 清洗后列表里全是浮点数
  12. 计算阶段没有因除零直接报错中断
  13. 结果条数不会超过可计算区间数
  14. 异常处理是不是会把错误“藏起来”
  15. 为什么不是一报错就停下来
  16. 为什么这里同时用了try/except和if
  17. 遇到坏值一定都要跳过吗
  18. 如果当前价格是 0 呢
  19. 哪些情况仍然算本讲完成
  20. 写一个带保护的收益率函数
  21. 第 7 讲建立的是“先防守再计算”的意识
  22. 完成标准
  23. 系列衔接
  24. 风险揭示与免责声明

Python · 入门短课

  1. 第 1 讲【Python 系列 第1讲】Python环境检查:先打印一组收盘价
  2. 第 2 讲【Python 系列 第2讲】列表和字典:装下价格与日期
  3. 第 3 讲【Python 系列 第3讲】for循环:批量计算日收益率
  4. 第 4 讲【Python 系列 第4讲】函数封装:写一个收益率计算器
  5. 第 5 讲【Python 系列 第5讲】条件判断:筛出上涨交易日
  6. 第 6 讲【Python 系列 第6讲】CSV读写:保存再读回价格表
  7. 第 7 讲【Python 系列 第7讲】异常处理:避开空值和除零
  8. 第 8 讲【Python 系列 第8讲】生成一份行情摘要

【Python 系列 第7讲】异常处理:避开空值和除零

1. 本节目标

第 7 讲开始处理 starter 系列里最常见的一类“运行时事故”。目标很明确:在计算收益率前,先挡住空值和除零这两种最容易让初学者脚本直接报错的情况。前几讲默认数据都很干净,但真实样本里,空字符串、缺失价格、上一日价格为 0 都可能出现,所以这里需要先补上一层防守。

学完这一讲后,你可以直接完成下面几件事:

  1. 看懂为什么空值和除零会让收益率计算失败。
  2. 用条件判断和 try/except 做最小保护。
  3. 在遇到坏样本时跳过并继续处理后面的数据。

第 7 讲的重点不是把所有异常都讲完,而是先守住最常见、最容易验证的两个坑。

2. 为什么要专门补一讲异常处理

如果你只在非常干净的练习样本上写代码,很容易形成一种错觉:只要公式没写错,脚本就会一直顺着跑下去。现实里并不是这样。真实数据里最常见的中断,往往不是高深模型错误,而是非常基础的脏值问题。比如:

  1. 某一天的价格缺了,结果字符串根本转不成浮点数。
  2. 前一天价格写成了 0,收益率一除就报错。
  3. 某条记录写成空字符串,循环跑到一半直接中断。

所以第 7 讲重点不在于把程序写得花哨,更在于让你的入门脚本第一次具备一点“碰到坏数据还能继续往下走”的能力。

3. 故意准备一组带问题的价格样本

raw_prices = [12.34, '12.80', '', 0, 13.10]

这组样本里包含三种常见情况:

  1. 正常浮点数 12.34
  2. 可转换的字符串 '12.80'
  3. 空字符串 ''
  4. 会引发除零问题的 0

故意把问题放进样本里,能让你更清楚地看到防护逻辑有没有生效。

4. 四步避开空值和除零

这四步要解决的是两个不同层面的风险:先挡住无法转成数值的坏输入,再挡住计算阶段会让分母失效的异常值。

5. 先把价格尝试转成浮点数

clean_prices = []

for item in raw_prices:
    try:
        clean_prices.append(float(item))
    except ValueError:
        print(f"跳过无法转换的值: {item}")

这一步先把明显不是数值的项挡掉。比如空字符串在转 float 时会报 ValueError,这里直接跳过即可。

6. 确认清洗后的列表再进入收益率计算

print(clean_prices)

清洗后,你应该看到类似 [12.34, 12.8, 0.0, 13.1] 这样的结果。注意,空字符串已经被排除了,但 0.0 还留着,因为它是合法数值,只是后面不能作为分母。

7. 在计算收益率前判断上一日价格是否为 0

safe_returns = []

for i in range(1, len(clean_prices)):
    prev_price = clean_prices[i - 1]
    curr_price = clean_prices[i]

    if prev_price == 0:
        print(f"跳过除零风险位置: {i}")
        continue

    safe_returns.append((curr_price - prev_price) / prev_price)

这里最关键的是 continue。一旦发现上一日价格为 0,就跳过这一段,而不是让整个脚本直接报错退出。

8. 把异常和保护逻辑一起打印检查

print(clean_prices)
print(safe_returns)
for ret in safe_returns:
    print(f"安全收益率: {ret:.2%}")

做完这一步以后,你已经拥有了一个比前几讲更稳的小流程:先清洗,再判断,再计算。

9. 怎样判断异常处理真的起作用了

这里的验证重点不是结果多漂亮,而是脚本有没有在碰到坏值后继续跑完,以及坏值有没有被挡在合适的位置上。

10. 空字符串没有进入清洗后的价格列表

assert '' not in clean_prices

11. 清洗后列表里全是浮点数

assert all(isinstance(x, float) for x in clean_prices)

12. 计算阶段没有因除零直接报错中断

如果脚本能顺利运行到最后并打印 safe_returns,就说明最基本的除零防护已经生效。

13. 结果条数不会超过可计算区间数

assert len(safe_returns) <= len(clean_prices) - 1

只要这些条件成立,就说明你已经把最容易让入门脚本中断的两个坑挡住了。

14. 异常处理是不是会把错误“藏起来”

异常处理确实会改变程序的默认失败方式,所以更需要把“为什么跳过、跳过了什么”说清楚,而不是无声吞掉问题。

15. 为什么不是一报错就停下来

如果你是在教学样本里排查单个问题,停下来当然有价值。但如果你已经知道某类坏值是可能出现的,就应该有能力跳过它,让程序继续处理后面的样本。

16. 为什么这里同时用了try/except和if

因为它们处理的问题不同。try/except 主要挡“转类型时出错”,if prev_price == 0 主要挡“逻辑上不能做除法”。

17. 遇到坏值一定都要跳过吗

不一定。真实项目里有时会记录日志、有时会补默认值。但 starter 系列先用“跳过并打印提示”最容易理解和验证。

18. 如果当前价格是 0 呢

那收益率可能是 -100%,并不一定非法。真正危险的是分母,也就是前一天价格为 0。

19. 哪些情况仍然算本讲完成

  1. 你可以只处理空字符串和 0,不必一次把所有脏值都覆盖。
  2. 当前不要求自定义异常类,第 7 讲先掌握最基本的保护方式。
  3. 你不一定非要打印每一次跳过提示,但至少要能看出程序没有中断。
  4. 若样本里刚好没有坏值,逻辑照样可以跑通,只是这节课的意义会没那么明显。

20. 写一个带保护的收益率函数

def calc_safe_returns(raw_prices):
    clean_prices = []
    for item in raw_prices:
        try:
            clean_prices.append(float(item))
        except ValueError:
            continue

    returns = []
    for i in range(1, len(clean_prices)):
        prev_price = clean_prices[i - 1]
        curr_price = clean_prices[i]
        if prev_price == 0:
            continue
        returns.append((curr_price - prev_price) / prev_price)
    return returns


print(calc_safe_returns([12.34, '12.80', '', 0, 13.10]))

这类函数虽然很小,但它让你的脚本从“只能处理完美样本”进了一步,变成“遇到明显坏值也不会立刻崩”。

21. 第 7 讲建立的是“先防守再计算”的意识

量化入门里一个很重要的转折点,就是你开始意识到:不是所有数据都值得直接拿来算。第 7 讲的价值就在这里。它让你第一次主动在计算前加一道门,而不是等程序出错了再回头补救。

这种“先防守再计算”的意识,后面无论你用的是标准库、pandas 还是回测框架,都会一直有用。

22. 完成标准

如果你现在已经能挡住空值转换错误,并在上一日价格为 0 时跳过该次收益率计算,让脚本继续跑完,那第 7 讲就算完成。

23. 系列衔接

本讲是《Python量化入门短课》的第 7/8 讲,当前主题是《异常处理:避开空值和除零》。

上一讲:第 6 讲《CSV读写:保存再读回价格表》。

下一讲:第 8 讲《生成一份行情摘要》。

后续安排:这是本系列最后一讲前的准备,下一讲会把前面得到的价格、收益率和上涨日结果整理成一份可读摘要。

24. 风险揭示与免责声明

风险揭示与免责声明

本页面内容仅用于量化研究与技术交流,旨在展示研究方法与流程,不构成对任何金融产品、证券或衍生品的要约、招揽、推荐或保证。

本文所涉历史数据、回测结果与示例参数不代表未来表现,也不应作为投资决策依据。

市场存在波动、流动性与执行偏差等不确定性,任何策略均可能出现收益波动或阶段性失效。

读者应结合自身风险承受能力进行独立判断,并在必要时咨询持牌专业机构意见。