`list()` constructor and `__len__` method

I didn’t say there is a grammatical error. I meant we shouldn’t read it objects <...> that implements but method that implements.

1 Like

Well, it doesn’t matter if you disagree. The sentence can also be parsed the other way around. There are no parentheses or arrows to clearly indicate how to associate the subordinate clause and the conjunction. You might have a favorite interpretation, but both are there.

Not in a grammatically correct way, it cannot.

1 Like

You are simply wrong. An again, there is no grammatical error. Grammatically the sentence is well-formed.

“Objects of any classes that implements sequence semantics” is a grammatically correct sentence?

2 Likes

Yes. It is a grammatically correct sentence. But like most sentences, only if it is not misquoted. E.g. by only providing half of it, and omitting the other half (especially when that contains the verb).

The full original is:

Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() method or with a __getitem__() method that implements sequence semantics.

UPD: Yes, it’s grammatically correct.

And we think this sentence says “the class’ object from the topic start is an iterable (any classes you define with an __iter__() method)”.

If so, list(X) is correct (Using the type constructor: list() or list(iterable)).

On the other hand, @abessman , we had

Lists may be constructed in several ways:

  • Using the type constructor: list() or list(iterable)

iterable may be either a sequence, a container that supports iteration, or an iterator object.

So, maybe iterable here doesn’t refer to https://docs.python.org/3/glossary.html#term-iterable?

@abessman , @franklinvp

The subject of “implements” in the complete sentence is still unambiguously “method”.

1 Like

Is it?

>>> class Iterable:
...     def __getitem__(self, item):
...             if type(item) is int and 0 <= item < 4:
...                     return item **2
...             raise IndexError
... 
>>> list(Iterable())
[0, 1, 4, 9]

As long as __getitem__ implements sequence semantics, the object IS iterable. I’m not sure why this doesn’t make sense to you, but regardless, it is a fact.

My confusion stemmed from the definition of “sequence semantics”, as the definition of sequence specifically mentions both __getitem__ and __len__.

But I guess an iterator can be an iterable that is not a sequence, but is “sequence-like” in that it lacks __len__ but has a suitable __getitem__.

By the way this statement itself doesn’t conform with https://docs.python.org/3/glossary.html#term-sequence:

sequence:
An iterable which supports efficient element access using integer indices via the __getitem__() special method and defines a __len__() method that returns the length of the sequence.

To be a sequence, an object needs getitem and len, both of which must fulfil sequence semantics.

To be iterable, an object needs getitem, which must fulfil sequence semantics. (Or have iter, of course.)

UPD: @Rosuav , do you mean sequence is not equal to sequence semantic? :slight_smile:


One more time. The whole picture.

https://docs.python.org/3/library/stdtypes.html#list:

Lists may be constructed in several ways:

  • Using the type constructor: list() or list(**iterable**)

iterable may be either a sequence, a container that supports iteration, or an iterator object.

https://docs.python.org/3/glossary.html:

iterable:
An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() method or with a __getitem__() method that implements sequence semantics.

sequence:
An iterable which supports efficient element access using integer indices via the __getitem__() special method and defines a __len__() method that returns the length of the sequence.


As I said above, we could change:

Lists may be constructed in several ways:

  • Using the type constructor: list() or list(not_an_iterable_but_another_term)

not_an_iterable_but_another_term may be either a sequence, a container that supports iteration, or an iterator object.

to make the logic correct.


Then:

list may receive not_an_iterable_but_another_term.

not_an_iterable_but_another_term: if any of statements are true:

  • is a sequence, or
  • is a container that supports iteration, or
  • is an iterator object.

iterable: if any of statements are true:

  • list, str, tuple, etc. (sequence type), or
  • dict, file, or
  • with __iter__,
  • with __getitem__ (sequence semantic), or
  • (??? more?).

sequence: if every statement is true:

  1. is an iterable,
  2. with __getitem__,
  3. with __len__.

(??? is this reducible?)

sequence type: < list of types here >

sequence semantic: a class with __getitem__ method. (???)

container that supports iteration: (??? what’s is it? do we really need it?)

iterator: <…>

Why do you want to add so much stuff:

  • the list constructor is fully correctly specified by list(iterable).

  • iterable is anything that can be iterated: Either it has a defined __iter__, or it has a __getitem__ with sequence semantics

  • sequence has __getiem__ and __len__

The only problem is that currently sequence semantics isn’t defined, and linking to sequence is confusing.

What is meant is that if an object does not have __iter__, but it does have __getitem__, python will automatically do stuff equivalent to the following code:

def iter_getitem(obj):
    for i in count(0):
        try:
            yield obj[i]
       except IndexError:
            return

not_an_iterable_but_another_term is completely pointless. iterable is the correct term. Misbehaving __len__ methods are not to be taken into consideration.

No, it isn’t Compare above, please.

Ok, a simpler solution:

Lists may be constructed in several ways:

  • Using the type constructor: list() or list(sequence) or list(container) or list(iterator).

See sequence, iterator in the Glossary.
container is a container that supports iteration (??? needs a definition).

Yes, it is. Everything you listed under not_an_iterable_but_another_term is an iterable, and I can’t think of anything that is an iterable that doesn’t fall into that category. Please give me an object that is in one set but not in the other.

I started the topic with it:

class A:
    def __iter__(self):
        for i in range(8):
            yield i
    def __len__(self):
        raise NotImplementedError

iterable:
An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() method or with a __getitem__() method that implements sequence semantics.

It is an iterable but list() can’t handle it.

… And? That is in both categories. It can be passed to list and it falls into the category of iterable. What breaks in OP is a misbehaving __len__. __len__ should return a number between 0 and sys.maxsize or raise a TypeError (in which case list behaves as if it isn’t defined). You doing something wrong (i.e. raising NotImplementedError) just means that a different contract isn’t specified enough, not that the documentation is wrong.

It can’t be passed.