0

The code I made works, but I want to know why. I accidentally made a mistake in the code, but for some reason it works, why? When I pass lastkeys to move.mov, shouldn't keys be a new variable? The same with ent.playerlocation, shouldn't be player in move.mov be a new variable? The original variable is changed to the value of the new one when I exit the function. I've tried to recreate this, but haven't been able to.

main.py:

import pygame
import move, updatescreen

class entities:
    def __init__(self):
        self.playerlocation = [64,64]

if __name__ == '__main__':
    pygame.init()
    screen=pygame.display.set_mode((640,360),pygame.RESIZABLE,32)#pygame.FULLSCREEN
    pygame.display.set_caption('Pygame Window')

    ent = entities()
    lastkeys = [0,0,0,0]
    ispaused = 0

    while True:
        move.userevents(lastkeys)
        move.mov(lastkeys, ent.playerlocation)
        updatescreen.gameupdate(screen,ent)

move.py:

import pygame, sys

def userevents(keys):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                keys[0] = 1
            elif event.key == pygame.K_RIGHT:
                keys[1] = 1
            elif event.key == pygame.K_UP:
                keys[2] = 1
            elif event.key == pygame.K_DOWN:
                keys[3] = 1
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                keys[0] = 0
            elif event.key == pygame.K_RIGHT:
                keys[1] = 0
            elif event.key == pygame.K_UP:
                keys[2] = 0
            elif event.key == pygame.K_DOWN:
                keys[3] = 0

def mov(keys,player):
    if keys[0]:
        player[0] -=1
    elif keys[1]:
        player[0] +=1
    if keys[2]:
        player[1] -=1
    elif keys[3]:
        player[1] +=1
jleahy
  • 16,149
  • 6
  • 47
  • 66
kommihe
  • 441
  • 2
  • 6
  • 11
  • 1
    possible duplicate of [Python: How do I pass a variable by reference?](http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference) (I understand that this is almost exactly the opposite of what you're asking, but the answers are relevant, and more importantly, every time this question is asked (about 5 times a day) on SO, it generates an incredible amount of disinformation from people who don't know the difference between assignment and mutating objects, or the difference between a name and a variable, so... – Wooble Apr 26 '12 at 11:31

2 Answers2

2

When you pass in a mutable object it gets passed in by reference (thus, any modifications you make to it affects the original object). For example:

>>> def change_list(lst):
...   lst[0] = lst[0] * 2
... 
>>> a = [1,2,3]
>>> change_list(a)
>>> a
[2, 2, 3]

So either make a copy of the list before you pass it into the function:

>>> def change_list(lst):
...   lst[0] = lst[0] * 2
... 
>>> a = [1,2,3]
>>> cpy_a = list(a)
>>> change_list(cpy_a)
>>> a
[1, 2, 3]

Or after it's passed into the function:

>>> def change_list(lst):
...   lst_cpy = list(lst)
...   lst_cpy[0] = lst_cpy[0] * 2
... 
>>> a = [1,2,3]
>>> change_list(a)
>>> a
[1, 2, 3]

For a more thorough discussion, please see: How do I pass a variable by reference?

Community
  • 1
  • 1
shu zOMG chen
  • 436
  • 3
  • 8
  • 2
    **All** objects are passed by reference. But with immutable ones, it doesn't matter... – glglgl Apr 26 '12 at 10:09
  • How do I not pass by reference? – kommihe Apr 26 '12 at 10:10
  • I still don't get it, if I do bar = 0 and then def foo(bar):bar+=1 then bar is still 0 – kommihe Apr 26 '12 at 10:14
  • 2
    Objects aren't passed, _references_ to objects are passed - by value – John La Rooy Apr 26 '12 at 10:17
  • @kommihe: Every value is an object. Objects are always passed by reference. But there are *immutable* objects that will copy themselves when trying to modify them. Numbers are immutable, so `bar += 1` changes the *variable* `bar` to hold a *new* immutable number and the original one is not modified (it's immutable!). – Ferdinand Beyer Apr 26 '12 at 11:28
  • 1
    @FerdinandBeyer: umm, no. Not even close. – Wooble Apr 26 '12 at 11:29
  • @FerdinandBeyer: Python is *not* pass-by-reference unless one redefines that term (sadly, many do) - pass-by-reference implies `def change(x, val): x = val` does something useful (also see ). Some prefer the term [call by object](http://effbot.org/zone/call-by-object.htm), which has the advantage of being unknown and thus not abused for a hundred different semantics. What you call a variable does not hold any object, it holds what Python calls a reference (some prefer the term "name" due to that difference from e.g. C's variables). –  Apr 26 '12 at 11:58
  • Technically, you are right. The subtle differences have been discussed a million times already. It does not make sense to explain all the details over and over again, I was being fuzzy on purpose to make it easier to understand. – Ferdinand Beyer Apr 26 '12 at 13:03
  • @kommihe in any case, the solution for you is to make a copy of the list either before or after the function call. You might be tempted to use the `copy` or `deepcopy` functions from the `copy` module, but you should just do `lst_copy = list(some_lst)` – shu zOMG chen Apr 26 '12 at 18:19
1

When I pass lastkeys to move.mov, shouldn't keys be a new variable?

No, objects are always passed by reference in Python. If you pass a list to a function, and the function modifies the list, then the modification is visible from the caller side afterwards.

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145