一个关于作用域的吐槽

2023-03-15 02:08:00 +08:00
 Aloento

今天在看 Hifigan 的源码,突然发现 IDE 提示 ch 变量 warning

    self.resblocks = nn.ModuleList()
    for i in range(len(self.ups)):
      ch = upsample_initial_channel // (2 ** (i + 1))
      for j, (k, d) in enumerate(zip(resblock_kernel_sizes, resblock_dilation_sizes)):
        self.resblocks.append(resblock(ch, k, d))

    self.conv_post = Conv1d(ch, 1, 7, 1, padding=3, bias=False)
    self.ups.apply(init_weights)

局部变量 ch 可能在赋值之前使用

首先说明本人不会 python ,今天看到这段百思不得其解

询问 AI 也没问出个所以然,遂询问朋友

得到了这样的回答:

Python 的 for 不认为是作用域

Python 没有语句块的概念

最小作用域就是闭包或者函数

知道这个以后我脑海中只有一句话

真的是令人叹为观止

2724 次点击
所在节点    Python
25 条回复
zhlxsh
2023-03-15 02:34:01 +08:00
局部变量 ch 可能在赋值之前使用

这句话是说,在 for 循环结束后使用了 ch ?

假设我理解没错,语言没有强制规定 for 循环作用域,代码跑起来没问题,编译器报语法错误。 那就是是写的人不规范😂
enchilada2020
2023-03-15 02:50:41 +08:00
这…你可能没写过 JS ?
enchilada2020
2023-03-15 02:51:49 +08:00
不对啊 你写过 JS 为啥会叹为观止…ES6 之前不都这样吗
enchilada2020
2023-03-15 02:53:16 +08:00
直接 var 或者连 var 都不写 就直接在 global 上定义属性才叫叹为观止…
Aloento
2023-03-15 03:00:39 +08:00
@enchilada2020 我是直接从 ES6 开始学的 JS (不如说一来就用的 TS )
然后写代码一直都是非常的规范,从来没用过黑魔法
所以说虽然我知道 var 是全局,但是 python 这种连 var / let / := 也不需要的语言
属实是超出了我的认知范围
enchilada2020
2023-03-15 03:02:24 +08:00
@Aloento 哈哈 看看 ES6 之前的 JS 那才叫群魔乱舞的感觉 直接写规范 TS 是正确选择😉
celerysoft
2023-03-15 03:19:32 +08:00
如果 len(self.ups) == 0 ,for 循环没有执行,那 ch 就没有赋值,并且直接在 self.conv_post = Conv1d(ch, 1, 7, 1, padding=3, bias=False) 这里调用了,所谓的「局部变量 ch 可能在赋值之前使用」说的就是这种情况吧

不过我有点不理解你吐槽的点,你是觉得 ch 应该在没有声明的情况下就能使用吗?还是说不习惯 Python 没有专门的词用于变量声明
enchilada2020
2023-03-15 03:25:17 +08:00
@celerysoft 他吐槽的是 Python 没块作用域…
fantasticfears
2023-03-15 03:43:15 +08:00
Python 没有块作用域。Python 没有块作用域。Python 没有块作用域。
重要的事情说三遍
celerysoft
2023-03-15 04:24:22 +08:00
@enchilada2020 那我的确没理解 OP 的意思,如果在不知道 Python 没有块作用域的前提下来读这段代码,确实晦涩难懂
xuanbg
2023-03-15 07:58:11 +08:00
这个哪怕是 Java ,也一样会报这个警告。因为你在倒数第二行是用了 ch 变量,如果 self.ups 为空集合,ch 上哪去赋值呢?
cmdOptionKana
2023-03-15 08:18:14 +08:00
Python 的作用域确实是比较与众不同,稍稍有点难用,并且没啥特别优点,我认为算是 Python 设计得比较差的一点。

但日常使用也没啥大问题就是了。
cbdyzj
2023-03-15 08:21:29 +08:00
Python 没有块作用域,C 、C++、Java 、JavaScript 、C#、Rust 等主流语言都支持块作用域,PO 不清楚实属正常
楼上说 ES3 也不支持块作用域的,现在是 2023 年
darkengine
2023-03-15 08:42:33 +08:00
@xuanbg 换 Java 直接就编不过了
xuanbg
2023-03-15 09:01:01 +08:00
@darkengine 可以过的。但我怀疑 OP 贴的代码中最后两行代码的缩进不对,应该加两个空格,这样就不会有这个警告。并且,变量在使用逻辑上也能和上面的循环对应起来。
hsfzxjy
2023-03-15 09:05:44 +08:00
@xuanbg 缩进是对的,代码就是这样,相当于一种取巧的方式获得 ch 最后一个计算结果
raymanr
2023-03-15 09:15:42 +08:00
这个还比较好理解吧,

如果 len(self.ups) == 0 那么循环就不会执行,

那么就会出现 ch 没有出现初始化的情况,

应该会抛出 NameError 吧

在循环前给 ch 一个初始化的值是更合理的做法

这个是作者写得不规范的问题, 和 let var 之类的声明语句没关系, 反正没有声明也检查出这个问题了嘛
bl4ckoooooH4t
2023-03-15 09:17:36 +08:00
在 for i in range(len(self.ups)): 里面定义了 ch , 如果 len(self.ups) == 0 , 那么 ch 变量就不会被定义,这样就引用了未定义的变量。 应该是这样吧
fbichijing
2023-03-15 09:39:31 +08:00
平时写的时候好像倒没怎么在意这个问题。只是乍一看起来代码感觉好像不太自然。如果是我自己在写的话可能在 for 前面给 ch 初始化一下。
好像许多编程语言 for 里面的局部变量都无法在 for 之外调用,如果 Python 确实这么做也可以的话,反而说明了使用变量前初始化的必要性。万一使用了一个自己前面定义过的变量,但是自己不记得了,这就会出现难以调试的 bug.
pendulum
2023-03-15 10:10:37 +08:00
for 循环之前应该先初始化 ch ,因为 for 循环后又用到了 ch 。或者给 for 循环里面的 ch 加个 nonlocal

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/924046

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX