Heisenberg strikes again!

David C. Fox davidcfox at post.harvard.edu
Wed Sep 10 17:38:27 EDT 2003


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





More information about the Python-list mailing list