Python: the mechanism behind list comprehension

2024/9/20 8:16:07

When using list comprehension or the in keyword in a for loop context, i.e:

for o in X:do_something_with(o)

or

l=[o for o in X]
  • How does the mechanism behind in works?
  • Which functions\methods within X does it call?
  • If X can comply to more than one method, what's the precedence?
  • How to write an efficient X, so that list comprehension will be quick?
Answer

The, afaik, complete and correct answer.

for, both in for loops and list comprehensions, calls iter() on X. iter() will return an iterable if X either has an __iter__ method or a __getitem__ method. If it implements both, __iter__ is used. If it has neither you get TypeError: 'Nothing' object is not iterable.

This implements a __getitem__:

class GetItem(object):def __init__(self, data):self.data = datadef __getitem__(self, x):return self.data[x]

Usage:

>>> data = range(10)
>>> print [x*x for x in GetItem(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

This is an example of implementing __iter__:

class TheIterator(object):def __init__(self, data):self.data = dataself.index = -1# Note: In  Python 3 this is called __next__def next(self):self.index += 1try:return self.data[self.index]except IndexError:raise StopIterationdef __iter__(self):return selfclass Iter(object):def __init__(self, data):self.data = datadef __iter__(self):return TheIterator(data)

Usage:

>>> data = range(10)
>>> print [x*x for x in Iter(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

As you see you need both to implement an iterator, and __iter__ that returns the iterator.

You can combine them:

class CombinedIter(object):def __init__(self, data):self.data = datadef __iter__(self):self.index = -1return selfdef next(self):self.index += 1try:return self.data[self.index]except IndexError:raise StopIteration

Usage:

>>> well, you get it, it's all the same...

But then you can only have one iterator going at once. OK, in this case you could just do this:

class CheatIter(object):def __init__(self, data):self.data = datadef __iter__(self):return iter(self.data)

But that's cheating because you are just reusing the __iter__ method of list. An easier way is to use yield, and make __iter__ into a generator:

class Generator(object):def __init__(self, data):self.data = datadef __iter__(self):for x in self.data:yield x

This last is the way I would recommend. Easy and efficient.

https://en.xdnf.cn/q/72371.html

Related Q&A

PRAW: Comment Submitters Username

Im developing a reddit bot that needs to know which user submitted a comment. According to the PRAW API wrapper docs, theres no specific way to get the username of a Comment objects author. Ideally I c…

Paramiko, exec_command get the output stream continuously [duplicate]

This question already has answers here:Get output from a Paramiko SSH exec_command continuously(6 answers)Closed 2 years ago.I dry on a Python script. I create a python script for a given IP will conne…

pdfminer3k has no method named create_pages in PDFPage

Since I want to move from python 2 to 3, I tried to work with pdfmine.3kr in python 3.4. It seems like they have edited everything. Their change logs do not reflect the changes they have done but I had…

curve fitting zipf distribution matplotlib python

I tried to fit the following plot(red dot) with the Zipf distribution PDF in Python, F~x^(-a). I simply chose a=0.56 and plotted y = x^(-0.56), and I got the curve shown below. The curve is obviously …

Running python/ruby script on iPhone?

From the recent news from the Apple, I learned that one has to use C/C++/Objective-C for iPhone App. Accordingly, its not possible to use MacPython or similar to make iPhone App. But as the python/ruby…

Unexpected behavior of universal newline mode with StringIO and csv modules

Consider the following (Python 3.2 under Windows):>>> import io >>> import csv >>> output = io.StringIO() # default parameter newline=None >>> csvdata = [1, …

logger chain in python

Im writing python package/module and would like the logging messages mention what module/class/function they come from. I.e. if I run this code:import mymodule.utils.worker as workerw = worker.Worker()…

How to make data to be shown in tabular form in discord.py?

Hi I am creating a bot that makes points table/leaderboard , below is the code which works really nice. def check(ctx):return lambda m: m.author == ctx.author and m.channel == ctx.channelasync def get_…

Getting Python version using Go

Im trying to get my Python version using Go:import ("log""os/exec""strings" )func verifyPythonVersion() {_, err := exec.LookPath("python")if err != nil {log.Fata…

Python shutil.copytree() is there away to track the status of the copying

I have a lot of raster files (600+) in directories that I need copy into a new location (including their directory structure). Is there a way to track the status of the copying using shutil.copytree()?…