Nonlocal that Python beginners (junior high school students) were addicted to (sorry for not being able to explain)

background

Junior high school student K (second appearance) did not move as expected and started crying. I fixed it, but there was still a haze about nonlocal. I will leave it because the haze has disappeared.

Programs that don't work

Try to find out what is the cause.

Programs that don't work


import tkinter as tk

count = 0

def dispLabel():
    count = count + 1
    lbl.configure(text = str(count) + "Pressed twice")


root = tk.Tk()
root.geometry("300x80")

lbl = tk.Label(text="Count button")
btn = tk.Button(text="Press", command = dispLabel)

lbl.pack()
btn.pack()
tk.mainloop()

When the button is displayed and I press the button, I get an error.

Execution result


Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\masa\Anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "c:\Users\masa\OneDrive\document\python\lessen_tk.py", line 6, in dispLabel     
    count = count + 1
UnboundLocalError: local variable 'count' referenced before assignment

It's a basic mistake that you make a mistake if you don't understand scope and local variables.

I want to increment the global count in dispLabel (), but if there is a value assigned to count in dispLabel (), count will be recognized as a local variable and I will not be able to refer to the global variable ( If you don't assign to count, you can refer to global.) Therefore, if you refer to a value, you will get an error because it is before the value is assigned (see the bonus for details).

Try to fix

It's also Darui to explain, so I took a look at the example of the Python tutorial and had them understand the law.

Python tutorial example

Tutorial sample


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)

Mr. K who understood that the variables in the function are treated differently from the outside, I copied the tutorial and fixed it as follows.

amendment


def dispLabel():
    nonlocal count
    count = count + 1
    lbl.configure(text = str(count) + "Pressed twice")

Execution result

Execution result


  File "c:\Users\masa\OneDrive\document\python\lessen_tk.py", line 6
    nonlocal count
    ^
SyntaxError: no binding for nonlocal 'count' found

Mr. T: "You can add nonlocal or global, but you can't." Me: What is this? ?? "If you set it to global count, it will work. I don't know." And make the tea muddy. (I'm sorry I can't explain) Of course, it worked when I made it global.

Why not nonlocal?

Why doesn't nonlocal allow you to refer to variables in the outer namespace? I knew nonlocal, but I didn't actually use it.

python documentation

The nonlocal statement makes sure that the listed identifiers refer to the previously bound variable in the scope one outside except global. This is important because the default behavior of bindings first searches the local namespace. This statement allows the code inside to rebinding variables outside the local scope other than the global (module) scope.

Names listed in the nonlocal statement, unlike names listed in the global statement, must refer to a binding that already exists in the outer scope (the choice of scope in which the new binding should be created is ambiguous. Cannot be ruled out).

Cause summary

--In this example, the count outside the dispLabel () scope is global. Therefore, it is not a nonlocal target. --global will create a variable if executed, but nonlocal must exist before it can be created

bonus

If you just read the global variable count in a function without declaring global, you don't need to declare global. However, if there is an assignment to count, count will be recognized as a local variable. Note, it seems to be judged by the existence of the count = line, not by whether count = was executed. Even in the following case, count is recognized as a local variable and an exception of referenced before assignment is thrown on the line of a = (I didn't understand it, so I tried it and it was like this).

def dispLabel():
    a = count + 1
    if False:
        count=a
    lbl.configure(text = str(count) + "Pressed twice")

Recommended Posts

Nonlocal that Python beginners (junior high school students) were addicted to (sorry for not being able to explain)
[Python] Ikiri high school students will explain blockchain to beginners in 10 minutes! !! !!
WebDriver methods that Python beginners were looking for first
SIR model that even junior high school students can understand
[Python] I tried to explain words that are difficult for beginners to understand in an easy-to-understand manner.
~ Tips for beginners to Python ③ ~
I was addicted to not being able to use Markdown on pypi's long_description