前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 静态类型检查入门

Python 静态类型检查入门

作者头像
初代庄主
发布2024-04-22 16:43:46
520
发布2024-04-22 16:43:46
举报
文章被收录于专栏:初代庄主初代庄主

问题

我写的代码主要是偏量化交易,这行啊对数值的准确性要求是非常的高,毕竟交易的都是真金白银。但是计算机有时候“不靠谱”,比如 0.2 * 100 用眼睛看一下都知道结果是 20 ;用计算机来算结果就不一定了,先算个 19.99xxx 的给大家看下。

代码语言:javascript
复制
#!/usr/bin/env python3


def my_sum(a, b):
    return a + b


def main():
    total = 0
    for i in range(100):
        j = 0.1
        k = 0.1
        total = total + my_sum(j, k)

    print("total = {}".format(total))


if __name__ == "__main__":
    main()

运行结果

代码语言:javascript
复制
python3 main.py
total = 19.99999999999996

做一个小小的改动,我们就能把结果算成 20.00xxx

代码语言:javascript
复制
#!/usr/bin/env python3


def main():
    total = 0
    for i in range(100):
        j = 0.1
        k = 0.1
        # 不调用函数了,直接在这里加
        total = total + j + k

    print("total = {}".format(total))


if __name__ == "__main__":
    main()

运行结果

代码语言:javascript
复制
python3 main.py
total = 20.000000000000014

解决方案

就问题的根本原因来说,就是计算机没有办法精确地表示 0.1 这样的数值,详细的可以参考 IEEE754 标准。解决问题的办法也非常简单就不用浮点数,改成全部用整数表现。比如 1.234¥ 我们程序中用整数记成 12340 也就是说程序中的每一个 1 表示的是 1/10000 ¥。

有了解决方案,问题就解决了一半,剩下的就是要落实;就其它静态类型的语言来说这个比较好办,只需要把数据类型声明为 int / long int 类型就行,编译时就能检查出问题。

对于 Python 的话我们要加一些类型提示(注解),然后再用专门的静态分析工具去检查,我们的使用方式与类型提示是否一致。那下面就来实操下。


第一步安装类型检查工具

为了做静默类型检查,我们需要先安装一个官方提供的工具 mypy ;从 github 上看这个已经是官方第二大的项目了,这个工具的工程质量上确实不错。

代码语言:javascript
复制
pip3 install mypy

第二步给代码增加类型提示

给我们的代码加上类型提示, 这样 mypy 就知道我们期望的参数类型是什么了。

代码语言:javascript
复制
#!/usr/bin/env python3


def my_sum(a: int, b: int) -> int:
    return a + b


def main() -> None:
    total = 0
    for i in range(100):
        j = 0.1
        k = 0.1
        total = total + my_sum(j, k)

    print("total = {}".format(total))


if __name__ == "__main__":
    main()

对代码进行静态类型检查

代码语言:javascript
复制
mypy --strict main.py 
main.py:13: error: Argument 1 to "my_sum" has incompatible type "float"; expected "int"  [arg-type]
main.py:13: error: Argument 2 to "my_sum" has incompatible type "float"; expected "int"  [arg-type]
Found 2 errors in 1 file (checked 1 source file)

可以看到 mypy 检查到类型不兼容的问题了,下面我们把代码改正确。


第三步修复类型检查的问题

按 1/10000 的精度把我们的代码逻辑改正确。

代码语言:javascript
复制
#!/usr/bin/env python3


def my_sum(a: int, b: int) -> int:
    return a + b


def main() -> None:
    total = 0
    for i in range(100):
        # 如果我们用 1/10000 精度,那么 0.1 就应该写成 1000
        j = 1000
        k = 1000
        total = total + my_sum(j, k)

    # 输出的时候要格式化一下这样对人更加友好
    print("total = {0} ¥".format(total / 10000))


if __name__ == "__main__":
    main()

运行类型检查工具,可以看到类型检查也过去了。

代码语言:javascript
复制
mypy --strict main.py
Success: no issues found in 1 source file

运行程序检查结果是不是期望中的 20

代码语言:javascript
复制
python3 main.py 
total = 20.0 ¥

总结

可以看到最初我们只是算了 100 次 0.1 + 0.1 就积累出了比较大的误差;现在我大 A 股有 5000+ 多只股票,每秒都会有新的价格产生,这个数据是海量的。

如果任由浮点数误差这样积累下去,最后模型的准确性应该和丢鞋差不多。静态类型检查就能比较好地解决掉这些问题。

事实上我们在真正的开发上并不会,每次都会去运行程序做检查的,vscode 上有方便的插件可以用;不过这是后话了下次再说吧,这篇文章已经有点长了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 初代庄主 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档