我刚刚切换到Pycharm,我很高兴它提供了所有警告和提示,以改进我的代码。除了这个我不明白的地方:
This inspection detects shadowing names defined in outer scopes.
我知道从外部作用域访问变量是不好的做法但是遮蔽外部作用域的问题是什么?
以下是一个示例,其中Pycharm向我发出警告消息:
data = [4, 5, 6]
def print_data(data): # <-- Warning: "Shadows 'data' from outer scope
print data
print_data(data)
答案 0 :(得分:173)
在上面的代码片段中没什么大不了的,但想象一个带有更多参数和更多代码行的函数。然后你决定将你的data
参数重命名为yadda
,但是错过了它在函数体中使用的其中一个位置......现在data
指的是全局,你开始有点奇怪行为 - 如果您没有全局名称NameError
,那么您将有更明显的data
。
还要记住,在Python中,一切都是对象(包括模块,类和函数),因此对于函数,模块或类没有明确的命名空间。另一种情况是您在模块的顶部导入函数foo
,并在函数体中的某处使用它。然后你为你的函数添加一个新参数并将其命名为 - 运气不好 - foo
。
最后,内置函数和类型也存在于同一名称空间中,并且可以以相同的方式进行阴影处理。
如果你的功能很短,命名良好且单位测试覆盖率不高,这一切都不是问题,但是,有时你必须保持不完美的代码并被警告这些可能的问题可能有所帮助。
答案 1 :(得分:100)
The currently most up-voted and accepted answer并且大多数答案都错过了重点。
你的功能有多长,或者你如何描述你的变量(希望最大限度地减少潜在名称冲突的可能性)并不重要。
您的函数的局部变量或其参数碰巧在全局范围内共享名称这一事实完全无关紧要。事实上,无论你多么谨慎地选择局部变量名,你的功能都无法预见&#34;我的酷名yadda
是否也将在未来用作全局变量?&#34;。解决方案?不用担心! 正确的思维方式是将您的功能设计为仅使用来自签名中的参数的输入,这样您就不需要关心全局范围内(或将会是什么),以及然后阴影根本不成问题。
换句话说,当您的函数需要使用相同名称的局部变量和全局变量时,阴影问题才有意义。但是你应该首先避免这种设计。 OP的代码并没有真正存在这样的设计问题。只是PyCharm不够聪明,它会发出警告以防万一。因此,只是为了让PyCharm感到高兴,并使我们的代码变得干净,请参阅此解决方案,引用silyevsk 's answer来完全删除全局变量。
def print_data(data):
print data
def main():
data = [4, 5, 6]
print_data(data)
main()
这是解决问题的正确方法。这个问题,通过修复/删除全局事物,而不是调整当前的本地函数。
答案 2 :(得分:18)
在某些情况下,一个好的解决方法可能是将vars +代码移动到另一个函数:
def print_data(data):
print data
def main():
data = [4, 5, 6]
print_data(data)
main()
答案 3 :(得分:6)
这样做:
data = [4, 5, 6]
def print_data():
global data
print(data)
print_data()
答案 4 :(得分:5)
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)
答案 5 :(得分:5)
这取决于功能有多长。功能越长,将来有人修改它的可能性越大,data
认为它意味着全局。事实上,它意味着本地,但因为功能太长,所以对他们来说并不明显存在具有该名称的本地。
对于你的示例函数,我认为阴影全局并不坏。
答案 6 :(得分:3)
我喜欢在pycharm的右上角看到一个绿色的勾号。我为变量名加上下划线只是为了清除此警告,因此我可以将重点放在重要警告上。
data = [4, 5, 6]
def print_data(data_):
print(data_)
print_data(data)
答案 7 :(得分:2)
它看起来像是100%pytest代码模式
请参阅:
https://docs.pytest.org/en/latest/fixture.html#conftest-py-sharing-fixture-functions
我遇到了同样的问题,这就是我发现这篇文章的原因;)
# ./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
它将以This inspection detects shadowing names defined in outer scopes.
要解决此问题,只需将twitter
灯具移至./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
./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和所有人