Bug with python mode

image

txt = '1';

def setup():
    size(600,600)
    noFill()
    noStroke()

def draw():
    fill('#FF0000') # red quadrant
    rect(width/2,0, width/2,height/2)

    fill('#004477') # blue quadrant
    rect(0,0, width/2,height/2)

    fill('#6633FF') # violet quadrant
    rect(0,height/2, width/2,height/2)

    fill('#FF9900') # orange quadrant
    rect(width/2,height/2, width/2,height/2)
    
    fill(255)
    if mouseX < width/2 and mouseY < height/2:
        #text("BLUE",mouseX,mouseY)
        txt = 'BLUE'
    if mouseX < width/2 and mouseY > height/2:
        #text("PURPLE",mouseX,mouseY)
        txt = 'PURPLE'
    if mouseX > width/2 and mouseY < height/2:
        #text("RED",mouseX,mouseY)
        txt = 'RED'
    if mouseX > width/2 and mouseY > height/2:
        #text("YELLOW",mouseX,mouseY)
        txt = 'YELLOW'
    text(txt,mouseX,mouseY)

I don’t know why but after some time the program just crashes

2 Likes
2 Likes

Try using the ‘global’ keyword inside the draw function.
This keyword is to be used if you want to assign the value of an initialized global variable inside a function.

txt = '1';

def setup():
    size(600,600)
    noFill()
    noStroke()

def draw():
    global txt
    fill('#FF0000') # red quadrant
    rect(width/2,0, width/2,height/2)

    fill('#004477') # blue quadrant
    rect(0,0, width/2,height/2)

    fill('#6633FF') # violet quadrant
    rect(0,height/2, width/2,height/2)

    fill('#FF9900') # orange quadrant
    rect(width/2,height/2, width/2,height/2)
    
    fill(255)
    if mouseX < width/2 and mouseY < height/2:
        #text("BLUE",mouseX,mouseY)
        txt = 'BLUE'
    if mouseX < width/2 and mouseY > height/2:
        #text("PURPLE",mouseX,mouseY)
        txt = 'PURPLE'
    if mouseX > width/2 and mouseY < height/2:
        #text("RED",mouseX,mouseY)
        txt = 'RED'
    if mouseX > width/2 and mouseY > height/2:
        #text("YELLOW",mouseX,mouseY)
        txt = 'YELLOW'
    text(txt,mouseX,mouseY)
3 Likes

Great question @CodeMasterX, and the answers by @SierraMike and @GoToLoop will help you solve this issue :slight_smile:

Just to give you a bit more context of what is going on… in your code without modifications your local txt variable fails to be assigned in some edge case (I would guess it is when the mouse is exactly in the middle of the screen and no if clauses are True).

One solution would be at the start of draw() to assign txt = '1' (then you don’t need the global assignment, please remove it from the start of your sketch for clarity!) otherwise you should be using the global statement for the global variable strategy as the other answers have indicated.

5 Likes

You were correct, I fixed it now:

txt = '1';

def setup():
    size(600,600)
    noFill()
    noStroke()

def draw():
    fill('#FF0000') # red quadrant
    rect(width/2,0, width/2,height/2)

    fill('#004477') # blue quadrant
    rect(0,0, width/2,height/2)

    fill('#6633FF') # violet quadrant
    rect(0,height/2, width/2,height/2)

    fill('#FF9900') # orange quadrant
    rect(width/2,height/2, width/2,height/2)
    
    fill(255)
    if mouseX < width/2 and mouseY < height/2:
        #text("BLUE",mouseX,mouseY)
        txt = 'BLUE'
    elif mouseX < width/2 and mouseY > height/2:
        #text("PURPLE",mouseX,mouseY)
        txt = 'PURPLE'
    elif mouseX > width/2 and mouseY < height/2:
        #text("RED",mouseX,mouseY)
        txt = 'RED'
    elif mouseX > width/2 and mouseY > height/2:
        #text("YELLOW",mouseX,mouseY)
        txt = 'YELLOW'
    else:
        txt = 'NONE'
    text(txt,mouseX,mouseY)
1 Like

Hi, @CodeMasterX,

It is important to note that there are two variables named txt in your program, one being global, and the other one local to the draw function. Because the draw function contains at least one assignment to txt, and the variable was not explicitly declared global within the function, that name refers to a local variable by that name, wherever used inside the function, even if none of those assignment statements ever gets executed. Of course, your else block does guarantee that at least one of the assignments will get executed, but that has no bearing on the scope of that variable.

If you do display the value of the global variable, txt, you will find that it is distinct from the local variable by that name. To demonstrate that, add this function to your code, making sure that its header is not indented, and call it from within the draw function:

def print_the_global_txt():
    # txt is not assigned anything within this function, 
    # therefore, we are accessing the global variable, txt
    print(txt)

You can add a call to the function as the final line in the draw function, indented directly under the call to text, as shown here:

    text(txt,mouseX,mouseY)
    print_the_global_txt()

Alternatively, you can place the call within one of the conditional blocks.

Regardless of what happens inside the draw function, the print_the_global_txt function will always display 1 in the console when it is called, because it is accessing the global variable.

See official documentation at Python.org: What are the rules for local and global variables in Python?. It states:

In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.

3 Likes

In short, b/c the global variable txt isn’t used as such anywhere within your sketch, but only as a local variable inside callback draw(), you should delete txt = '1'; for clarity of intention. :yin_yang:

BtW, semicolons aren’t needed in Python, unless we want more than 1 statement in the same line. :wink:

3 Likes
ys = 0
g = 0.1
x = 300
y = 50

def setup():
    size(600,600)
    delay(1000)
def draw():
    # global ys
    # global g
    # global x
    # global y
    background(0)
    ys += g
    y += ys
    ellipse(x,y,15,15)

image

It says here that the variables declared at the top of the code will automatically become global variables. So why does it still need global? Is the tutorial outdated or for a different version of processing.py?

(I am learning processing.py through https://tabreturn.github.io/code/processing/python/2018/08/10/processing.py_in_ten_lessons-4.1-_animation.html )

1 Like

The tutorial written is correct and not obselete.

It says:



You need to include the keyword 'global ’ only when you want to reassign that variable inside a function.

Here, you are reassigning the value of the global variable inside the draw() function.

If you do not want to include that keyword, another alternative is first overriding the value of the global variables inside the draw() function and then assigning them.

ys = 0
g = 0.1
x = 300
y = 50

def setup():
    size(600,600)
    delay(1000)
def draw():
    ys = 0
    g = 0.1
    x = 300
    y = 50
    background(0)
    ys += g
    y += ys
    ellipse(x,y,15,15)

Hope this helps! :smile:

3 Likes

Yes, that is true. However, if you create another variable with the same name within an inner scope, such as a function definition, the global variable by that name will still exist, but will not be visible within that inner scope, except with the use of some particular coding gymnastics, which are not covered in this post. So while you do have a global variable named txt, that name refers only to the local variable when it is used within the draw function.

If, however, you declare txt as global within the function, the name, whether used within the function or in the global scope, will refer to the global variable by that name, and no local variable by that name will be created within that particular function.

That may seem like an arbitrary rule, at first, but I think it is a good language feature.

5 Likes
  • In short we can read from existing global variables within a function.
  • But once we need to write a value to them, 1st we’ve gotta declare them via keyword global.
  • Otherwise Python will treat them as local variables, temporarily overshadowing their corresponding global versions within that function.
5 Likes