4

The "intuitive" way of getting an iterator for someone who usually programs in Java, C++, etc is something like list.iterator().

Why did the Python folks choose to have it as a general function like len() (which results in iter(list) rather than list.iter())?

The same question can be asked for the length of a construct as well (len()).

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
matanc1
  • 6,525
  • 6
  • 37
  • 57
  • Also related: [Special methods and interface-based type system](https://mail.python.org/pipermail/python-3000/2006-November/004643.html) – Ashwini Chaudhary Aug 08 '14 at 10:51

1 Answers1

4

iter() supports different types of objects.

You can pass in either a sequence (supporting length and item access) or an iterable (which produces an iterator by calling obj.__iter__()) or an iterator (which returns self from __iter__).

The Java list.iter() then is served by list.__iter__() in Python, but the iter() function allows for more types. You can customise the behaviour with a __iter__ method but if you implemented a sequence instead, things will still work.

There is also a second form of the function where a callable and a sentinel are passed in:

iter(fileobj.readline, '')

iterates over a file object by calling the readline() method until it returns an empty string (equal to the second argument, the sentinel).

Then there is the Principle of Least Astonishment argument; iter() gives the standard library a stable API call to standardise on, just like operators do; no need to look up the documentation of the class to see if it implemented obj.iter() or obj.iterator() or obj.get_iterator().

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • So what you're saying is that `iter()` exists so that both sequence types and iterable types will have one method to get an iterator (which follows the Principle of least astonishment)? – matanc1 Aug 08 '14 at 10:58
  • 2
    @Shookie: That, and it's better HCI to have a post-fix function for core language features, just like operators exist to do arithmetic. You are not looking for `(4.3).divide_by(1.4)` either; you use `4.3 / 1.4` instead. – Martijn Pieters Aug 08 '14 at 11:10
  • 1
    I don't understand your argument. Couldn't be the same thing implemented using `varioustypeofobject.iter()`? – Karoly Horvath Aug 08 '14 at 11:38
  • 2
    @KarolyHorvath: sure, in the same way you can do `obj.length()` everywhere. And `int.divide()` and `float.add()`. But by using operators and post-fix functions you can provide a richer and more consistent API. – Martijn Pieters Aug 08 '14 at 11:45
  • 1
    I don't see why it would be more richer and consistent. You can have and use operators with both approaches. To me, it looks like a language design decision, and both paths lead to a rich and consistent language. Can you give an example? – Karoly Horvath Aug 08 '14 at 12:57
  • @KarolyHorvath: how do you propose the `iter()`-with-two-arguments option is implemented as a method on objects? The whole point is to enable iteration for function calls that are not iterable from the start. Nor do standard sequence types have an iterator, so you'd complicate code that wants to support both sequences and iterables. And of course this is a language design decision. – Martijn Pieters Aug 08 '14 at 13:02
  • 1
    huh? Why do you think that's a problem? It's just a different syntax. Example decision: You don't implement it, it comes with a language, it is a builtin, as it is in python. It calls the appropriate dunder magic functions, or whatever is needed, just as in python. But, again, decisions, if you want to ship the solution with the standard library, you can even implement the generic `iter()` in the base `object`. – Karoly Horvath Aug 08 '14 at 13:12
  • @KarolyHorvath: sure, and the language already does that for a lot of things; but part of the language design is to use `__dunder__` method names for such methods and make them *hooks*; places for classes to provide alternate behaviour. This does enable richer behaviour; perhaps not for `iter()` but take a look how `__add__` and `__radd__` work; the interpreter consults both to find an object that can handle the addition, delegating to *the right object*. – Martijn Pieters Aug 08 '14 at 13:37
  • @MartijnPieters: yes, that adds a richer behaviour. just as it would add if you had `o.iter()` or `o.len()`. You're talking about properties of the language that make it reach, not realising that in the parallel universe where you had `o.iter()`, the language would have the same properties and consequences.That universe also has `__add__`, it also has hooks. It has just a different syntax for the "outer" (e.g. `len`) abstraction. – Karoly Horvath Aug 08 '14 at 13:45