我刚刚切换到PyCharm,我很高兴它为我提供的所有警告和提示来改进我的代码。除了这个我不明白

此检查检测在外部作用域中定义的阴影名称。

我知道从外部范围访问变量是不好的做法,但阴影外部范围的问题是什么?

下面是一个例子,PyCharm给了我警告信息:

data = [4, 5, 6]

def print_data(data): # <-- Warning: "Shadows 'data' from outer scope
    print data

print_data(data)

data = [4, 5, 6] # Your global variable

def print_data(data): # <-- Pass in a parameter called "data"
    print data  # <-- Note: You can access global variable inside your function, BUT for now, which is which? the parameter or the global variable? Confused, huh?

print_data(data)

这取决于函数的长度。函数越长,将来修改它的人写数据时认为它意味着全局的可能性就越大。实际上,它指的是局部函数,但由于函数太长,它们并不清楚是否存在具有该名称的局部函数。

对于你的例子函数,我认为遮蔽全局一点都不坏。


在上面的代码片段中没有什么大问题,但是想象一下,一个函数有更多的参数和相当多的代码行。然后,您决定将数据参数重命名为yadda,但忽略了它在函数体中使用的一个地方……现在data引用全局数据,你开始有奇怪的行为——如果你没有全局名称数据,你会有一个更明显的NameError。

还要记住,在Python中一切都是对象(包括模块、类和函数),因此函数、模块或类没有不同的命名空间。另一种情况是在模块的顶部导入函数foo,并在函数体的某处使用它。然后在函数中添加一个新参数,并将其命名为- bad luck - foo。

最后,内置函数和类型也位于相同的名称空间中,可以以相同的方式隐藏。

如果你有简短的函数,良好的命名和良好的单元测试覆盖率,这些都不是什么大问题,但是,有时候你必须维护不太完美的代码,对这些可能的问题发出警告可能会有所帮助。


在某些情况下,一个很好的解决方法是将变量和代码移动到另一个函数:

def print_data(data):
    print data

def main():
    data = [4, 5, 6]
    print_data(data)

main()

目前投票最多、接受度最高的答案和这里的大多数答案都没有抓住重点。

这与你的函数有多长无关,也与你如何描述性地命名你的变量(希望最小化潜在的名称冲突的机会)无关。

The fact that your function's local variable or its parameter happens to share a name in the global scope is completely irrelevant. And in fact, no matter how carefully you choose you local variable name, your function can never foresee "whether my cool name yadda will also be used as a global variable in future?". The solution? Simply don't worry about that! The correct mindset is to design your function to consume input from and only from its parameters in signature. That way you don't need to care what is (or will be) in global scope, and then shadowing becomes not an issue at all.

换句话说,只有当你的函数需要使用同名的局部变量和全局变量时,阴影问题才会起作用。但是您应该首先避免这样的设计。OP的代码并没有这样的设计问题。只是PyCharm不够智能,它会发出警告以防万一。因此,为了让PyCharm开心,也为了让我们的代码干净,请参阅引用silyevsk的答案的解决方案,以完全删除全局变量。

def print_data(data):
    print data

def main():
    data = [4, 5, 6]
    print_data(data)

main()

这是“解决”这个问题的正确方法,通过修复/删除全局的东西,而不是调整当前的局部函数。


这样做:

data = [4, 5, 6]

def print_data():
    global data
    print(data)

print_data()

它看起来像是100%的pytest代码模式。

See:

Pytest fixture:显式的、模块化的、可伸缩的

我也有同样的问题,这就是为什么我找到了这篇文章;)

# ./tests/test_twitter1.py
import os
import pytest

from mylib import db
# ...

@pytest.fixture
def twitter():
    twitter_ = db.Twitter()
    twitter_._debug = True
    return twitter_

@pytest.mark.parametrize("query,expected", [
    ("BANCO PROVINCIAL", 8),
    ("name", 6),
    ("castlabs", 42),
])
def test_search(twitter: db.Twitter, query: str, expected: int):

    for query in queries:
        res = twitter.search(query)
        print(res)
        assert res

并且它将警告“此检查检测在外部作用域中定义的阴影名称”。

要解决这个问题,只需将twitter fixture移动到。/tests/conftest.py

# ./tests/conftest.py
import pytest

from syntropy import db


@pytest.fixture
def twitter():
    twitter_ = db.Twitter()
    twitter_._debug = True
    return twitter_

并删除twitter fixture,如./tests/test_twitter2.py:

# ./tests/test_twitter2.py
import os
import pytest

from mylib import db
# ...

@pytest.mark.parametrize("query,expected", [
    ("BANCO PROVINCIAL", 8),
    ("name", 6),
    ("castlabs", 42),
])
def test_search(twitter: db.Twitter, query: str, expected: int):

    for query in queries:
        res = twitter.search(query)
        print(res)
        assert res

这将使QA, PyCharm和每个人都感到高兴。


我喜欢在PyCharm的右上角看到一个绿色的勾。我在变量名后面加上下划线,只是为了清除这个警告,这样我就可以专注于重要的警告。

data = [4, 5, 6]

def print_data(data_):
    print(data_)

print_data(data)

要忽略这个警告,就像克里斯托弗在评论中说的,你可以在上面评论

# noinspection PyShadowingNames

我认为这条规则没有多大帮助。我只是禁用了它,点击设置->编辑器->检查,然后勾选这条规则:

Shadowing names from outer scope