[Python-Dev] New bug in function object hash() and comparisons

Guido van Rossum guido@digicool.com
Sat, 27 Jan 2001 11:57:40 -0500


Barry noticed:

> Anyway, did you know that you can use functions as keys to a
> dictionary, but that you can mutate them to "lose" the element?
> 
> -------------------- snip snip --------------------
> Python 2.0 (#13, Jan 10 2001, 13:06:39) 
> [GCC egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)] on linux2
> Type "copyright", "credits" or "license" for more information.
> >>> d = {}
> >>> def foo(): pass
> ... 
> >>> def bar(): pass
> ... 
> >>> d[foo] = 1
> >>> d[foo]
> 1
> >>> foocode = foo.func_code
> >>> foo.func_code = bar.func_code
> >>> d[foo]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> KeyError: <function foo at 0x81ef474>
> >>> d[bar] = 2
> >>> d[bar]
> 2
> >>> d[foo]
> 2
> >>> foo.func_code = foocode
> >>> d[foo]
> 1
> -------------------- snip snip --------------------
> 
> It's because a function's func_code attribute is used in its hash
> calculation, but func_code is writable!

Clearly, something changed.  I'm pretty sure it's the function
attributes.  Either the function attributes shouldn't be used in
comparing function objects, or hash() on functions should be
unimplemented, or comparison on functions should use simple pointer
compares.

What's the right solution?  Do people use functions as dict keys?  If
not, we can remove the hash() implementation.  But I suspect they
*are* used as dict keys.  Not using the __dict__ on comparisons
appears ugly, so probably the best solution is to change function
comparisons to use simple pointer compares.  That removes the
possibility to see whether two different functions implement the same
code -- but does anybody really use that?

--Guido van Rossum (home page: http://www.python.org/~guido/)