Patric Hartmann
Patric Hartmann

Reputation: 748

Python 3/ PyGame: Surfaces Reference / Handling (former title: Strange behaviour of copied dictionaries)

Technical background: Python 3.4 + PyGame 1.9.2 on a Win XP system.

IMPORTANT

The original title was misleading as it turned out that is has NOTHING to do with how Python dictionaries work! It was just a coincidence it happened with a dictionary. I quickly explain the problem, hoping it will be useful to somebody in the future.

There are two dictionaries representing the two players' "boards" (it's kind of a battleship/sea battle as computer game) containing position-tuples (x, y) as keys and surfaces as keys' content. Some Pseudo-Code for clarification:

surface1 = pygame.Surface((w, h)).convert()
surface1.fill(WATER_COLOUR)

dict1 = {(x1, y1): surface1.copy(), (x2, y2): surface1.copy(), (x3, y3): surface1.copy()}
dict2 = dict1.copy()

In the course of the game the players would click on the display and if they'd hit a valid game field, that field would change its colour depending on whether a ship has been hit or not.

def clicked(mousepos, key):
    if active_player == 1:
        if mousepos_inside_enemy_ship_rectangle(mousepos):
            dict1[position_of_mouse].fill((255, 0, 0)) # Make it red
        else:
            dict1[position_of_mouse].fill((0, 0, 0)) # Make it black

To my surprise ALL the square-surfaces would change their colour in both dictionaries! I first thought, it's a problem with the dictionary, until I found out, that it's a problem with how surfaces work in PyGame.

It seems that all surface1.copy() refer to one single copy of surface1. So to say: if I change one of the copies, all the others look the same, they do not really copy it, they just reference it!

Two solutions there are:

  1. Create a surface for each state: one for "not clicked yet", one for "clicked but missed" and one for "clicked and hit". Then change the dictionaries key to the respective surface.

  2. Create an individual surface for each key in the dictionary and then fill them with the respective colours individually. That also works.

Thanks to everybody who tried to resolve it and sorry for the trouble... It's a completely different problem. I updated the title and the keywords, hoping it helps somebody else in the future. I left the old question text for reference. And whoever added the link to that other dictionary question: Please remove it, it's not about dictionaries but surfaces, thanks!

Pat



OLD QUESTION TEXT Left for reference

My script has a function f() returning a dictionary:

def f(data):
    d = {}
    for n in range(len(data)):
        d.update({n: data[n]})
    return d

I need two dictionaries starting with the precisely same data, so I can modify these data in different ways.

dict1 = f(data)
dict2 = dict1.copy()

To my surprise, when I modify dict1 the same changes are also shown by dict2! I thought the copy would be independent from the original - have I misunderstood something?

It has definitely something to do with the .copy() method. When I change my code like this:

dict1 = f(data)
dict2 = f(data)

I receive precisely what I wanted and I can modify both dictionaries differently without interfering with each other.

Basically this solves my problem but it raises a number of questions... Have I misunderstood what .copy() does? Is this a general issue in this Python version?

//edit:

To clarify what I mean by "modify":

Some of the keys' data in dict1 is changed, if the keys meet a certain condition:

for key in dict1:
    if key == meets_this_condition:
        dict1[key] = new_data

In another method I constantly compare the contents of the two dictionaries and call certain functions depending on them either being the same or being different

for key in dict1:
    if dict1[key] == dict2[key]:
        do_something()
    else:
        do_something_else()

Thanks for any insights!

Pat

Upvotes: 0

Views: 101

Answers (1)

Alon
Alon

Reputation: 2929

I would try use deepcopy function something like

  dict2=copy.deepcopy(dict1);

import the copy library

as I remember .copy make a shallow copy so it only copy pointers. so if you modified one in some cases the copy also would be change.

Upvotes: 1

Related Questions