msg201002 - (view) |
Author: Austin Bingham (abingham) |
Date: 2013-10-23 07:00 |
When passed a weakref.proxy to a legitimate sequence, reversed() throws a TypeError complaining that its argument isn't a sequence. Perhaps this is the expected behavior, but it's surprising to at least me and the few others I've spoken with about it. |
|
|
msg201069 - (view) |
Author: PCManticore (Claudiu.Popa) *  |
Date: 2013-10-23 21:26 |
Attached an attemptive patch. |
|
|
msg213526 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2014-03-14 09:00 |
Thanks for looking at this. Putting in a special case for weak references isn't the way to go. The problem is that _PyObject_LookupSpecial isn't working well with weakref proxies. A solution for reversed() could be to replace ``PyObject_GetAttrString(seq, "__reversed__")`` with the slower call to ``_PyObject_LookupSpecial(seq, "__reversed__", &reversed_cache);``. The unfortunate downside is that this would slow down the common cases. Another solution is to patch _PyObject_LookupSpecial to make it smarter with respect to weakref objects or possibly use a fallback to PyObject_GetAttrString when a method isn't found using the speedy lookup. The advantage of fixing _PyObject_LookupSpecial is that it fixes all uses of _PyObject_LookupSpecial not just reversed(). Also, it would keep the current speed benefit for the common case. I'm reassigning to Benjamin because it was his optimized that broke the ability to find the __reversed__ method on a proxy object. Another issue that needs to be looked at is whether PySequence_Check() needs to be made aware of weakref proxies. |
|
|
msg213528 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2014-03-14 10:04 |
I suppose Benjamin's commit is afd62eb1692e. Claudiu, that doesn't look like the best approach to me. Instead of hardcoding a weakref.proxy check in reversed(), why not implement __reversed__ on weakref.proxy? |
|
|
msg213529 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2014-03-14 10:07 |
It would also perhaps be practical to have some kind of "proxy mixin" that everyone can re-use to avoid having to reimplement __special__ methods by hand. |
|
|
msg213530 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2014-03-14 10:11 |
Another possible idea is to introduce a "proxy protocol" (__proxy__ / tp_proxy) that would be used as a fallback by PyObject_LookupSpecial to fetch the lookup target, i.e.: def PyObject_LookupSpecial(obj, name): tp = type(obj) try: return getattr(tp, name) except AttributeError: return getattr(tp.tp_proxy(), name) (not sure that makes sense, I haven't thought very hard about it) |
|
|
msg213562 - (view) |
Author: Benjamin Peterson (benjamin.peterson) *  |
Date: 2014-03-14 15:14 |
afd62eb1692e wasn't a matter of speed, but a matter of correctness. Special methods should be looked up on the type on the instance as was done before. |
|
|
msg388678 - (view) |
Author: Irit Katriel (iritkatriel) *  |
Date: 2021-03-14 17:52 |
On 3.10 the reversed_proxy_failure.py script fails with Traceback (most recent call last): File "/Users/iritkatriel/src/cpython/tmp.py", line 18, in reversed(weakref.proxy(foo)) # TypeError AttributeError: 'Foo' object has no attribute '__reversed__' |
|
|