Shadows name from outer scope python что это
Перейти к содержимому

Shadows name from outer scope python что это

  • автор:

Как правильно именовать переменную, чтобы избежать предупреждения типа «Имя тени из внешней области видимости» в Python

Я использую PyCharm для своей программы на Python, и я написал коды ниже:

Поэтому я получаю текст предупреждения типа «Shadows name ‘ds’ from external scope». Я знаю влияние области действия, но я все еще хочу использовать тот же формат кода, что и «для root, ds, fs in . » во внутренней или внешней области видимости.

Я искал PEP8, однако до сих пор не знаю, как назвать переменную в функции нормативно.

Не могли бы вы дать мне предложение?

3 ответа

В общем: просто проигнорируйте предупреждение. Это просто предупреждение, а не ошибка. Вы можете использовать как глобальные, так и локальные имена, которые совпадают.

Однако я бы не стал вызывать os.walk() вызов в глобальной области видимости в любом случае . Я бы предпочел поместить это и в функцию, которая имеет счастливый побочный эффект от имен, которые вы использовали, больше не глобальные.

Например, вы можете использовать функцию main() :

Вообще говоря, вы не хотите оставлять имена циклов, такие как root, ds, fs , как глобальные переменные в вашем модуле. Это детали реализации, и они не должны становиться частью общедоступного API модуля. Если у вас есть для использования цикла for , подобного этому, в глобальной области, используйте _ префиксы с одним подчеркиванием в именах и рассмотрите возможность их удаления после цикла с <> :

Если ваши имена повторяются, используйте «_», чтобы избежать таких предупреждений. Это обычная практика.

Это предупреждение shadows name XX from outer scope — это не проблема PEP8, а реальное предупреждение от Pycharm о том, что повторное использование имен переменных таким образом — плохая идея. Другими словами, это не проблема стиля кода, а то, что может привести к проблемам в более поздних программах.

Мое предложение было бы, ну, во всяком случае, избегать повторного использования имен переменных, когда это возможно. Набрав это:

for root_path, directory_name, file_name in os.walk(root_dir):

Не займет много времени и позволит избежать нежелательных побочных эффектов в будущем.

Тем не менее, если по какой-либо причине вам абсолютно необходимо повторно использовать имена переменных и вы хотите избавиться от предупреждающего сообщения, вы можете отключить его в Pycharm («Настройки» -> «Редактор» -> «Стиль кода» -> «Проверки» -> скрытие имен из внешних областей). Но обычно это плохая идея.

What is the problem with shadowing names defined in outer scopes?

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:

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:

TylerH's user avatar

10 Answers 10

There isn’t any 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 data argument as yadda , but miss one of the places it is used in the function’s body. Now data refers to the global, and you start having weird behaviour — where you would have a much more obvious NameError if you didn’t have a global name 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 foo at 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 .

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 unit test coverage, but well, sometimes you have to maintain less than perfect code and being warned about such possible issues might help.

Peter Mortensen's user avatar

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

In other words, the 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 answer to remove the global variable completely.

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

How to fix “Shadows name from outer scope” in PyCharm

PyCharm is a hugely popular Python IDE developed by JetBrains. PyCharm supports pretty much anything you can think of when you mention a modern IDE, such as debugging, syntax highlighting, project management, smart prompt, automatic completion, unit testing, version control… In addition to that, PyCharm also provides advanced web development for Django, doing data science with Anaconda and even IronPython.

While working with PyCharm, you might encounter some warning, a few of them are not Python error messages. “Shadows name from outer scope” is one of the most common error message that spread confusion among new users. This article will explain why it happens and what you can do to avoid it.

Why does “Shadows name from outer scope” happens?

Let’s take the code snippets below as our example :

You can clearly see that in the first line we define the_list in the global scope, and inside the function data_log , we reused that name. Reusing names in and out of functions will be referred as “shadowing names” in PyCharm, therefore causes “Shadows name from outer scope”. This is just a warning and doesn’t make your code unable to run.

While there’s nothing wrong with the example and it runs just fine, it can be the beginning of strange behaviour if you continue to ignore the error message.

Imagine data_log takes in not one but a few more arguments, and the inner logic of it gets more complex. You decide to manually rename the_list to array_object , but leaves a few miss here and there.

If you run the code again, it might just work, but the results will certainly be strange. That is because now the_list refers to the global object, array_object refers to the local one, they are different and you mixed them back and forth inside your function.

Avoid “Shadows name from outer scope”

Now that we know the reason behind the warning, the solution is quite simple : You need to avoid reusing names in your code.

Doing so will not only reduce weird behaviour in your code, but also make debugging easier, since you would end up with NameError if Python cannot find a global name or local name.

One more thing to remember is that you should not “shadow” modules, classes and functions the same way you shadow names, too.

Python – the problem with shadowing names defined in outer scopes

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:

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:

Best Solution

There isn't any 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 data argument as yadda , but miss one of the places it is used in the function's body. Now data refers to the global, and you start having weird behaviour — where you would have a much more obvious NameError if you didn't have a global name 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 foo at 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 .

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 unit test coverage, but well, sometimes you have to maintain less than perfect code and being warned about such possible issues might help.

Related Solutions
Python – the naming convention in Python for variable and function names

Function names should be lowercase, with words separated by underscores as necessary to improve readability.

Variable names follow the same convention as function names.

mixedCase is allowed only in contexts where that's already the prevailing style (e.g. threading.py), to retain backwards compatibility.

Python – What does the “yield” keyword do

To understand what yield does, you must understand what generators are. And before you can understand generators, you must understand iterables.

Iterables

When you create a list, you can read its items one by one. Reading its items one by one is called iteration:

mylist is an iterable. When you use a list comprehension, you create a list, and so an iterable:

Everything you can use " for. in. " on is an iterable; lists , strings , files.

These iterables are handy because you can read them as much as you wish, but you store all the values in memory and this is not always what you want when you have a lot of values.

Generators

Generators are iterators, a kind of iterable you can only iterate over once. Generators do not store all the values in memory, they generate the values on the fly:

It is just the same except you used () instead of [] . BUT, you cannot perform for i in mygenerator a second time since generators can only be used once: they calculate 0, then forget about it and calculate 1, and end calculating 4, one by one.

Yield

yield is a keyword that is used like return , except the function will return a generator.

Here it's a useless example, but it's handy when you know your function will return a huge set of values that you will only need to read once.

To master yield , you must understand that when you call the function, the code you have written in the function body does not run. The function only returns the generator object, this is a bit tricky.

Then, your code will continue from where it left off each time for uses the generator.

Now the hard part:

The first time the for calls the generator object created from your function, it will run the code in your function from the beginning until it hits yield , then it'll return the first value of the loop. Then, each subsequent call will run another iteration of the loop you have written in the function and return the next value. This will continue until the generator is considered empty, which happens when the function runs without hitting yield . That can be because the loop has come to an end, or because you no longer satisfy an "if/else" .

Your code explained

This code contains several smart parts:

The loop iterates on a list, but the list expands while the loop is being iterated. It's a concise way to go through all these nested data even if it's a bit dangerous since you can end up with an infinite loop. In this case, candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) exhaust all the values of the generator, but while keeps creating new generator objects which will produce different values from the previous ones since it's not applied on the same node.

The extend() method is a list object method that expects an iterable and adds its values to the list.

Usually we pass a list to it:

But in your code, it gets a generator, which is good because:

  1. You don't need to read the values twice.
  2. You may have a lot of children and you don't want them all stored in memory.

And it works because Python does not care if the argument of a method is a list or not. Python expects iterables so it will work with strings, lists, tuples, and generators! This is called duck typing and is one of the reasons why Python is so cool. But this is another story, for another question.

You can stop here, or read a little bit to see an advanced use of a generator:

Controlling a generator exhaustion

Note: For Python 3, use print(corner_street_atm.__next__()) or print(next(corner_street_atm))

It can be useful for various things like controlling access to a resource.

Itertools, your best friend

The itertools module contains special functions to manipulate iterables. Ever wish to duplicate a generator? Chain two generators? Group values in a nested list with a one-liner? Map / Zip without creating another list?

Then just import itertools .

An example? Let's see the possible orders of arrival for a four-horse race:

Understanding the inner mechanisms of iteration

Iteration is a process implying iterables (implementing the __iter__() method) and iterators (implementing the __next__() method). Iterables are any objects you can get an iterator from. Iterators are objects that let you iterate on iterables.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *