我刚刚切换到 PyCharm,我对它为我改进代码提供的所有警告和提示感到非常高兴。除了这个我不明白的:
此检查检测外部范围中定义的阴影名称。
我知道从外部范围访问变量是不好的做法,但是隐藏外部范围有什么问题?
这是一个示例,其中 PyCharm 给了我警告信息:
data = [4, 5, 6]
def print_data(data): # <-- Warning: "Shadows 'data' from outer scope
print data
print_data(data)
上面的代码段没有什么大不了的,但是想象一个有更多参数和更多代码行的函数。然后您决定将您的 data
参数重命名为 yadda
,但错过了它在函数主体中使用的位置之一......现在 data
指的是全局,并且您开始出现奇怪的行为 - 您会在哪里如果您没有全局名称 data
,则有一个更明显的 NameError
。
还要记住,在 Python 中,一切都是对象(包括模块、类和函数),因此函数、模块或类没有不同的命名空间。另一种情况是您在模块顶部导入函数 foo
,并在函数体的某处使用它。然后向函数添加一个新参数并将其命名为 - 运气不好 - foo
。
最后,内置函数和类型也存在于相同的命名空间中,并且可以以相同的方式被隐藏。
如果你有简短的函数、良好的命名和不错的单元测试覆盖率,那么这一切都不是什么大问题,但是,有时你必须维护不完美的代码,并且被警告这些可能的问题可能会有所帮助。
The currently most up-voted and accepted answer,这里的大多数答案都没有抓住重点。
不管你的函数有多长,或者你如何描述性地命名你的变量(希望最大限度地减少潜在的名称冲突的机会)。
您的函数的局部变量或其参数恰好在全局范围内共享名称这一事实完全无关紧要。而事实上,无论你如何仔细选择局部变量名,你的函数永远无法预见“我的酷名yadda
将来是否也将用作全局变量?”。解决方案?根本不用担心! 正确的思维方式是设计您的函数以使用来自且仅来自其签名中的参数的输入。这样你就不需要关心全局范围内是什么(或将是什么),然后阴影就完全不是问题了。
换句话说,阴影问题仅在您的函数需要使用同名的局部变量和全局变量时才重要。但是你应该首先避免这样的设计。 OP 的代码确实没有真的有这样的设计问题。只是 PyCharm 不够聪明,它会发出警告以防万一。所以,为了让 PyCharm 开心,也让我们的代码更干净,请参阅 silyevsk's answer 中引用的此解决方案以完全删除全局变量。
def print_data(data):
print data
def main():
data = [4, 5, 6]
print_data(data)
main()
这是“解决”这个问题的正确方法,通过修复/删除你的全局事物,而不是调整你当前的本地函数。
print_data
是一个全局变量。想一想...
在某些情况下,一个好的解决方法可能是将变量和代码移动到另一个函数:
def print_data(data):
print data
def main():
data = [4, 5, 6]
print_data(data)
main()
我喜欢在 PyCharm 的右上角看到一个绿色的勾号。我在变量名后面加上下划线只是为了清除这个警告,这样我就可以专注于重要的警告。
data = [4, 5, 6]
def print_data(data_):
print(data_)
print_data(data)
# noinspection PyShadowingNames
这取决于函数的长度。函数越长,将来修改它的人写 data
认为它意味着全局的机会就越大。事实上,它的意思是本地的,但是因为函数很长,对他们来说并不明显存在同名的本地。
对于您的示例函数,我认为遮蔽全局并不坏。
做这个:
data = [4, 5, 6]
def print_data():
global data
print(data)
print_data()
global
声明全局变量。
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)
data
怎么办,都在几百行代码之内?
data
是 this 函数中的本地名称,所以我什至不费心检查/记住同名的全局名称是否存在 /i>,更不用说它包含的内容了。
False
- 如果您没有定义,而只是尝试使用 data
,它会在范围内查找直到找到一个,因此它确实找到全局 data
。 data = [1, 2, 3]; def foo(): print(data); foo()
看起来它是 100% 的 pytest 代码模式。
看:
pytest fixtures: explicit, modular, scalable
我遇到了同样的问题,这就是我找到这篇文章的原因;)
# ./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 和每个人都感到高兴。
要忽略警告,正如 Chistopher 在评论中所说,您可以在其上方发表评论
# noinspection PyShadowingNames
不定期副业成功案例分享
nonlocal
关键字使外部得分引用(如在闭包中)显式。请注意,这与遮蔽不同,因为它不会显式地遮蔽外部变量。