global vs nonlocal in Python (2)



This content originally appeared on DEV Community and was authored by Super Kai (Kazuya Ito)

Buy Me a Coffee☕

*Memos:

First of all, there are 4 kinds of variables from the viewpoint of third() using 2 classes and 3 functions as shown below:

  • A global variable is the variable out of any functions and classes.
  • A non-local variable is the variable within outer functions.
  • A local variable is the variable which is within its function.
  • A class variable is the variable within its class.
""" It's from the viewpoint of `third()` """

num = 2 # <- Global variable
print(num) # 2
class Cls1:
    num = 3 # <- Class variable
    print(num) # 3
    class Cls2:
        num = 4 # <- Class variable
        print(num) # 4
        def first(self):
            num = 5 # <- Non-local variable
            print(num) # 5
            def second():
                num = 6 # <- Non-local variable
                print(num) # 6
                def third():
                    num = 7 # <- Local variable
                    print(num) # 7
                third()
            second()
Cls1().Cls2().first()

A global statement can refer to a global variable as shown below. *The doc explains the rules for local and global variables in Python:

<Read>:

""" It's from the viewpoint of `third()` """

num = 2 # <- 〇
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    global num # Here
                    print(num) # 2
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

# num = 2 # <- Commented
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    global num # NameError: name 'num' is not defined.
                    print(num) # Did you mean: 'sum'?
                third()
            second()
Cls1().Cls2().first()

<Change>:

""" It's from the viewpoint of `third()` """

num = 2 # <- 〇
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    global num # Here
                    num += 10  # Here
                    print(num) # 12
                third()
            second()
Cls1().Cls2().first()
print(num) # 12
""" It's from the viewpoint of `third()` """

# num = 2 # <- Commented
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    global num # NameError: name 'num' is not defined.
                    num += 10  # Did you mean: 'sum'?
                    print(num)
                third()
            second()
Cls1().Cls2().first()
print(num)

A nonlocal statement can refer to a non-local variable as shown below:

<Read>:

""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- 〇
                def third():
                    nonlocal num # Here
                    print(num) # 6
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- 〇
            def second():
                # num = 6 # <- Commented
                def third():
                    nonlocal num # Here
                    print(num) # 5
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            # num = 5 # <- Commented
            def second():
                # num = 6 # <- Commented
                def third():
                    nonlocal num # SyntaxError: no binding
                    print(num)   # for nonlocal 'num' found
                third()
            second()
Cls1().Cls2().first()

<Change>:

""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- 〇
                def third():
                    nonlocal num # Here
                    num += 10    # Here
                    print(num) # 16
                third()
                print(num) # 16
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- 〇
            def second():
                # num = 6 # <- Commemnted
                def third():
                    nonlocal num # Here
                    num += 10    # Here
                    print(num) # 15
                third()
            second()
            print(num) # 15
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            # num = 5 # <- Commemnted
            def second():
                # num = 6 # <- Commemnted
                def third():
                    nonlocal num # SyntaxError: no binding        
                    num += 10    # for nonlocal 'num' found
                    print(num)
                third()
            second()
Cls1().Cls2().first()

Without a global or nonlocal statement, the closest non-local variable or a global variable can be referred to in order as shown below:

<Read>:

""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- 〇
                def third():
                    print(num) # 6
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- 〇
            def second():
                # num = 6 # <- Commented
                def third():
                    print(num) # 5
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- 〇
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            # num = 5 # <- Commented
            def second():
                # num = 6 # <- Commented
                def third():
                    print(num) # 2
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

# num = 2 # <- Commented
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            # num = 5 # <- Commented
            def second():
                # num = 6 # <- Commented
                def third():
                    print(num) # NameError: name 'num' is not defined.
                third()        # Did you mean: 'sum'?
            second()
Cls1().Cls2().first()

<Change>:

""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    num += 10  # UnboundLocalError: cannot access
                    print(num) # local variable 'num' where it is 
                third()        # not associated with a value
            second()
Cls1().Cls2().first()

Using both a global and nonlocal statement in the same function gets error as shown below:

""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    global num   # SyntaxError: name 'num'
                    nonlocal num # is nonlocal and global
                    print(num)
                third()
            second()
Cls1().Cls2().first()
""" It's from the viewpoint of `third()` """

num = 2 # <- ✖
class Cls1:
    num = 3 # <- ✖
    class Cls2:
        num = 4 # <- ✖
        def first(self):
            num = 5 # <- ✖
            def second():
                num = 6 # <- ✖
                def third():
                    nonlocal num # SyntaxError: name 'num'
                    global num   # is nonlocal and global
                    print(num)
                third()
            second()
Cls1().Cls2().first()


This content originally appeared on DEV Community and was authored by Super Kai (Kazuya Ito)