Message118214
| Author |
rbp |
| Recipients |
arno, rbp, rhettinger |
| Date |
2010年10月08日.18:51:38 |
| SpamBayes Score |
4.440892e-15 |
| Marked as misclassified |
No |
| Message-id |
<1286563900.05.0.424485161186.issue10017@psf.upfronthosting.co.za> |
| In-reply-to |
| Content |
If I'm understanding this correctly, this fails on 3.1 and not (although, actually, it does) on py3k/3.2 because:
* pprint._safe_key.__lt__ checks "rv = self.obj.__lt__(other.obj)" and falls back to id comparison if rv is NotImplemented
* If the object passed to _safe_key is a class, self.obj.__lt__ will expect *self* as well as the other object. Therefore the verification above fails with "TypeError: expected 1 arguments, got 0". You can see that pprint works with an instance:
>>> pprint.pprint({A(): 1, 1: 2})
{<__main__.A object at 0x8594d4c>: 1, 1: 2}
* Finally, this works on py3k *for your example* because, for some reason, on py3k the comparison is being based on the 1 key. That is, the comparison on _safe_key.__lt__ happens to be 1.__lt__(A), instead of A.__lt__(1). Perhaps hashing changed after the 3.1 release?
Anyway, py3k still fails when you force the comparison to happen on the class:
>>> class B(object): pass
...
>>> pprint.pprint({A: 1, B: 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 55, in pprint
printer.pprint(object)
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 132, in pprint
self._format(object, self._stream, 0, 0, {}, 0)
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 155, in _format
rep = self._repr(object, context, level - 1)
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 245, in _repr
self._depth, level)
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 257, in format
return _safe_repr(object, context, maxlevels, level)
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 299, in _safe_repr
items = sorted(object.items(), key=_safe_tuple)
File "/home/rbp/python/dev/py3k/Lib/pprint.py", line 89, in __lt__
rv = self.obj.__lt__(other.obj)
TypeError: expected 1 arguments, got 0
>>>
So, basically, the fix on issue 3976 does't (always) work when there are classes as dict keys. I think switching from
rv = self.obj.__lt__(other.obj)
if rv is NotImplemented:
to something like
try:
rv = self.obj < other.obj
except TypeError:
rv = (str(type(self.obj)), id(self.obj)) < \
(str(type(other.obj)), id(other.obj))
solves this. Or we can check first whether self.obj is a 'type', but I think it gets convoluted.
If anyone can confirm that that's the way to go, I can produce one (though it's a trivial one). Raymond? |
|
History
|
|---|
| Date |
User |
Action |
Args |
| 2010年10月08日 18:51:40 | rbp | set | recipients:
+ rbp, rhettinger, arno |
| 2010年10月08日 18:51:40 | rbp | set | messageid: <1286563900.05.0.424485161186.issue10017@psf.upfronthosting.co.za> |
| 2010年10月08日 18:51:38 | rbp | link | issue10017 messages |
| 2010年10月08日 18:51:38 | rbp | create |
|