Python 在外部作用域中定义的阴影名称有多糟糕?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20125172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 19:37:32  来源:igfitidea点击:

How bad is shadowing names defined in outer scopes?

pythoncoding-stylepycharm

提问by Framester

I just switched to Pycharm and I am very happy about all the warnings and hints it provides me to improve my code. Except for this one which I don't understand:

我刚刚切换到 Pycharm,我对它为我改进代码提供的所有警告和提示感到非常高兴。除了这个我不明白:

This inspection detects shadowing names defined in outer scopes.

This inspection detects shadowing names defined in outer scopes.

I know it is bad practice to access variable from the outer scope but what is the problem with shadowing the outer scope?

我知道从外部作用域访问变量是不好的做法,但是遮蔽外部作用域有什么问题?

Here is one example, where Pycharm gives me the warning message:

这是一个示例,其中 Pycharm 给了我警告消息:

data = [4, 5, 6]

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

print_data(data)

采纳答案by bruno desthuilliers

No big deal in your above snippet, but imagine a function with a few more arguments and quite a few more lines of code. Then you decide to rename your dataargument as yaddabut miss one of the places it is used in the function's body... Now datarefers to the global, and you start having weird behaviour - where you would have a much more obvious NameErrorif you didn't have a global name data.

上面的代码片段没什么大不了的,但是想象一个带有更多参数和更多代码行的函数。然后你决定将你的data参数重命名为yadda但错过了它在函数体中使用的地方之一......现在data指的是全局,你开始有奇怪的行为 -NameError如果你不这样做,你会有更明显的表现有一个全球名称data

Also remember that in Python everything is an object (including modules, classes and functions) so there's no distinct namespaces for functions, modules or classes. Another scenario is that you import function fooat the top of your module, and use it somewhere in your function body. Then you add a new argument to your function and named it - bad luck - foo.

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

Finally, built-in functions and types also live in the same namespace and can be shadowed the same way.

最后,内置函数和类型也存在于相同的命名空间中,并且可以以相同的方式进行隐藏。

None of this is much of a problem if you have short functions, good naming and a decent unittest coverage, but well, sometimes you have to maintain less than perfect code and being warned about such possible issues might help.

如果您有简短的函数、良好的命名和不错的单元测试覆盖率,那么这些都不是什么大问题,但是,有时您必须维护不太完美的代码,并且被警告此类可能的问题可能会有所帮助。

回答by JoeC

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)

回答by Steve Jessop

It depends how long the function is. The longer the function, the more chance that someone modifying it in future will write datathinking that it means the global. In fact it means the local but because the function is so long it's not obvious to them that there exists a local with that name.

这取决于函数的长度。函数越长,将来修改它的人就越有可能data认为这意味着全局。事实上,它的意思是本地,但因为函数太长,他们并不明显存在具有该名称的本地。

For your example function, I think that shadowing the global is not bad at all.

对于您的示例功能,我认为遮蔽全局一点也不差。

回答by silyevsk

A good workaround in some cases may be to move the vars + code to another function:

在某些情况下,一个好的解决方法可能是将 vars + 代码移动到另一个函数:

def print_data(data):
    print data

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

main()

回答by RayLuo

The currently most up-voted and accepted answerand most answers here miss the point.

目前投票最多和被接受的答案以及这里的大多数答案都没有抓住要点。

It doesn't matter how long your function is, or how you name your variable descriptively (to hopefully minimize the chance of potential name collision).

无论您的函数有多长,或者您如何以描述方式命名变量(希望最大限度地减少潜在名称冲突的可能性)都无关紧要。

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 yaddawill 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.

您的函数的局部变量或其参数恰好在全局范围内共享一个名称这一事实完全无关紧要。而事实上,无论你如何谨慎地选择你的局部变量名,你的函数永远无法预见“我的酷名字yadda将来是否也会被用作全局变量?”。解决方案?根本不用担心!正确的心态是设计你的函数来消费来自并且仅来自其签名中的参数的输入,这样你就不需要关心全局范围内是什么(或将会是什么),然后阴影就完全不是问题了。

In other words, shadowing problem only matters when your function need to use the same name local variable AND the global variable. But you should avoid such design in the first place. The OP's code does NOT really have such design problem. It is just that PyCharm is not smart enough and it gives out a warning just in case. So, just to make PyCharm happy, and also make our code clean, see this solution quoting from silyevsk 's answerto remove the global variable completely.

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

def print_data(data):
    print data

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

main()

This is the proper way to "solve" this problem, by fixing/removing your global thing, not adjusting your current local function.

这是“解决”这个问题的正确方法,通过修复/删除您的全局事物,而不是调整您当前的本地功能。

回答by RayLuo

Do this:

做这个:

data = [4, 5, 6]

def print_data():
    global data
    print(data)

print_data()

回答by Andrei.Danciuc

It looks like it 100% pytest code pattern

看起来像 100% pytest 代码模式

see:

看:

https://docs.pytest.org/en/latest/fixture.html#conftest-py-sharing-fixture-functions

https://docs.pytest.org/en/latest/fixture.html#conftest-py-sharing-fixture-functions

I had the same problem with, this is why I found this post ;)

我有同样的问题,这就是我找到这篇文章的原因;)

# ./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

And it will warn with This inspection detects shadowing names defined in outer scopes.

它会警告 This inspection detects shadowing names defined in outer scopes.

To fix that just move your twitterfixture into ./tests/conftest.py

要解决这个问题,只需将您的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_

And remove twitterfixture like in ./tests/test_twitter2.py

并删除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

This will be make happy QA, Pycharm and everyone

这会让 QA、Pycharm 和所有人都开心

回答by Baz

I like to see a green tick in the top right corner in pycharm. I append the variable names with an underscore just to clear this warning so I can focus on the important warnings.

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

data = [4, 5, 6]

def print_data(data_): 
    print(data_)

print_data(data)