[pypy-issue] Issue #2034: PyPy Regression with Python on Iterable expansions (pypy/pypy)

Pedro Rodriguez issues-reply at bitbucket.org
Fri Apr 24 07:41:57 CEST 2015


New issue 2034: PyPy Regression with Python on Iterable expansions
https://bitbucket.org/pypy/pypy/issue/2034/pypy-regression-with-python-on-iterable

Pedro Rodriguez:

I am the main developer on github.com/EntilZha/ScalaFunctional and in working on it I found a regression with Python. I don't know if it is an intended regression, but it caused some unexpected behavior which I was able to narrow down. If you want the full explanation, it is on the issue on the project here: https://github.com/EntilZha/ScalaFunctional/issues/25

Below is a minimal code example showing the regression between pypy and python. The primary problem is how `pypy` is doing expansions of iterables (`list()`, `set()`, `dict()`, ...). When those are expanded `pypy` will call `__iter__`, then `__len__`. Python will only call `__iter__`.


```
#!python

from collections import Iterable

class A(object):
    def __init__(self, seq):
        self.l = seq
    def __getitem__(self, item):
        print "DEBUG:getitem called"
        return self.l[item]
    def __iter__(self):
        print "DEBUG:iter called"
        return iter(self.l)
    def __len__(self):
        print "DEBUG:len called"
        if isinstance(self.l, Iterable):
            self.l = list(self.l)
        return len(self.l)

class B(object):
    def __init__(self, seq):
        self.l = seq
    def __iter__(self):
        print "DEBUG:iter called"
        return iter(self.l)

# set interchangable with list/dict
print "Calling set(A([1, 2]))"
a = A([1, 2])
print set(a)


print "Calling set(B([1, 2]))"
b = B([1, 2])
print set(b)

print "Calling union"
s = set([1, 2, 3]).union([4, 5])
c = A(iter(s))
print set(c)

```


```
#!python
$ python iterable.py
Calling set(A([1, 2]))
DEBUG:iter called
set([1, 2])
Calling set(B([1, 2]))
DEBUG:iter called
set([1, 2])
Calling union
DEBUG:iter called
set([1, 2, 3, 4, 5])
$ pypy iterable.py
Calling set(A([1, 2]))
DEBUG:len called
DEBUG:iter called
[1, 2]
Calling set(B([1, 2]))
DEBUG:iter called
set([1, 2])
Calling union
DEBUG:iter called
DEBUG:len called
set([])

```

In my code, the solution would be fairly easy to do type checking and not rewrap the iterator within another iterator. Regardless, since I am unfamiliar with `pypy` I don't know if the regression is intended or unintended.




More information about the pypy-issue mailing list