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
haoliang
V2EX  ›  Python

Python 这个 scope/block leak 我是越来越膈硬

  •  
  •   haoliang · 2022-08-07 11:44:21 +08:00 · 2382 次点击
    这是一个创建于 600 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个 scope/block leak 我最初是在学 nim 时看到的: https://github.com/nim-lang/Nim/wiki/Nim-for-Python-Programmers#scoping

    最开始我还不是很在意,直到之前接手老项目代码,我都快疯了:if..elif..else 里面藏着 n 个变量,然后在后面使用变量的代码是否能正常运行完全靠运气(当然有一些业务逻辑保证,但业务逻辑一直在变啊,能从静态分析阶段排除的问题非要等到运行时再确认,费时费力) 我之前一直用嵌套 function 的方式来创造 scope ,以达到隔离变量名、最小化变量生命周期的目的 (我经常纠结命名:xx_a 、xx_b, 有了 scope 我全叫它们 xx )

    我觉得有两方面的缺失在 python 中

    1. for 、while 、with 、if 这类应该是隐式 scope ,却不是 (当然 with 列在这里不太合适,但有必要)
    2. 没有提供显式 scope 块,除非 def

    针对第 2 点,我所了解的其他大部分语言都有对应的设计

    • nim block:
    • zig 、go 、javascript {}
    • lua do..end

    针对第 1 点,javascript 有 let ,lua 有 local ,上面列出的其他语言没这毛病; python 的 nonlocal 也不是针对这种情况的。

    很少见网上有过相关讨论,所以好奇问下大家难道不在意吗?

    -- 倒是找到个相关库: https://github.com/l74d/scoping

    9 条回复    2022-08-08 13:57:36 +08:00
    imycc
        1
    imycc  
       2022-08-07 12:04:04 +08:00
    是有点在意的。块级作用域缺失,出现的 bug 靠编辑器发现不了。比如一个函数写得比较长,存在几个循环,后面的循环用错了变量之类的。
    只能靠代码规范来规避了,比如控制函数长度,变量命名表意明确,临时变量的初始化、使用和销毁放到一块,写好注释之类的。
    humiaozuzu
        2
    humiaozuzu  
       2022-08-07 12:07:44 +08:00
    一方面是靠编码风格来减少这些 scope 在其他地方被引用。另外不知道 flake8 有没有插件可以发现这类用法, 提示出来
    wxf666
        3
    wxf666  
       2022-08-07 12:07:57 +08:00
    这……是一个函数内揉了太多内容,还是不同含义的变量都用同一个命名表示了?
    hezhiming1993
        4
    hezhiming1993  
       2022-08-07 14:46:56 +08:00
    在意啊
    所以转 Go 了,

    现在小工具都用静态语言写
    chenxytw
        5
    chenxytw  
       2022-08-07 18:39:28 +08:00
    这点确实是 Why Python sucks 的重要组成部分。而且嵌套函数定义也确确实实就是唯一解决方案。
    但其实 Python 作用域的坑远比你想象的深且大(
    比如这个: https://blog.kevmod.com/2014/06/26/what-does-this-print-1/
    junkun
        6
    junkun  
       2022-08-07 23:17:11 +08:00
    我觉得 leak 这个名词不合适,python 它就是只有两种作用域,模块全局和函数内,并没有 leak 。global 和 nonlocal 其实只是变量查找的规则。

    并且个人认为,python 其实设计上就不提倡嵌套函数(除非你要返回这个函数),过多的嵌套函数实际上就像共享全局变量一样,甚至 context 更复杂,也不好扩展。我更提倡在外面建一个新的函数然后把相关局部变量用参数传递进去,要修改 nonlocal 变量再返回出来。
    jfcherng
        7
    jfcherng  
       2022-08-08 00:51:00 +08:00
    @chenxytw #5 請問這個是什麼原理呢?
    haoliang
        8
    haoliang  
    OP
       2022-08-08 12:10:49 +08:00
    谢谢各位回复。
    @chenxytw 哈哈,这个例子太冷门了,我目前没遇到过。不过帖子描述中的 nim 链接中确实有列出它。
    @junkun 这 nonlocal 操作有点繁琐啊,看起来不贴近实际场景,我大概率会继续用 closure ,除非像 zig 这样不支持 nested function 更没有 closure 的。(为了区分这两者,就用 closure 、function 代替了)

    我有些惊讶,lua 5.1 这个 10 来年语法没改变的语言在这点上都比 python 想得周到,而 python 这边竟然连个 pep 都没有。(lua 5.1 发布于 2006 ,python 3.0 于 2008 )
    chenxytw
        9
    chenxytw  
       2022-08-08 13:57:36 +08:00   ❤️ 1
    @jfcherng 用 dis 包看一下这个函数编译出来的 opcode 。x 和 y 的处理完全不一样 0 0
    至于为什么不一样,原因之一 是后面的赋值语句,会改变 x 的属性 /类别。
    原因之二是 class 的特殊处理。同样的顺序放到 function 中,只会得到 UnboundLocalError: local variable referenced before assignment

    当然,整件事上我个人认为是设计缺陷....
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5433 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 08:44 · PVG 16:44 · LAX 01:44 · JFK 04:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.