2

Is there any alternative one liner for this simple code block:

n = int(input())
for i in range(n):
    print(i**2)

I tried:

print(i**2 for i in range(int(input())))

It takes an input, but gives the following error:

<generator object <genexpr> at 0x00000000032D3E60>

My problem is a little bit different than this qs. That qs helped print items in a list whether I need print them in newline.

Arkistarvh Kltzuonstev
  • 6,824
  • 7
  • 26
  • 56
  • 3
    That's **not** an error, that's the representation of the object you're passing to `print`. You *could* do something like `[print(i**2) for i in range(int(input()))]`, but using list comprehensions for side effects is generally discouraged; `for i in range(int(input())): print(i**2)` is fine. – jonrsharpe May 07 '18 at 10:39
  • Possible duplicate of [Python: print a generator expression?](https://stackoverflow.com/questions/5164642/python-print-a-generator-expression) – Patrick Artner May 07 '18 at 10:43

4 Answers4

4

You should wrap the expression into [] in order to have a list comprehension.

print([i**2 for i in range(int(input()))])

If you want to print the results line by line just use extended iterable unpacking operator.

print(*[i**2 for i in range(int(input()))], sep = '\n')
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
4

As Jon and Patrick mention, that's not an error, it's what happens when you print the __repr__ of a generator expression.

So you just need to "splat" that generator. :)

print(*(i**2 for i in range(int(input()))), sep='\n')

demo output

10
0
1
4
9
16
25
36
49
64
81

In that demo I entered 10 at the input prompt.


In the comments I wondered how the speed of i * i compares to i ** 2. On my old 2GHz 32 bit single core machine, running Python 3.6.0, i * i is around 3 or 4 times faster than i ** 2. Here's some timeit code.

from timeit import Timer

commands = {'mul' : 'num * num', 'pow' : 'num ** 2'}

def time_test(num, loops, reps):
    timings = []
    setup = 'num = {}'.format(num) 
    for name, cmd in commands.items():
        result = Timer(cmd, setup).repeat(reps, loops)
        result.sort()
        timings.append((result, name))

    timings.sort()
    for result, name in timings:
        print(name, result)

loops, reps = 100000, 3
num = 1
for _ in range(10):
    print('num =', num)
    time_test(num, loops, reps)
    num <<= 1

output

num = 1
mul [0.02114695899945218, 0.02127135100090527, 0.02303983199817594]
pow [0.08504067399917403, 0.08687452600133838, 0.12349813100081519]
num = 2
mul [0.02089159800016205, 0.021789606998936506, 0.02889108999806922]
pow [0.08612996800002293, 0.09132789800059982, 0.09559987299871864]
num = 4
mul [0.021155500999157084, 0.02333696799905738, 0.028521009000542108]
pow [0.08492234799996368, 0.08499632499660947, 0.08537705599883338]
num = 8
mul [0.02173021600174252, 0.021955170999717666, 0.02823427400289802]
pow [0.08423048700205982, 0.08541251700080466, 0.08654486299928976]
num = 16
mul [0.02176373900147155, 0.02222509399871342, 0.02816650199747528]
pow [0.08528696699795546, 0.09080051600176375, 0.0968476650014054]
num = 32
mul [0.03118283900039387, 0.03388790600001812, 0.03745272100059083]
pow [0.0943321790000482, 0.09484523300125147, 0.09691544299857924]
num = 64
mul [0.030481540998152923, 0.03292956899895216, 0.03887743200175464]
pow [0.09454960600123741, 0.09569520199875114, 0.09926063899911242]
num = 128
mul [0.030935312999645248, 0.031198748001770582, 0.03733277300125337]
pow [0.09531564099961543, 0.09669112700066762, 0.09679062199938926]
num = 256
mul [0.03280377900227904, 0.03324341500047012, 0.04479783699935069]
pow [0.09439349899912486, 0.09439918999851216, 0.09548852000079933]
num = 512
mul [0.03275527599907946, 0.03428718699797173, 0.038492286003020126]
pow [0.10492119499758701, 0.10698100599984173, 0.13057717199990293]
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • This is exactly what's needed, prints them in newline as wanted. – Arkistarvh Kltzuonstev May 07 '18 at 10:45
  • @michaelpetronav Glad you like it. :) BTW, I'd probably use `i*i` rather to compute a square, rather than the general-purpose power operator. It's slightly shorter to type, but I don't know if there's a measurable difference in execution speed. – PM 2Ring May 07 '18 at 10:48
  • That speed comparison test for i*i and i**2 could be a good thing to ask here. I tried to check with big numbers, but to no avail. – Arkistarvh Kltzuonstev May 07 '18 at 11:15
  • 1
    @michaelpetronav On my machine, `i * i` is around 3 or 4 times faster than `i ** 2`. I added some `timeit` code & output to the end of my answer. – PM 2Ring May 07 '18 at 11:52
1

This is no error. Your statement inside the print(...) is a generator expression - the string representation of it is printed - thats what you deemed an "error".

You can convert it by feeding it into a list:

print(list(i**2 for i in range(int(input()))))

or by iterating it:

print(*(i**2 for i in range(int(input()))))

The last one will lead to an output (for input() = 5) of:

0 1 4 9 16

as each result of the generator is passed to print and printed with the default sep=' ' which you could change to '\n' - see PM 2Ring's post

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

This prints each i**2 on a separate line as your code does:

print('\n'.join(str(i**2) for i in range(int(input()))))
haklir
  • 76
  • 4
  • BTW, it's actually more efficient to pass `.join` a list comp than a generator expression because it has to scan the collection of strings to be joined twice: the first time determines the total size of the destination string, the second scan performs the copying. So if you pass it a gen exp it has to save the output of the gen exp so it can perform those 2 scans. – PM 2Ring May 07 '18 at 10:52