1

So I was testing one interesting thing in pygame. I know this code is very crappy, but it's just a test. In this programme I have a lists that represent a pygame polygon and list of them. In the function, it returns changed list to draw it. But for some reason, no matter how hard I try, it changes original "polygon" list. But if I set the "mor" variable a ctrl + c ctrl + v of "polygon" list, it works just fine Am I crazy? Shouldn't .copy() create unrelated list? Why "hexagon" changes?

import pygame

pygame.init()
sc = pygame.display.set_mode((1000, 1000))
clock = pygame.time.Clock()
WHITE = (255,255,255)
hexagon = [WHITE,[[669,207],[615,240],[615,305],[669,335],[725,305],[725,240]],8]
hexagon2 = [WHITE,[[669,335],[725,305],[725,240],[669,207],[615,240],[615,305]],8]
hexs = [hexagon,hexagon2]
hex = pygame.Surface((1000,1000))
state = 0
def morph (states,first):
    global state
    done = 0
    current = first
    for i in current[1]:
        a = 0
        for n in i:
            try:
                if n < states[state+1][1][current[1].index(i)][a]:
                    current[1][current[1].index(i)][a] += 1
                elif n > states[state+1][1][current[1].index(i)][a]:
                    current[1][current[1].index(i)][a] -= 1
                else:
                    done += 1
            except:
                if n < states[0][1][current[1].index(i)][a]:
                    current[1][current[1].index(i)][a] += 1
                elif n > states[0][1][current[1].index(i)][a]:
                    current[1][current[1].index(i)][a] -= 1
                else:
                    done += 1
            a += 1
    if done == len(current[1])*2:
        if state + 1 <= len(states):
            state += 1
        else:
            state = 0
    return current
run = True
mor = hexagon[:]
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    hex.fill((0,0,0))
    mor = morph(hexs,mor)
    pygame.draw.polygon(hex,*mor)
    sc.blit(hex,(0,0))
    pygame.display.update()
    clock.tick(60)

pygame.quit()
exit()

Again, sorry for crappy code and bad english

Stepa1411
  • 27
  • 3
  • "Shouldn't .copy() create unrelated list" -- there is a difference between a *deep copy* (which is what you want) and a *shallow copy* (which is what you are creating). – John Coleman Dec 30 '21 at 19:21
  • 2
    You never actually call `.copy()` anywhere. That said, `hexagon[:]` is a *shallow* copy. See the `copy` module, specifically the `copy.deepcopy` function, for copying deeply nested structures. – ShadowRanger Dec 30 '21 at 19:21

1 Answers1

2

Actually this is a very intriguing question!

What is happening is a shallow copy and not a deep copy like you think. For most compreenssion is necessary to note that python comes from the C language and there exist a concept called pointer. A "pointer" is a reference to a memory location and not to the "value" itself.

To better understand follow the script:

l1 = [1,2]
id(l1) # addr 140028122641088

# here the attribution works like a shallow copy
l2 = l1
id(l2) # addr 140028122641088

# here we make a deep copy, also knows a "copy by value"
import copy
l2 = copy.deepcopy(list)
id(l2) # addr 140028122642816

Reference of deepcopy and id

Franz Kurt
  • 1,020
  • 2
  • 14
  • 14