2

This is my first post here, so please excuse me if I do not make myself clear. I searched for this problem beforehand, but didn't know exactly what terms to phrase it in. This code was originally part of a larger program, but I tried cutting out all the other variables and my problem still remains:

What I want this to do is create a function that categorizes a list of numbers in to 7-number sublists. There must be one sublist for each item in the 'player' list, which is why I simply copied the player list and ran a for loop to replace each element (previously the names of players) with their corresponding seven numbers. The number of sets there should be is drawn from the 'player' list, and the numbers themselves are drawn from the 'playermodifier' list, both of which are defined elsewhere in the program.

players=['Paul', 'Darren']
playermodifiers=[4,5,7,2,8,4,7,3,9,4,6,2,6,4]
def modifiersort():
    n=1
    global playermodifierssort
    global playermodifiers
    playermodifierssort=players
    for x in playermodifierssort:
        playermodifierssort[n-1]=playermodifiers[7*(n-1):7*n]
        n=n+1
    playermodifiers=playermodifierssort

This sorts the list as I want it to, however, it also somehow changes the original 'players' list to be identical to playermodifierssort and playermodifiers at the end of the function. When I run the function, I get:

playermodifiers = [[4, 5, 7, 2, 8, 4, 7], [3, 9, 4, 6, 2, 6, 4]]
players = [[4, 5, 7, 2, 8, 4, 7], [3, 9, 4, 6, 2, 6, 4]]

This is problematic because I want to preserve the players list. How can this be happening? The 'players' list isn't global, so how can it be permanently changed as a result of this function?

Paul
  • 21
  • 1

2 Answers2

2

Your line

playermodifierssort=players

is not copying the values of players into playermodifierssort; it's simply making playermodifierssort a reference to players. Thus, any changes to playermodifierssort will also change players. Replace that line with:

playermodifierssort=players[:]

to copy the values of the list and you'll be fine.


Addendum: See this article regarding list copying (reference vs. value). Also, you'll also need to fix your playermodifiers=playermodifierssort line as it has the same problem. It is not copying values -- it simply making playermodifiers reference playermodifierssort.

Another question which might be of use to you.

Community
  • 1
  • 1
Greg Sadetsky
  • 4,863
  • 1
  • 38
  • 48
  • Thanks very much. Problem solved, but I must admit I'm still mystified as to how 'players' can change outside the function even when it hasn't been marked as global. – Paul Mar 07 '16 at 02:45
  • @Paul: you are right that if you did `players = "foo"` inside of the `modifiersort` function, the global `players` would not be changed. However, your line `playermodifierssort=players`, creates a reference to `players` -- the only `players` that exists at that point is the global one. So, once you've created this reference, changing `playermodifierssort` will change `player`. – Greg Sadetsky Mar 07 '16 at 03:30
0

The line:

playermodifierssort=players

binds the variable named playermodifierssort to the players list. Now the list can be accessed through players as well as playermodifierssort. Any changes made to the list through either variable will be reflected in both variables, because it is one list.

But I think that you're going about this the wrong way. For one thing your global players list is trashed when modifiersort() is called. You could rewrite like this without the use of globals:

def modifiersort(players, playermodifiers):
    modifiers = []
    for n in range(len(players)):
        modifiers.append(playermodifiers[7*n:7*(n+1)])
    playermodifiers[:] = modifiers

The last line of the function uses in-place replacement of the playermodifiers list without resorting to global variables. Using the function:

>>> players=['Paul', 'Darren']
>>> playermodifiers=[4,5,7,2,8,4,7,3,9,4,6,2,6,4]
>>> modifiersort(players, playermodifiers)
>>> players
['Paul', 'Darren']
>>> playermodifiers
[[4, 5, 7, 2, 8, 4, 7], [3, 9, 4, 6, 2, 6, 4]]

This can be simplified with a list comprehension:

def modifiersort(players, playermodifiers):
    playermodifiers[:] = [playermodifiers[7*n:7*(n+1)] for n in range(len(players))]

>>> modifiersort(players, playermodifiers)
>>> players
['Paul', 'Darren']
>>> playermodifiers
[[4, 5, 7, 2, 8, 4, 7], [3, 9, 4, 6, 2, 6, 4]]

And, although it does improve code readability if you need to sort from multiple places, the function is not required:

>>> players=['Paul', 'Darren']
>>> playermodifiers=[4,5,7,2,8,4,7,3,9,4,6,2,6,4]
>>> playermodifiers = [playermodifiers[7*n:7*(n+1)] for n in range(len(players))]
>>> players
['Paul', 'Darren']
>>> playermodifiers
[[4, 5, 7, 2, 8, 4, 7], [3, 9, 4, 6, 2, 6, 4]]
mhawke
  • 84,695
  • 9
  • 117
  • 138