Search code examples
pythonpyglet

Why append() is called every loop?


I have got the tile class:

class Tile:
    tile_pref = {
        "sprites": []
    }
    pos = Vector2(vector_zero)

    def img(self, x, y, tilemap, t):
        return self.tile_pref["sprites"][0]

    def __init__(self, img, pos):
        self.tile_pref["sprites"].append(img)
        self.pos = pos

And another part, cropped: src is valid string path, spacing, tile_size, offset are vectors with .x and .y. self.__tiles__ is array.

img = pyglet.image.load(src)
for i in range((img.height - offset.x) // (spacing.x + tile_size.x) + 1):
  for j in range((img.width - offset.y) // (spacing.y + tile_size.y) + 1):
                a = offset.x + (tile_size.x + spacing.x) * j
                b = offset.y + (tile_size.y + spacing.y) * i
                self.__tiles__.append(Tile(img.get_region(a, b, tile_size.x, tile_size.y), Vector2(i, j)))

Main problem is in what tile_pref["sprites"] is not 1 in length, bu equals to all amount of tiles. How can I fix it?


I think, when I call img.get_region, it returns me a link to it. So, it calls append any time link is changing.


Solution

  • Here:

    class Tile:
        tile_pref = {
            "sprites": []
        }
        pos = Vector2(vector_zero)
    

    You are defining tile_pref and pos as class attributes - attributes that belong to the class (not to the instances of...), and are shared amongst all instances. Unless shadowed by an instance attribute, class attributes are also available thru the instance (which is how you can access methods, which ARE class attributes), so here:

    def __init__(self, img, pos):
        self.tile_pref["sprites"].append(img)
    

    you are actually mutating the class's own tile_pref attribute - so whatever you add here will be visible to all instances.

    Note that the following line:

        self.pos = pos
    

    creates a 'pos' instance attribute (you are binding the name, not mutating), which will shadow the class attribute.

    For what it's worth, all this is clearly and explicitely documented in the official tutorial - so I kindly suggest you stop what you're doing, take a day (or two if needed) to do the whole tutorial, then come back to your code. This will save you a lot of time and pain and frustration.