diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-09-14 00:25:33 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-09-14 00:25:33 (GMT) |
commit | 0ab085c4cba79c1743288a300425b3c9050250ba (patch) | |
tree | aa0436b634cc45a83f710bdf94289deefd540d9b /Lib/test | |
parent | 742dfd6f178c3880248c32d64322e2cff8cea23f (diff) | |
download | cpython-0ab085c4cba79c1743288a300425b3c9050250ba.zip cpython-0ab085c4cba79c1743288a300425b3c9050250ba.tar.gz cpython-0ab085c4cba79c1743288a300425b3c9050250ba.tar.bz2 |
Changed the dict implementation to take "string shortcuts" only when
keys are true strings -- no subclasses need apply. This may be debatable.
The problem is that a str subclass may very well want to override __eq__
and/or __hash__ (see the new example of case-insensitive strings in
test_descr), but go-fast shortcuts for strings are ubiquitous in our dicts
(and subclass overrides aren't even looked for then). Another go-fast
reason for the change is that PyCheck_StringExact() is a quicker test
than PyCheck_String(), and we make such a test on virtually every access
to every dict.
OTOH, a str subclass may also be perfectly happy using the base str eq
and hash, and this change slows them a lot. But those cases are still
hypothetical, while Python's own reliance on true-string dicts is not.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_descr.py | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index f1af5b9..06631dc 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1533,8 +1533,8 @@ def inherits(): verify(str(s) == base) verify(str(s).__class__ is str) verify(hash(s) == hash(base)) - verify({s: 1}[base] == 1) - verify({base: 1}[s] == 1) + #XXX verify({s: 1}[base] == 1) + #XXX verify({base: 1}[s] == 1) verify((s + "").__class__ is str) verify(s + "" == base) verify(("" + s).__class__ is str) @@ -1758,6 +1758,39 @@ f = t(%r, 'w') # rexec can't catch this by itself except: pass +def str_subclass_as_dict_key(): + if verbose: + print "Testing a str subclass used as dict key .." + + class cistr(str): + """Sublcass of str that computes __eq__ case-insensitively. + + Also computes a hash code of the string in canonical form. + """ + + def __init__(self, value): + self.canonical = value.lower() + self.hashcode = hash(self.canonical) + + def __eq__(self, other): + if not isinstance(other, cistr): + other = cistr(other) + return self.canonical == other.canonical + + def __hash__(self): + return self.hashcode + + verify('aBc' == cistr('ABC') == 'abc') + verify(str(cistr('ABC')) == 'ABC') + + d = {cistr('one'): 1, cistr('two'): 2, cistr('tHree'): 3} + verify(d[cistr('one')] == 1) + verify(d[cistr('tWo')] == 2) + verify(d[cistr('THrEE')] == 3) + verify(cistr('ONe') in d) + verify(d.get(cistr('thrEE')) == 3) + + def all(): lists() dicts() @@ -1794,6 +1827,7 @@ def all(): inherits() keywords() restricted() + str_subclass_as_dict_key() all() |