[Tutor] lists of lists: more Chutes & Ladders!
spir
denis.spir at gmail.com
Tue Dec 31 10:27:20 CET 2013
On 12/31/2013 06:59 AM, Keith Winston wrote:
> I resolved a problem I was having with lists, but I don't understand how! I
> caught my code inadvertently resetting/zeroing two lists TWICE at the
> invocation of the game method, and it was leading to all the (gamechutes &
> gameladders) lists returned by that method being zeroed out except the
> final time the method is called. That is: the game method below is iterated
> iter times (this happens outside the method), and every time gamechutes and
> gameladders (which should be lists of all the chutes and ladders landed on
> during the game) were returned empty, except for the last time, in which
> case they were correct. I can see that doing the multiple zeroing is
> pointless, but I can't understand why it would have any effect on the
> returned values. Note that self.reset() is called in __init__, so the lists
> exist before this method is ever called, if I understand properly.
>
> def game(self, iter):
> """Single game"""
>
> self.gamechutes[:] = [] #when I take out these two slice
> assignments,
> self.gameladders[:] = [] # then gamechutes & gameladders work
> properly
>
> self.gamechutes = [] # these were actually in a call to
> self.reset()
> self.gameladders = []
>
> #.... other stuff in reset()
>
> while self.position < 100:
> gamecandl = self.move()
> if gamecandl[0] != 0:
> self.gamechutes.append(gamecandl[0])
> if gamecandl[1] != 0:
> self.gameladders.append(gamecandl[1])
> return [iter, self.movecount, self.numchutes, self.numladders,
> self.gamechutes, self.gameladders]
>
> I'm happy to share the rest of the code if you want it, though I'm pretty
> sure the problem lies here. If it's not obvious, I'm setting myself up to
> analyse chute & ladder frequency: how often, in a sequence of games, one
> hits specific chutes & ladders, and related stats.
>
> As always, any comments on style or substance are appreciated.
Well you have found the reason for weird behaviour, but there is one point you
may have missed, I mean not fully understood, else you would probably never have
coded that way.
Imagine there is somewhere in your code, before the resetting of either, some
reference to this list; then you empty this list using the first idiom, the
emptying instruction with [:], like:
original = [1, 2, 3]
# ...
ref_to_list = original # not a copy
# ...
original[:] = [] # empty the same list
# assert checks something is true; else we get an AssertionError:
assert(ref_to_list is original)
assert(ref_to_list == [])
Now, replace the emptying instruction with:
original = [] # assigns another list
Now, assertions are false (both). `ref_to_list` actually still refers to the...
original list; The folllowing is true in this version:
assert(ref_to_list == [1,2,3])
But the symbol `original` itself is not bound to this orignal list anymore (it's
now a liar! a misnomer). In this version, we do not *modify* the list element
(to empty it, for the matter), but *replace* it by a new one (empty right from
the start), bound to `original`.
And as you ask for style comments, I would (this is subject to personal views):
* use '_' for multi-word ids: game_chutes
* say what the 'game' method computes and returns, in comment/doc and in its *name*
(many think a true function, that produces a result, should be named after
its product
-- I share this view -- eg 'square' compute the square of its input)
* 'iter' is a clear misnomer: I would have never guessed if you didn't say it in
text:
use eg n_iters or number_iters or such [*]
(
Denis
[*] In addition, "iter" is also the name of a builtin function, like "print". It
is rarely a good idea to reuse such names, but maybe you did not know it. Here
is what it does (if you don't know yet about iterator objects, this will give
you a fore-taste, but don't bother with that topic before you actually need them):
spir at ospir:~$ python3
Python 3.3.1 (default, Sep 25 2013, 19:29:01)
[GCC 4.7.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> iter
<built-in function iter>
>>> l = [1,2,3]
>>> it = iter(l)
>>> it
<list_iterator object at 0x7f5a63b41c50>
>>> for i in it: print(i)
...
1
2
3
More information about the Tutor
mailing list