V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
xuegy
V2EX  ›  Python

如何分离屎山中 Union 类型的变量

  •  
  •   xuegy · 35 天前 · 1550 次点击
    这是一个创建于 35 天前的主题,其中的信息可能已经有所发展或是发生改变。

    正在处理一座屎山,大概情况是这样的。有一个自定义的class X,需要改掉的东西注释写的是y=Union[X, str],实际情况也是两种类型到处都混在一起根本分不清。后面所有跟X类有关的方法一点注释没写,甚至都不做类型判断,而是大量的使用getattr(y, 'name', y)把水搅得更浑(如果y是字符串,没有name,返回字符串本身。否则返回y.name也是一个字符串)。最离谱的是整座屎山还配了一套 30 分钟才能跑完的 pytest 。

    现在需要把混乱的y分成确定类型的yy_str,使用 pydantic 强制定义数据类型来一点点排错。然而改了几百行以后,所有跟X有关的方法都被迫改出两种版本的。pytest 不再报类型错误了,却开始出现各种离奇的 bug 挂掉。

    有什么更强大的工具可以搞定这件事吗?比如同步检测两个版本的代码,看从哪一步开始两边的数据变得不一致了?

    第 1 条附言  ·  35 天前

    项目背景是一个生物博士毕设的Python代码商业化后形成的屎山。所以写成这样不意外,能跑起来才是意外。

    12 条回复    2025-08-04 15:01:11 +08:00
    chaoshui
        1
    chaoshui  
       35 天前
    交给 AI
    xuegy
        2
    xuegy  
    OP
       35 天前
    @chaoshui 用 GPT o4-mini-high 也无力回天
    huangyezhufeng
        3
    huangyezhufeng  
       35 天前   ❤️ 1
    其实从开始用`Union`开始,就已经把潘多拉魔盒打开了一半。再用`getattr`,几乎是不可避免地成为屎山了。

    为了避免误解,补充说明一下,用`Union`和`getattr`都没问题,前提是会用。从这个半个钟的单测来看,似乎并不是如此。
    Syiize
        4
    Syiize  
       35 天前   ❤️ 1
    可以重写 class X 中的魔术方法 __getattribute__,如果要访问的属性是 "name",就 raise RuntimeError 。然后运行代码,再根据 Python 的 traceback 定位到对应的位置修改。
    xuegy
        5
    xuegy  
    OP
       35 天前 via iPad
    @huangyezhufeng 字里行间甚至能看出来原作者对于 getattr 这个小聪明还挺自豪的
    xuegy
        6
    xuegy  
    OP
       35 天前 via iPad
    @Syiize 这个不行吧,是真的需要查询 y.name 。我隐约感觉整个代码的真实运行逻辑就是建立在 getattr 大乱炖的基础之上。
    julyclyde
        7
    julyclyde  
       34 天前
    @Syiize 冒烟测试,哈哈哈
    julyclyde
        8
    julyclyde  
       34 天前
    @xuegy getattr 、getattribute 、__call__之类的,都过于动态了,只有 runtime 才知道这玩意具体在干啥
    woodfizky
        9
    woodfizky  
       34 天前
    代码量有多少?建议不要直接在屎山上改,而是认真品鉴屎山的代码逻辑之后,用更好的方式重新写一遍。
    有原始需求或者设计文档最好了。

    血泪教训,特别是需要长期维护迭代的项目,早期图省事屎上雕花,后面会长痛。
    除非真的赶时间,不如短痛一下重写。
    Syiize
        10
    Syiize  
       34 天前
    @xuegy #6 应该是可以的。我测试了一下,重写过__getattribute__后,不论是 y.name 还是 getattr(y, "name", y) 都会打印出信息的。
    xuegy
        11
    xuegy  
    OP
       34 天前
    @woodfizky 总量差不多十万行,涉及操作这个类的有五千行左右。其实我就是在用 C++和 pybind11 移植底层的数据结构,但是老板觉得 std::variant 是屎上雕花不解决问题。所以我只能是先在 Python 里面试着分离一下,能跑过 pytest 了再移植到 C++。
    zizon
        12
    zizon  
       31 天前
    >pytest 不再报类型错误了,却开始出现各种离奇的 bug 挂掉
    说明有些地方已经变成 feature 了.

    比如本来就是不是 str 的,但是当作 str 处理了产生后续逻辑.
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   987 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 22:07 · PVG 06:07 · LAX 15:07 · JFK 18:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.