Heisenberg strikes again!

Discussion in 'Python' started by neeson, Sep 10, 2003.

  1. neeson

    neeson Guest

    Alright, I'm fairly new to Python, and this one has got me stumped.
    I've just started to write a cli program that'll use readline, and
    I've attached the relevant bits.

    Here's the mystery: If I so much as /look/ at the list 'matches',
    readline stops working. Run the program, hit tab at the prompt,
    you'll get 'one', which is incorrect, as there are in fact four
    possible completions. Now comment out the line that I've marked
    (which, incidentally, does nothing). /Now/ it works.

    Is there some very strange side effect to accessing a list element
    that I'm unaware of? I've tried it in two different versions of
    Python.

    Any elightenment would be appreciated...

    Heath

    ps In terms of being useful, this program doesn't make any sense. I'm
    not trying to get it to work, I'm looking to understand why the
    commented line affects the rest of the code.


    #!/usr/bin/python

    import readline
    import sys

    commands = ["one", "two", "three", "four"]
    matches = []

    def comp(text, state):
    if state == 0:
    matches = []
    n = len(text)
    for cmd in commands:
    if cmd[:n] == text:
    matches.append(cmd)
    throwaway = matches[0] # <--- Comment out this line
    return commands[state]

    readline.set_completer(comp)
    readline.parse_and_bind("tab: complete")

    while 1:
    try:
    line = raw_input("> ")
    except EOFError:
    print "\n",
    sys.exit()
    print ": %s" % line
     
    neeson, Sep 10, 2003
    #1
    1. Advertising

  2. neeson

    rzed Guest

    neeson wrote:
    > Alright, I'm fairly new to Python, and this one has got me stumped.
    > I've just started to write a cli program that'll use readline, and
    > I've attached the relevant bits.
    >
    > Here's the mystery: If I so much as /look/ at the list 'matches',
    > readline stops working. Run the program, hit tab at the prompt,
    > you'll get 'one', which is incorrect, as there are in fact four
    > possible completions. Now comment out the line that I've marked
    > (which, incidentally, does nothing). /Now/ it works.
    >
    > Is there some very strange side effect to accessing a list element
    > that I'm unaware of? I've tried it in two different versions of
    > Python.
    >
    > Any elightenment would be appreciated...
    >
    > Heath
    >
    > ps In terms of being useful, this program doesn't make any sense.
    > I'm not trying to get it to work, I'm looking to understand why the
    > commented line affects the rest of the code.
    >
    >
    > #!/usr/bin/python
    >
    > import readline
    > import sys
    >
    > commands = ["one", "two", "three", "four"]
    > matches = []
    >
    > def comp(text, state):
    > if state == 0:
    > matches = []
    > n = len(text)
    > for cmd in commands:
    > if cmd[:n] == text:
    > matches.append(cmd)
    > throwaway = matches[0] # <--- Comment out this line


    What is supposed to happen when state != 0? 'matches' will not exist
    at that point.

    > return commands[state]
    >
    > readline.set_completer(comp)
    > readline.parse_and_bind("tab: complete")
    >
    > while 1:
    > try:
    > line = raw_input("> ")
    > except EOFError:
    > print "\n",
    > sys.exit()
    > print ": %s" % line
     
    rzed, Sep 10, 2003
    #2
    1. Advertising

  3. neeson

    David C. Fox Guest

    neeson wrote:

    > Alright, I'm fairly new to Python, and this one has got me stumped.
    > I've just started to write a cli program that'll use readline, and
    > I've attached the relevant bits.
    >
    > Here's the mystery: If I so much as /look/ at the list 'matches',
    > readline stops working. Run the program, hit tab at the prompt,
    > you'll get 'one', which is incorrect, as there are in fact four
    > possible completions. Now comment out the line that I've marked
    > (which, incidentally, does nothing). /Now/ it works.
    >
    > Is there some very strange side effect to accessing a list element
    > that I'm unaware of? I've tried it in two different versions of
    > Python.


    No, but there is a side effect of accessing the first element of an
    empty list: namely, Python raises an IndexError exception (i.e. index
    out of range).

    > Any elightenment would be appreciated...
    >
    > Heath



    >
    > import readline
    > import sys
    >
    > commands = ["one", "two", "three", "four"]
    > matches = []
    >
    > def comp(text, state):
    > if state == 0:
    > matches = []


    Because you haven't used

    global matches

    the next statement creates a new list called matches as a variable local
    to comp. All your matching commands are added to this variable, which
    disappears when comp returns.


    > n = len(text)
    > for cmd in commands:
    > if cmd[:n] == text:
    > matches.append(cmd)



    > throwaway = matches[0] # <--- Comment out this line


    When comp is called with state == 0, matches is still referring to the
    local list which is not empty (unless there were no matches to the
    text), so this line does indeed do nothing. However, when comp is
    called with state != 0, this line refers to the global matches list,
    which is empty, so it raises an IndexError, and the following line is
    not reached.

    Apparently, readline treats an exception in the completer as equivalent
    to returning None. In fact, you seem to be relying on this behavior
    implicitly in the line below, because you are not checking whether state
    < len(commands)

    > return commands[state]
    >
    > readline.set_completer(comp)
    > readline.parse_and_bind("tab: complete")


    David
     
    David C. Fox, Sep 10, 2003
    #3
  4. neeson

    John J. Lee Guest

    "David C. Fox" <> writes:
    [...]
    > Apparently, readline treats an exception in the completer as
    > equivalent to returning None. In fact, you seem to be relying on this

    [...]

    That's pretty unpleasant. Naked except:s (with no specific exception)
    can cause about the weirdest bugs it's possible to get in Python. I
    think it's worth filing an SF documentation bug (or a patch, better)
    about that: set_completer should mention it.

    While debugging your completer function, try putting the whole content
    of the function in a big try: except:, and use the traceback module:

    from traceback import print_exc

    def my_completer(text, state):
    try:
    # put everything here
    ...
    except:
    print_exc()


    John
     
    John J. Lee, Sep 11, 2003
    #4
  5. neeson

    neeson Guest

    Thank you! That answers my questions precisely. :) You can see my
    c/c++/java biases showing. Expecting global variables to carry into
    functions and not expecting silent exceptions to alter my execution
    paths. Valuable lessons!

    Heath


    "David C. Fox" <> wrote in message news:<nRM7b.311656$Oz4.100417@rwcrnsc54>...
    > neeson wrote:
    >
    > > Alright, I'm fairly new to Python, and this one has got me stumped.
    > > I've just started to write a cli program that'll use readline, and
    > > I've attached the relevant bits.
    > >
    > > Here's the mystery: If I so much as /look/ at the list 'matches',
    > > readline stops working. Run the program, hit tab at the prompt,
    > > you'll get 'one', which is incorrect, as there are in fact four
    > > possible completions. Now comment out the line that I've marked
    > > (which, incidentally, does nothing). /Now/ it works.
    > >
    > > Is there some very strange side effect to accessing a list element
    > > that I'm unaware of? I've tried it in two different versions of
    > > Python.

    >
    > No, but there is a side effect of accessing the first element of an
    > empty list: namely, Python raises an IndexError exception (i.e. index
    > out of range).
    >
    > > Any elightenment would be appreciated...
    > >
    > > Heath

    >
    >
    > >
    > > import readline
    > > import sys
    > >
    > > commands = ["one", "two", "three", "four"]
    > > matches = []
    > >
    > > def comp(text, state):
    > > if state == 0:
    > > matches = []

    >
    > Because you haven't used
    >
    > global matches
    >
    > the next statement creates a new list called matches as a variable local
    > to comp. All your matching commands are added to this variable, which
    > disappears when comp returns.
    >
    >
    > > n = len(text)
    > > for cmd in commands:
    > > if cmd[:n] == text:
    > > matches.append(cmd)

    >
    >
    > > throwaway = matches[0] # <--- Comment out this line

    >
    > When comp is called with state == 0, matches is still referring to the
    > local list which is not empty (unless there were no matches to the
    > text), so this line does indeed do nothing. However, when comp is
    > called with state != 0, this line refers to the global matches list,
    > which is empty, so it raises an IndexError, and the following line is
    > not reached.
    >
    > Apparently, readline treats an exception in the completer as equivalent
    > to returning None. In fact, you seem to be relying on this behavior
    > implicitly in the line below, because you are not checking whether state
    > < len(commands)
    >
    > > return commands[state]
    > >
    > > readline.set_completer(comp)
    > > readline.parse_and_bind("tab: complete")

    >
    > David
     
    neeson, Sep 11, 2003
    #5
  6. neeson

    Duncan Booth Guest

    "David C. Fox" <> wrote in
    news:nRM7b.311656$Oz4.100417@rwcrnsc54:

    >> throwaway = matches[0] # <--- Comment out this line

    >
    > When comp is called with state == 0, matches is still referring to the
    > local list which is not empty (unless there were no matches to the
    > text), so this line does indeed do nothing. However, when comp is
    > called with state != 0, this line refers to the global matches list,
    > which is empty, so it raises an IndexError, and the following line is
    > not reached.


    Not quite true there. Whether or not state is 0, this line always tries to
    access the local variable 'matches'. If you assign to a variable anywhere
    in a function (and don't declare it global), then all accesses in the
    function are to the local variable, not the global.

    Of course the effect is basically the same, the function throws an
    exception either way, its just a different exception.

    --
    Duncan Booth
    int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
    "\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?
     
    Duncan Booth, Sep 11, 2003
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Vijay Bajwa
    Replies:
    6
    Views:
    2,022
    Jerry Coffin
    Feb 16, 2007
  2. Aahz

    xkcd strikes again

    Aahz, Apr 21, 2008, in forum: Python
    Replies:
    0
    Views:
    246
  3. Michael Conroy

    Riddle me this... RBL strikes again. Min USENET clue reveals noth

    Michael Conroy, Feb 10, 2005, in forum: ASP .Net Web Controls
    Replies:
    3
    Views:
    102
    Michael Conroy
    Feb 11, 2005
  4. Michael Neumann

    (fwd) [Borges-users] memory strikes back!

    Michael Neumann, May 10, 2004, in forum: Ruby
    Replies:
    1
    Views:
    91
    Yukihiro Matsumoto
    May 19, 2004
  5. David Mark

    Qooxdoo strikes back

    David Mark, Jun 4, 2010, in forum: Javascript
    Replies:
    17
    Views:
    177
    John G Harris
    Jun 9, 2010
Loading...

Share This Page