为什么Python lint希望我使用不同的局部变量名,而不是全局变量名,以达到相同的目的



给定Python代码,如

def func():
    for i in range(10):
        pass
for i in range(10):
    pass  

pylint抱怨

Redefining name 'i' from outer scope 

上面的python代码是怎么写的?在本地使用不同的变量,例如j ?

但是为什么,当变量在两种情况下的含义完全相同时(i表示索引)。假设我将所有本地索引更改为j,然后后来我发现我想使用j作为glocal作用域中的第二个索引。又要换衣服吗?

我不能禁用lint警告,我不想有它们,我想写Pythonic,但我想在相同的事情中使用相同的名称,在上面的简单情况下。这难道不可能吗?

您可以通过不使用任何全局变量来避免全局变量冲突:

def func():
    for i in range(10):
        pass
def _init_func():
    for i in range(10):
        pass  
_init_func()

任何需要在模块初始化时运行的代码都可以放入单个函数中。在模块初始化期间,只有def语句、class语句和一个函数调用可以运行。

同样,如果您的代码不打算被import编辑,而是要运行的脚本,
def func():
    for i in range(10):
        pass
def main():
    for i in range(10):
        pass  
if __name__=="__main__":
    main()

因为当你认为你在使用另一个时,它消除了使用其中一个的风险。Lint工具是用来让你的代码更健壮的。通过让所有变量具有不同的名称,可以确保不会出现此类冲突。

这在解释型语言中尤其重要,因为错误不会在"编译时"检查。我曾经遇到过这样的问题,第二次调用函数给了我一个错误,因为我重命名了一个函数,我没有意识到在某些情况下有一个与我的函数同名的变量,所以,当我试图调用我的函数时,解释器试图"调用"我新创建的变量,这从来没有工作过XD。

这个lint策略将避免这种问题。

下面是一个示例代码(这是一个计算圆周率的程序):
from fractions import Fraction

def order(x):
    r, old_r, n, old_n = 2, 1, 1, 0
    while (x>=r):
        r, old_r, n, old_n = r*r, r, 2*n, n
    return order(x >> old_n) + old_n if old_n > 0 else 0

def term(m, n, i):
    return Fraction(4 * m, n**(2*i+1) * (2*i+1))

def terms_generator(exp_prec):
    ws = [ [term(parm[1], parm[2], 0), 0] + list(parm)
          for parm in ((1, 44, 57),
                       (1, 7, 239),
                       (-1, 12, 682),
                       (1, 24, 12943))]
    digits = 0
    while digits<exp_prec:
        curws = max(ws, key=lambda col: col[0])
        digits = int(0.30103 *
                     (order(curws[0].denominator))
                      - order(curws[0].numerator))
        yield curws[2] * curws[0], digits
        curws[2] = -curws[2]                
        curws[1] += 1
        curws[0] = term(curws[3], curws[4], curws[1])
expected_precision = 1000
pi = 0
for term, dgts in terms_generator(expected_precision):
    pi += term
print("{} digits".format(dgts))
print("pi = 3.{}".format(int((pi-3)*10**expected_precision)))

在本例中,我从生成器初始化了一个变量,而生成器使用了另一个函数,这个函数在生成器初始化变量后与我的变量名冲突。好吧,这不是一个很好的例子,因为这里的两个名字都是全局的,但从它的结构来看,它不会立即发生。

我的观点是,即使你知道如何编程,你也会犯错误,这些做法将有助于减少那些隐藏的风险。

如果i在循环后至少运行一次,则会发出警告。这意味着,如果你在不重新初始化它的情况下使用它,它仍然具有上次循环迭代时的值。

你使用它的方式是好的,因为i总是会被重新初始化。

一个有用的做法是在ALL_CAPS中命名外部作用域中的所有值。这样就不会出错了。

这个答案显然是错误的。详见:https://stackoverflow.com/a/25072186

最新更新