问题:在外部作用域中定义阴影名称有多糟糕?
我刚刚切换到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
在上面的代码片段中没什么大不了的,但是请想象一个具有更多参数和更多代码行的函数。然后,您决定将data
参数重命名为,yadda
但错过了函数主体中使用该参数的位置之一…现在data
是指全局变量,您开始有怪异的行为- NameError
如果不这样做,您将拥有更明显的表现有一个全球的名字data
。
还要记住,在Python中,所有东西都是对象(包括模块,类和函数),因此对于函数,模块或类没有明显的命名空间。另一种情况是将函数导入foo
到模块顶部,然后在函数主体中的某个位置使用它。然后,在函数中添加一个新参数,并将其命名为-bad lucky- foo
。
最后,内置函数和类型也位于相同的命名空间中,并且可以以相同的方式进行阴影处理。
如果您的功能短,命名合理且单元测试范围广,那么这些都不是什么大问题,但是好吧,有时您必须维护的代码不够完美,并且被警告可能存在的问题。
回答 1
当前最受投票和接受的答案以及此处的大多数答案都没有抓住重点。
函数有多长,或描述性地命名变量(希望将潜在的名称冲突机会降到最低)都没有关系。
函数的局部变量或其参数恰好在全局范围内共享名称这一事实是完全不相关的。实际上,无论您多么仔细地选择本地变量名称,您的函数都无法预见到“ yadda
将来我的好名字是否也将用作全局变量?”。解决方案?根本不用担心!正确的心态是将函数设计为仅使用签名中参数的输入,而无需使用全局范围内的(或将要)什么,然后阴影根本就不是问题。
换句话说,仅当函数需要使用相同名称的局部变量和全局变量时,阴影问题才重要。但是您首先应该避免这种设计。OP的代码实际上并没有这样的设计问题。仅仅是PyCharm不够聪明,它会发出警告以防万一。因此,只是为了使PyCharm满意,并使我们的代码整洁,请参见silyevsk的回答中引用的此解决方案以完全删除全局变量。
def print_data(data):
print data
def main():
data = [4, 5, 6]
print_data(data)
main()
这是解决问题的正确方法,方法是修复/删除全局对象,而不调整当前的局部函数。
回答 2
在某些情况下,一个好的解决方法是将vars +代码移至另一个函数:
def print_data(data):
print data
def main():
data = [4, 5, 6]
print_data(data)
main()
回答 3
这取决于功能的持续时间。功能越长,将来有人对其进行修改的机会就越多,data
以为它意味着全局。实际上,这意味着本地,但是由于功能太长了,因此对于他们来说并不明显存在具有该名称的本地。
对于您的示例函数,我认为遮盖全局一点也不差。
回答 4
做这个:
data = [4, 5, 6]
def print_data():
global data
print(data)
print_data()
回答 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)
回答 6
我喜欢在pycharm的右上角看到一个绿色的勾号。我为变量名加上下划线只是为了清除此警告,因此我可以将重点放在重要警告上。
data = [4, 5, 6]
def print_data(data_):
print(data_)
print_data(data)
回答 7
看起来像是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和所有人感到高兴