Python Forum
Understanding Scoping in Python - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Understanding Scoping in Python (/thread-12035.html)



Understanding Scoping in Python - yksingh1097 - Aug-06-2018

I was reading Python docs and encountered this example under "Scope and Namespaces".
def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
The output to this code is
Output:
After local assignment: test spam After nonlocal assignment: nonlocal spam After global assignment: nonlocal spam In global scope: global spam
My question is, why in output, it is
Output:
After global assignment: nonlocal spam
according to me it should be
Output:
After global assignment: global spam
as spam become a global variable after calling do_global(), and value becomes spam = "global spam"


RE: Understanding Scoping in Python - Windspar - Aug-06-2018

Because scope_test already has local variable name spam.
scope looks up local spam first. If not exist then looks for global spam.

spam = "global"

def global_spam():
    print(spam)

def local_spam():
    spam = "local"
    print(spam)

local_spam()
global_spam()



RE: Understanding Scoping in Python - yksingh1097 - Aug-06-2018

(Aug-06-2018, 02:24 PM)Windspar Wrote: Because scope_test already has local variable name spam.
scope looks up local spam first. If not exist then looks for global spam.

spam = "global"

def global_spam():
    print(spam)

def local_spam():
    spam = "local"
    print(spam)

local_spam()
global_spam()


Hi Windspar,
Thanks for your explanation,but let me be more specific about my problem
I know that the scoping in python works by LEGB rule,

But when do_global() is called, control finds that do_global() is creating a global variable spam, which is priorly created in scope_test(). So why the variable spam in scope_test is not get overridden by spam variable of do_global(), as it happened when we called do_nonlocal() function (there value of spam = "test spam" became spam = "nonlocal spam",as you can see in the output)


RE: Understanding Scoping in Python - Windspar - Aug-06-2018

Because global spam only brings in global scope variables. Not non local variables.

# This is global scope area
spam = "global scope"

def print_spam():
    print(spam)

# soon as you get into a function. It a local variable.
def spam_it():
    def update_spam():
        # grabs  spam from 1 layer down.
        nonlocal spam
        spam = "nonlocal"

    def update_global():
        global spam
        spam = "global scope change"

    print_spam()
    spam = "local"
    print(spam)
    update_spam()
    print(spam)
    update_global()
    print_spam()

spam_it()



RE: Understanding Scoping in Python - yksingh1097 - Aug-06-2018

(Aug-06-2018, 05:16 PM)Windspar Wrote: Because global spam only brings in global scope variables. Not non local variables.

# This is global scope area
spam = "global scope"

def print_spam():
    print(spam)

# soon as you get into a function. It a local variable.
def spam_it():
    def update_spam():
        # grabs  spam from 1 layer down.
        nonlocal spam
        spam = "nonlocal"

    def update_global():
        global spam
        spam = "global scope change"

    print_spam()
    spam = "local"
    print(spam)
    update_spam()
    print(spam)
    update_global()
    print_spam()

spam_it()


Okay. Thanks Windspar for your explanation. I understand now.


RE: Understanding Scoping in Python - nilamo - Aug-06-2018

There are three different spam variables. A local spam, within do_local(), a local spam, within scope_test() (which is non-local for enclosed functions), and a global spam, which doesn't exist until after do_global() is called. do_global() creates a new variable in the global scope, but it doesn't change any of the other spams that already exist in other scopes. After do_global() is called, referencing spam uses the local version, which is set to "nonlocal spam" at that time.

If print(spam) were to return "global spam", that would violate scoping, as there's a local spam that exists.

...and that's why you avoid having variables with the same name. It adds unneeded confusion. It's highly unlikely that all three of those refer to the same thing, which means they're all poor choices for a variable name, as none actually describe what a spam is.