New bug in function object hash() and comparisons
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/)
On Sat, 27 Jan 2001 11:57:40 -0500, Guido van Rossum <guido@digicool.com> wrote: (about function hash doing the wrong thing)
What's the right solution?
I have no idea...
Do people use functions as dict keys? If not, we can remove the hash() implementation.
...but this ain't it. -- Moshe Zadka <sig@zadka.site.co.il> This is a signature anti-virus. Please stop the spread of signature viruses! Fingerprint: 4BD1 7705 EEC0 260A 7F21 4817 C7FC A636 46D0 1BD6
"GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Clearly, something changed. I'm pretty sure it's the GvR> function attributes. Actually no. func_code is used in func_hash() but somewhere in the Python 1.6 cycle, func_code was made assignable. GvR> Either the function attributes shouldn't be used in comparing GvR> function objects, or hash() on functions should be GvR> unimplemented, or comparison on functions should use simple GvR> pointer compares. GvR> What's the right solution? We should definitely continue to allow functions as keys to dictionaries, but probably just remove func_code as an input to the function's hash. -Barry
Me> We should definitely continue to allow functions as keys to Me> dictionaries, but probably just remove func_code as an input Me> to the function's hash. But of course, func_globals won't be sufficient as a hash for functions. Probably changing the hash to a pointer compare is the best thing after all. -Barry
"GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Clearly, something changed. I'm pretty sure it's the GvR> function attributes.
Actually no. func_code is used in func_hash() but somewhere in the Python 1.6 cycle, func_code was made assignable.
Argh! You're right.
GvR> Either the function attributes shouldn't be used in comparing GvR> function objects, or hash() on functions should be GvR> unimplemented, or comparison on functions should use simple GvR> pointer compares.
GvR> What's the right solution?
We should definitely continue to allow functions as keys to dictionaries, but probably just remove func_code as an input to the function's hash.
OK, that settles it. There's not much point in having a function compare do anything besides a pointer comparison when the code objects aren't compared. (Two completely different functions could compare equal e.g. if they has the same attribute dict.) So we should just punt, and compare functions by object pointer. The proper way to do this is to *delete* func_hash and func_compare from funcobject.c -- the default comparison will take care of this. --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (3)
-
barry@digicool.com
-
Guido van Rossum
-
Moshe Zadka