putting globals into a python class and while loop shuffle

I realized today that when I updated the last post, the pygame paint like program, that I didn't leave any explanations or show the major mistakes I made.

Since this blogs intentions are to help fellow learners, it seems really important I explain some things.

First: Putting the globals into their own class

Imagine you have a pile of crayola red crayons, and for some reason the monsters under the bed will not go away until each red crayon is put into it's original box.

Some have labels, some don't.  Some are used, some are not.

Now pythonic is to CAPitilize a global variable, but outside of a class, they can be changed and altered by the whim of another method.
It's true you can alter attributes in an initiated class from a method, but it is a local change.  My class of globals has no function within it to alter the original set attributes.

I made my own crayon box, and every piece inside has a label as to where it came from.

some links supporting how hard it is to get or change attributes in a class:

https://stackoverflow.com/questions/9058305/getting-attributes-of-a-class
https://stackoverflow.com/questions/44046920/changing-class-attributes-by-reference

If my crayons are in a class:

class Crayon(object):
    def __init__(self):
        self.red = "red"
        self.blue = "blue"
        self.green = "green"
        self.RGB = (self.red, self.green, self.blue)

So now I can see where the variable is, where it's stored, and it is alterable only by calling an initiated class to change it.
Original set values to the Crayons class will not alter
(sepecially if you don't put a method in the class that allows a self.variable change)

You can alter an initiated class

GLOBALS have no container, no specific identity of storage
They can accidentally be altered and changed with effects to the whole file
I want to modify my pygame paint easily and readably in the future
Using global settings (or in my code a class holding the globals I want)  to place all draws and features throughout will make it easier to alter, read and experiment on (test too!)

I wrote a little code to test it.
pic of my results:






#!usr/bin/python3
# -*- coding: utf-8 -*-

CRAYON = 'red'

print("global crayon before method = ", CRAYON)

CRAYON = "The tips of my toes in winter."

print("global crayon after new assignment =", CRAYON)


def change_global(color):
    global CRAYON
    CRAYON = color

change_global("spam and eggs")

print("global crayon after method = ", CRAYON)

class Crayons(object):
    def __init__(self):
        self.red = 'red'
        self.blue = 'blue'
        self.green = 'green'
        self.attr_list = [self.red, self.green, self.blue]

    def get_attr(self, color):
        for things in self.attr_list():
            if things == color:
                return color

    def print_attr(self, color):
        red = self.red
        if color == red:
            return self.red
        else:
            return None
   
    def _alter_attr_all(self):
        self.red = 'Blasphemy'
        self.green = 'Blue and yellow had an ugly baby'
        self.blue = 'water from the sky'




box = Crayons()
original = Crayons()
print("box instance attribute red = ", box.red)
print("original instance attribute red =", original.red)


""" let us change some instances and compare---> """
def change_class_attr(thing):
    thing.red = 'blood of the viking troll'

change_class_attr(box)

print("class change red = ", box.red)
print("after box instance change, original = ", original.red)

"""Lets try changing it without a method:"""
box.red = 'No more brownies for YOU!'
original.red = 'slightly pink, a bit rare'
print("did it change outside the method?", box.red)
print("did it change the original?", original.red)

#make a new instance:
new_origin = Crayons()
print("Is the written class altered? red =", new_origin.red)



"""Make a method to alter original class attributes, see what happens ---> """


Crayons._alter_attr_all(box)
Crayons._alter_attr_all(original)
Crayons._alter_attr_all(new_origin)
another_instance = Crayons()

print("box red now equals =", box.red)
print("original blue now equals=", original.blue)
print("new_origin green now equals=", new_origin.green)
print("new instance after changes red = ", another_instance.red)


 In short, an instance can be altered changed, and traced easier (IMHO)
and the original global variables will be protected by the class container.

 From all of that, I hope I explained why I think it is a good idea, if you are going to need to use some global variables, that you store them in a nice protective container like a class. 
Note: I don't think it's possible to put the pygame initial calls inside this class
exmpl:  screen = pg.display.set_mode(WIDTH, HEIGHT)
error on trying to make it in my globals class like this:
self.screen = pg.display.set_mode(self.WIDTH, self.HEIGHT)
I believe because pygame can not accept variables that have not been intiated...


Second: Crazy while loop shuffle!

Here's the original run loop I had for the pygame paint:
Forgive me oh mighty python gods, I was just trying to make it all work!
I really was going to fix it all after the hard stuff was done!
And I did.... **especially since this dogged my CPU down so bad it started running it's fans hard every time I ran the .py**
A friendly reminder from the Learn Code the Hard Way forum, when I asked why my CPU was freaking out:  That's way too many nested loops!

So, a class engine was born, everything got sorted and neat as you can see in the previous post. 

It was a lot easier then I thought to shuffle it out.  It seemed like it would be a tremendous trial and error, but it just worked, and easy peasy.
This is how NOT to do it:

def run_draw(self):
        red = 0
        green = 0
        blue = 0
        on = False
        off = False
        new = False
        color_pick = False
        color = (red, green, blue)
        screen.fill(globals.background_color)
        picker_window = False
        new_window = None
        while self.running:
            #sleep(1) <---- no circles drawn to screen
            #sleep(0.1)  <---- slight lag, circles being draw, CPU still Whirring during run
            animation_timer.tick(60)
            screen.fill(globals.background_color)
            self.center_surface.draw_surface()
            pg.draw.rect(screen, globals.menu_bar_color, (0, 0, globals.WIDTH, globals.HEIGHT//20), 0)
            pg.draw.rect(screen, globals.menu_bar_color, (0, globals.HEIGHT - globals.HEIGHT//20, globals.WIDTH, globals.HEIGHT//20), 0)
            for rects in self.rect_list:
                rects.place_rect()
            for circs in self.drawn_circs:
                circs.add_circle()
            for window in self.windows:
                window.run(red, green, blue)
            mousedown = False
            events = pg.event.get()
            for event in events:
                if event.type == pg.QUIT:
                    self.running = False
                    pg.quit()
                    exit(0)
                if event.type == pg.MOUSEBUTTONDOWN:
                    position = pg.mouse.get_pos()
                    # cbd = Current Button Dimensions
                    # list returned = [x position, y postion, x postion + width, y position + height]
                    for rects in self.rect_list:
                        cbd = rects.get_rect_place()
                        if cbd[0] < position[0] < cbd[2]:
                            if cbd[1] < position[1] < cbd[3]:
                                #print("IN BUTTON", rects.name)
                                if rects.name == "ON":
                                    on = True
                                    off = False
                                if rects.name == "OFF":
                                    off = True
                                    on = False
                                    color_pick = False
                                    if len(self.windows) > 0:
                                        self.windows.pop()
                                if rects.name == "NEW":
                                    new = True
                                    color_pick = False
                                if rects.name == 'COLOR':
                                    on = True
                                    new = False
                                    color_pick = True
                                    off = False
                                    new_window = ColorPicker()
                                    self.windows.append(new_window)
                            else:
                                pass

            for event in events:
                if event.type == pg.MOUSEBUTTONDOWN and not off and on and new and not color_pick:

                    radius = 20
                    (x, y) = pg.mouse.get_pos()
                    # dsp = Drawn Screen Parameters
                    limit_x_left = self.dsp[0] - radius
                    limit_x_right = self.dsp[2] - radius
                    limit_y_top = self.dsp[1] - radius
                    limit_y_bottom = self.dsp[3] - radius

                    if limit_x_left < x < limit_x_right:
                        if limit_y_top < y < limit_y_bottom:

                            color = (red, green, blue)

                            circle = DrawCircle(screen, x, y, radius, color)
                            self.drawn_circs.append(circle)

                    for rects in self.rect_list:
                        cbd = rects.get_rect_place()
                        if cbd[0] < position[0] < cbd[2]:
                            if cbd[1] < position[1] < cbd[3]:
                                #print("IN BUTTON", rects.name)
                                if rects.name == "ON":
                                    on = True
                                    off = False
                                if rects.name == "OFF":
                                    off = True
                                    on = False
                                    color_pick = False
                                    if len(self.windows) > 0:
                                        self.windows.pop()
                                if rects.name == "NEW":
                                    new = True
                                    color_pick = False
                                if rects.name == 'COLOR':
                                    on = True
                                    new = False
                                    color_pick = True
                                    off = False
                                    new_window = ColorPicker()
                                    self.windows.append(new_window)
                            else:
                                pass

                if event.type == pg.MOUSEBUTTONDOWN and on and color_pick and not off and not new:

                    (gx, gy, gdx, gdy) = new_window.get_button_place("plus green")
                    (g2x, g2y, g2dx, g2dy) = new_window.get_button_place("minus green")
                    (bx, by, bdx, bdy) = new_window.get_button_place("plus blue")
                    (b2x, b2y, b2dx, b2dy) = new_window.get_button_place("minus blue")
                    (rx, ry, rdx, rdy) = new_window.get_button_place("plus red")
                    (r2x, r2y, r2dx, r2dy) = new_window.get_button_place("minus red")
                    (shx, shy, shdx, shdy) = new_window.get_button_place("plus shade")
                    (sh2x, sh2y, sh2dx, sh2dy) = new_window.get_button_place("minus shade")
                    position = pg.mouse.get_pos()
                    if gx < position[0] < gdx and gy < position[1] < gdy:
                        if 0 <= green <= 250:
                            green += 5
                    elif g2x < position[0] < g2dx and g2y < position[1] < g2dy:
                        if 255 >= green >= 5:
                            green -= 5
                    elif bx < position[0] < bdx and by < position[1] < bdy:
                        if 0 <= blue <= 250:
                            blue += 5
                    elif b2x < position[0] < b2dx and b2y < position[1] < b2dy:
                        if 255 >= blue >= 5:
                            blue -= 5
                    elif rx < position[0] < rdx and ry < position[1] < rdy:
                        if 0 <= red <= 250:
                            red += 5
                    elif r2x < position[0] < r2dx and r2y < position[1] < r2dy:
                        if 255 >= red >= 5:
                            red -= 5
                    elif shx < position[0] < shdx and shy < position[1] < shdy:
                        # I tried increments of 10, shade difference was much more dramatic
                        if 0 <= red <= 250:
                            red += 5
                        if 0 <= green <= 250:
                            green += 5
                        if 0 <= blue <= 250:
                            blue += 5
                    elif sh2x < position[0] < sh2dx and sh2y < position[1] < sh2dy:
                        if 255 >= red >= 5:
                            red -= 5
                        if 255 >= green >= 5:
                            green -= 5
                        if 255 >= blue >= 5:
                            blue -= 5

                    else:
                        print("-----color picker event else clause----")
                        for rects in self.rect_list:
                            cbd = rects.get_rect_place()
                            if cbd[0] < position[0] < cbd[2]:
                                if cbd[1] < position[1] < cbd[3]:
                                    #print("IN BUTTON", rects.name)
                                    if rects.name == "ON":
                                        on = True
                                        off = False
                                    if rects.name == "OFF":
                                        # I have to double click to get color picker off... need fixed
                                        off = True
                                        on = False
                                        color_pick = False
                                        if len(self.windows) > 0:
                                            self.windows.pop()
                                    if rects.name == "NEW":
                                        new = True
                                        color_pick = False
                                    if rects.name == 'COLOR':
                                        on = True
                                        new = False
                                        color_pick = True
                                        off = False
                                        new_window = ColorPicker()
                                        self.windows.append(new_window)
                                else:
                                    pass

            if on:
                item = self.object_list[0]
                item.draw_circle()

            if off:
                item = self.object_list[1]
                item.draw_circle()
            #print(" object_list length ==========", len(self.object_list))
            pg.display.flip()





















Comments

Popular posts from this blog

playing with color in powershell python

JavaScript Ascii animation with while loops and console.log

playing with trigonometry sin in pygame