Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__reversed__ method not called when calling reversed() #1073

Closed
nilp0inter opened this issue Jan 16, 2015 · 4 comments
Closed

__reversed__ method not called when calling reversed() #1073

nilp0inter opened this issue Jan 16, 2015 · 4 comments

Comments

@nilp0inter
Copy link

Hi,

I'm trying to implement reverse iteratoration using the dunder method reversed.
I'm having problems because reversed is not called; instead, the interpreted is trying to reverse the iterator using len and getitem.

This is my code and my expected result (I'm using CPython 3.4 here):

>>> class I:                     
    def __iter__(self):
        return (x for x in range(10))
    def __reversed__(self):
        return (x for x in range(9, -1, -1))
...     
>>> list(I())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(reversed(I()))              
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> 

Instead of the desired result I'm getting this on Micro Python v1.3.3 PYBv1.0:

>>> list(I())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(reversed(I()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'I' has no len()
>>> 

Thank you.

Best regards,
Roberto

@pfalcon
Copy link
Contributor

pfalcon commented Jan 17, 2015

Current known workaround is to write list(my_reversed(I())) or list(I().__reversed__()). I doubt you'll need to change more than couple of places in your code. reversed() is used pretty rarely on its own, and even rare on custom types, so it's on low priority to be fully implemented.

@pfalcon
Copy link
Contributor

pfalcon commented Jan 17, 2015

Oh, and now it's possible to override builtins, so you can implement it in Python and override builtin.

@dpgeorge
Copy link
Member

Well, the patch to implement it is 3 semicolon-lines and 1 qstr:

diff --git a/py/objreversed.c b/py/objreversed.c
index b614958..7e84743 100644
--- a/py/objreversed.c
+++ b/py/objreversed.c
@@ -39,6 +39,13 @@ typedef struct _mp_obj_reversed_t {
 STATIC mp_obj_t reversed_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
     mp_arg_check_num(n_args, n_kw, 1, 1, false);

+    // check if __reversed__ exists, and if so delegate to it
+    mp_obj_t dest[2];
+    mp_load_method_maybe(args[0], MP_QSTR___reversed__, dest);
+    if (dest[0] != MP_OBJ_NULL) {
+        return mp_call_method_n_kw(0, 0, dest);
+    }
+
     mp_obj_reversed_t *o = m_new_obj(mp_obj_reversed_t);
     o->base.type = &mp_type_reversed;
     o->seq = args[0];
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 71a523c..86e2918 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -55,6 +55,7 @@ Q(__file__)

 Q(__bool__)
 Q(__contains__)
+Q(__reversed__)
 Q(__enter__)
 Q(__exit__)
 Q(__len__)

dpgeorge added a commit that referenced this issue Jan 21, 2015
@dpgeorge
Copy link
Member

Now implemented.

tannewt pushed a commit to tannewt/circuitpython that referenced this issue Jul 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants