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@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

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to