BUG: Make dict iterators real iterators, provide "next()" in Python 2 #12299

Closed
wants to merge 2 commits into
from

Conversation

Projects
None yet
3 participants
Contributor

toobaz commented Feb 11, 2016

Currently, compat.itervalues and friends are not real iterators (under Python 3): compare

In [3]: next(six.itervalues({1:2}))
Out[3]: 2

with

In [4]: next(pd.compat.itervalues({1:2}))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-177f5d3e9571> in <module>()
----> 1 next(pd.compat.itervalues({1:2}))

TypeError: 'dict_values' object is not an iterator

This PR fixes this (it drops support for **kwargs: although it is supported by six, I fail to see what's the utility, and it's anyway apparently not used in the pandas codebase - but if I'm missing something, it is trivial to reintroduce it) and provides next() in Python 2.

Contributor

jreback commented Feb 12, 2016

Why don't we just use the six code almost directly?

if PY3:
    def iterkeys(d, **kw):
        return iter(d.keys(**kw))

    def itervalues(d, **kw):
        return iter(d.values(**kw))

    def iteritems(d, **kw):
        return iter(d.items(**kw))

    def iterlists(d, **kw):
        return iter(d.lists(**kw))

    viewkeys = operator.methodcaller("keys")

    viewvalues = operator.methodcaller("values")

    viewitems = operator.methodcaller("items")
else:
    def iterkeys(d, **kw):
        return d.iterkeys(**kw)

    def itervalues(d, **kw):
        return d.itervalues(**kw)

    def iteritems(d, **kw):
        return d.iteritems(**kw)

    def iterlists(d, **kw):
        return d.iterlists(**kw)

    viewkeys = operator.methodcaller("viewkeys")

    viewvalues = operator.methodcaller("viewvalues")

    viewitems = operator.methodcaller("viewitems")

jreback added the 2/3 Compat label Feb 12, 2016

Contributor

toobaz commented Feb 12, 2016

Makes sense, except that you could not use anymore compat.iteritems(NDFrame), given that NDFrame.iter is not callable (while the six Python 3 version expects it to be so, since dict.iter is).

But still the right thing to do is probably to (also) change each compat.iteritems(NDFrame) to iter(NDFrame.iteritems()). There aren't tons of them.

(then, I still fail to understand the **kw thing, but never mind)

Contributor

jreback commented Feb 12, 2016

yeh the compat was done a long time ago, its possible the actual six code was changed since then (to be better) and we have the original. ok with these kinds of changes (e.g. they do a slightly better check for next compat)

Contributor

kawochen commented Feb 12, 2016

the keyword argument passing is needed to generate the correct error messages.

Contributor

toobaz commented Feb 12, 2016

... I still don't understand: which error messages?

Contributor

kawochen commented Feb 12, 2016

when you pass a keyword argument, the real function gets to tell you that it doesn't need any. the other error messages still are wrong tho. but these things are not super important

Contributor

toobaz commented Feb 12, 2016

Got it!

Contributor

toobaz commented Feb 14, 2016

Above, I clearly made a mistake writing NDFrame.iter rather than NDFrame.items, and anyway it is not NDFrame, but only Series and DataFrame.

That said, I ended up

  • making my compat code semantically equivalent to six - but tell me if you also want it more verbose
  • changing compat.iter*(obj) to obj.iter*() only when obj was an NDFrame with ndim (possibly) >2

What I didn't do but may be worth doing in the medium/long run:

  • changing compat.iter*(obj) to obj.iter*() whenever obj is an NDFrame (and in the short run, not using the former in new code)
  • removing Series.items() and DataFrame.items() (they are aliases for iteritems(), not even documented)

It is true that one driver of the decision would be to avoid problems with features (Panel, in which items is an axis) which will be probably deprecated... but I don't see any downside (apart from a minor one: we are sticking to Python 2-sounding method names).

Contributor

toobaz commented Feb 21, 2016

Is anything expected from me here?

Contributor

jreback commented Feb 21, 2016

write out all of the iter methods there strongly a couple instead of evaluating them at run time

Contributor

toobaz commented Mar 3, 2016

ping

jreback added this to the 0.18.0 milestone Mar 3, 2016

jreback closed this in 9313089 Mar 3, 2016

Contributor

jreback commented Mar 3, 2016

thanks @toobaz

toobaz deleted the toobaz:compat_iters branch Mar 3, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment