43

I keep seeing functions and documentation like this and this (to name a few) which operate on or refer to list-like objects.

I'm quite aware of what exactly an actual list is (dir(list)), and can deduce what (often varying) methods from a list are necessary in most references to a "list-like object", however the number of times I see it referenced has left me with the following question:

Is there an official or common knowledge standard minimal interface for a "list-like" object? Is it as simple as actualizing__getitem__, or is it agreed that additional things like __len__ and __setitem__are required as well?

This may seem like semantics, but I can't help but think that if there does not exist a standard minimal interface requirement, various ideas of "list-likeness" could cause some issues/improper handling. Perhaps this is just a slight downside to Python's duck typing?

HavelTheGreat
  • 3,299
  • 2
  • 15
  • 34
  • possible duplicate of [Comprehensive list of Python protocols/interfaces](http://stackoverflow.com/questions/6087731/comprehensive-list-of-python-protocols-interfaces) – aruisdante Mar 03 '15 at 20:59
  • Yes, it does, if you click through the links to the [python data model](https://docs.python.org/2/reference/datamodel.html). A `list` is an implementation of a *mutable sequence*. The data model describes what that entails. Much documentation simply calls that a 'list-like' because list is essentially the canonical implementation of a *mutable sequence*, but it is by no means the only one. – aruisdante Mar 03 '15 at 21:02
  • 14
    Welcome to the wonderful world of duck typing. –  Mar 03 '15 at 21:21
  • 3
    @aruisdante Those are some pretty poor link-only answers that do not address the OP's question. – Uyghur Lives Matter Mar 03 '15 at 23:16
  • 1
    @cpburnz While they're definitely link only, and not the highest quality in terms of explaining the link, I'm not really sure how you don't provide a comprehensive list of standard python protocols (which being *list-like* obstinately is, hence the suggested duplicate), without linking to them, especially since the links are to the core python doc. SO certainly wouldn't be the proper place for such a repository. Having said that, Antii's answer certainly covers the specific case, hence why I upvoted it. – aruisdante Mar 03 '15 at 23:21
  • 3
    @aruisdante References are great, but simply linking to them is not good enough for a stackoverflow answer. A summary of the information should be provided. Also, the [data model](https://docs.python.org/2/reference/datamodel.html) documentation is a very dense read. Without already having an understanding of how things work, it's not very clear which methods go with which protocol. – Uyghur Lives Matter Mar 03 '15 at 23:30

3 Answers3

42

See the collections.abc module. Of the abstract base classes listed there, list in Python implements Iterable, Container, Sized, Sequence and MutableSequence. Now, of these, Iterable, Sequence and MutableSequence could be casually called list-like.

However, I would understand the term list-like to mean that it is a MutableSequence - has at least the methods __getitem__, __setitem__, __delitem__ and __len__, expecting also it to have the mixin methods mentioned in the documentation, such as append.

If there is no need for __setitem__ and __delitem__ it should be called a sequence instead - the assumption is that if something accepts a sequence, it does not need to be mutable, thus str, bytes, tuple etc also work there.


Your two links highlight the vagueness of the term:

The plotly API requires that the list-like objects will be serialized to a JSON array by the internal PlotlyJSONEncoder that delegates most of the encoding to the Python JSONEncoder. However, the latter encodes only tuple and list (and subclasses) to a JSON array; thus the list-like here means a list, a tuple or subclasses thereof. A custom sequence object that is not a subclass of either will result in TypeError: [...] is not JSON serializable.

The unzip recipe you linked to requires an object that behaves like a Sequence, (mutability is not required), thus a tuple or str, or any custom object implementing Sequence will do there.


TL;DR list-like is a vague term. It is preferable to use the terms iterable, sequence and mutable sequence instead, now that these are defined in collections.abc.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
11

The technical term for a "list-like object" is sequence. At the very least it supports ordering (i.e. two objects with the same elements but different order are not equal), indexing (foo[bar] such that bar is an integer less than the length of the sequence), and containment checking (in), and has a given length. It should support iteration, but if not then Python will simulate it using indexing.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 5
    I think "mutable sequence" would be more accurate. A tuple for example is a sequence, but it does not support item assignment (`__setitem__`) like a list does. If a function is documented to take a list-like object, it could very well intend to mutate that object. –  Mar 03 '15 at 21:12
  • 2
    @iCodez: We will agree to disagree. I personally feel that modifying mutable arguments is pathological behavior, since there's no guarantee (beyond the documentation, of course) that the argument will be mutable in the first place. – Ignacio Vazquez-Abrams Mar 03 '15 at 21:13
  • 4
    The python data model pretty specifically states that a list is a mutable sequence. Any API specifying a list-like will almost certainly expect mutablilty, otherwise it would (or at least should) use a different term. The goodness/badness of parameters that are used as both input and output is not really part of the scope of the python data model. In addition, the API might be specifying it *returns* a list-like, in which case the point about modifying inputs is moot. – aruisdante Mar 03 '15 at 21:26
  • @aruisdante APIs that return list-likes are another issue - the API may expect me to modify it with `__setitem__` (which will notify it of the modification I want to make), but may not handle `__delitem__`, append, slices, etc. – Random832 Mar 03 '15 at 21:58
  • @Random832 It will if it actually returns a *list-like* that follows the data model for what a list is. The data model pretty specifically states that a list is a mutable sequence, and a mutable sequence must suport those operations (except append, that's not part of being a mutable sequence). If it doesn't, it shouldn't call it a *list-like*, because it's not. But yes, duck typing in general is quite nebulous. – aruisdante Mar 03 '15 at 22:01
  • 2
    @aruisdante If you have citations for these claims, you should post them as an answer. – Random832 Mar 03 '15 at 22:02
  • @Random832 I did. The linked duplicate, and in my comments afterwards where I directly cited the python data model. Of course an API is free to not do that, it's just documentation after all, but that's always a risk in a dynamic duck-typed language. The best you can do really at the end of the day is try to do something with the object, and catch the error if it fails. – aruisdante Mar 03 '15 at 22:03
  • 1
    It's not clear at all that this is meant to be a contract. In particular, terms like "some" sequences (support extended slicing) suggest it's meant to be descriptive. Now, `list` _does_ support extended slicing, but it's no more clear that "list-like" requires this than support for its other methods (or, for that matter, isinstance(..., list)). I'm also interested to know how append is not part of being a mutable sequence: "Mutable sequences should provide methods append(), count(), index(), extend(), insert(), pop(), remove(), reverse() and sort(), like Python standard list objects." – Random832 Mar 03 '15 at 22:06
  • 1
    @Random832 hmm, I must have missed that in the doc when I read it. But you're right, it's not a strict contract, because Python has no way of enforcing one. All a description like *list-like* could ever do is be a convention even if it had an explisit definition. At the end of the day, the best you can do in a dynamic, duct-typed language is try and do something with an object and catch the error if it fails. You might be able to argue, however, that [abstract base classes](https://docs.python.org/2/glossary.html#term-abstract-base-class) are a move towards more formalized interface defintions – aruisdante Mar 03 '15 at 22:10
8

Pretty much any time you see "-like object" in Python documentation the author is being deliberately vague. The author has decided that enumerating all the required interfaces would be too much trouble, and is only saying that some of its interfaces are required. An object that implemented all the interfaces is guaranteed to work, but in most cases it will work with an object that implements much less.

With a "list-like object" probably the best you can do, short of inspecting the source code, is to infer whether it needs any of the mutable interfaces. If it only needs read-only access to the list, you can be pretty sure you don't need to implement any of the mutable sequence operations.

If it says "list-like object or iterator" you can provide something that implements the much simpler iterator interface.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112