1

I was doing a Hackerrank python problem the task was to print 123...N (where N is the input) without using any string function.

Someone commented a solution which is:

print(*range(1, int(input())+1), sep='')

My question is:

  1. What is the use of * here with this range() function?
  2. Why we can't do it by only using range() function inside the print?
  3. Is there any other way to do this?
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Brijesh Joshi
  • 19
  • 1
  • 10
  • 2
    `python-2.7` seems to be misfit tag here, in fact `print(*range(1, int(input())+1), sep='')` will cause `SyntaxError` if you attempt to use it in 2.7 *(tested in 2.7.17)* – Daweo May 05 '20 at 16:55
  • 2
    It's called **unpacking**. You can do it in any iterable, not just range. – Djib2011 May 05 '20 at 16:56
  • 1
    @Daweo It works in Python 2.7 if you use `from __future__ import print_function`. The syntax error arises when the interpreter is expecting `print` to be a statement, in which case the parentheses are part of the expression used by `print`, not to indicate an argument list. – chepner May 05 '20 at 16:58
  • Refer:https://docs.python.org/3.7/tutorial/controlflow.html#unpacking-argument-lists – jizhihaoSAMA May 05 '20 at 16:59
  • VTR - that question is about *parameters*, not *arguments*. That said, this question might still be a duplicate of something. – wjandrea May 05 '20 at 17:04
  • Possible duplicate: [asterisk in function call](https://stackoverflow.com/q/5239856/4518341) (or at least partial duplicate) – wjandrea May 05 '20 at 17:42

3 Answers3

5

The * "unpacks" an iterable, so that each element is passed as a separate argument, rather than the function receiving the iterable object as a single argument:

>>> print(range(1,3))
range(1, 3)
>>> print(*range(1,3))
1 2
>>> print(1,2)
1 2
chepner
  • 497,756
  • 71
  • 530
  • 681
1

range will give you an iterable, a ready object that when consumed will give you individual values. Try to print it without the * and it will call the object __str__() magic method and print range(start, end).

Putting a star upon calling a function will pull all the values from the iterable and pass them as "comma separated" arguments to the function. That is called unpacking.

Tarik
  • 10,810
  • 2
  • 26
  • 40
  • Beside the point, but `range` is not a generator or iterator, though it is an iterable and a sequence. See [If range() is a generator in Python 3.3, why can I not call next() on a range?](https://stackoverflow.com/q/13092267/4518341) – wjandrea May 05 '20 at 17:09
  • @wjandrea Thanks for the correction. I am not as familiar with the python nomenclature as with the .Net platform. – Tarik May 05 '20 at 17:12
  • Welcome. Can't blame you in any case, it's pretty intricate :) Though you've still got "generator" written in one spot. Also ranges don't get consumed per se, just iterated over. I would describe it as working like a list. – wjandrea May 05 '20 at 17:38
  • The "consumed" thing was on purpose. By the way, I found Python iterable behavior different than .Net IEnumerable in the sense that once you iterate over it in python, that's it. It's more like IEnumerator. Will fix the other "generator". – Tarik May 06 '20 at 00:24
1

You are executing this, essentially,

n = int(input())
print(*range(1, n + 1), sep='')

1.) The star *args syntax lets you fill in arguments from an iterable. For example, these are all equivalent:

def foo(a, b):
    return a + b

foo(1, 2)
lst = [1, 2]
foo(*lst)
tup = (1, 2)
foo(*tup)

2.) Certainly you can use just range without unpacking *args. See next item.

3.) Another way would be to print within a for loop, or more compactly to create a string s:

s = "".join(map(str, range(1, n + 1)))
print(s)
J_H
  • 17,926
  • 4
  • 24
  • 44
  • Is not `"".join` string function and task requriement *without using any string function*? – Daweo May 05 '20 at 17:01