How to identify a generator versus list comprehension

I have it:

>>> sum( i*i for i in xrange(5)) 

My question is, in this case, am I passing a list comprehension or a generator object to summarize? How can I say that? Is there a general rule around this?

Also remember that a sum in itself needs a pair of parentheses to surround its arguments. I think the brackets are higher for the sum, not for creating a generator object. Do you agree?

+6
source share
6 answers

You pass the expression.

A list comprehension is given by square brackets ( [...] ). Understanding the list first creates the list object, so it uses syntax closely related to the syntax of the letter list:

 list_literal = [1, 2, 3] list_comprehension = [i for i in range(4) if i > 0] 

The generated expression, on the other hand, creates an iterator object. Only when iteration over this object is performed in a closed loop and elements are created. The generator expression does not store these elements; no list object is created.

The generator expression always uses (...) round parethesis, but when used as the only argument to call, the bracket may be omitted; the following two expressions are equivalent:

 sum((i*i for i in xrange(5))) # with parenthesis sum(i*i for i in xrange(5)) # without parenthesis around the generator 

Quote from the documentation of the generator expression:

Brackets can be omitted in calls with only one argument. See the Calls section for more details.

+9
source

Explanations for the list are enclosed in [] :

 >>> [i*i for i in xrange(5)] # list comprehension [0, 1, 4, 9, 16] >>> (i*i for i in xrange(5)) # generator <generator object <genexpr> at 0x2cee40> 

You pass the generator.

+4
source

This is a generator:

 >>> (i*i for i in xrange(5)) <generator object <genexpr> at 0x01A27A08> >>> 

The list is summarized in [] .

+2
source

You may also ask: "Does this syntax really call sum to consume the generator one element at a time or does it secretly create a list each element in the generator in the first place?" One way to check this is to try it on a very large range and see memory usage:

 sum(i for i in xrange(int(1e8))) 

The memory usage for this case is constant, where as range(int(1e8)) creates a complete list and consumes several hundred MB of RAM.

You can verify that the brackets are optional:

 def print_it(obj): print obj print_it(i for i in xrange(5)) # prints <generator object <genexpr> at 0x03853C60> 
+1
source

I tried this:

 #!/usr/bin/env python class myclass: def __init__(self,arg): self.p = arg print type(self.p) print self.p if __name__ == '__main__': c = myclass(i*i for i in xrange(5)) 

And this prints:

 $ ./genexprorlistcomp.py <type 'generator'> <generator object <genexpr> at 0x7f5344c7cf00> 

This is consistent with what Martin and mdscruggs explained in his post.

+1
source

You pass the generator object, the list comprehension is surrounded by [] .

0
source

Source: https://habr.com/ru/post/951646/


All Articles