1

Are there any ways range print an array without using list()?

def every_three_nums(start):
  lst = []
  if start <= 100:
    lst += range(start, 101, 3)
    # this returns an array but if I print(range(start, 101, 3)), it doesn't
    return lst
  else:
    return lst

This returns an array but if I print(range(start, 101, 3)), it doesn't. Why? How does this code lst += range(start, 101, 3) turn range into an array of numbers?

Sharon Ng
  • 35
  • 9
  • How do you want to print it? – Devesh Kumar Singh Jul 13 '19 at 14:55
  • 1
    An `range` is not a list so printing it doesn't print a list, `range` it is an object the produces values on iteration. You need get those values out with something like `print([x for x in range(start, 101, 3)])`. – Mark Jul 13 '19 at 15:00
  • Not a duplicate, but [this answer](https://stackoverflow.com/a/30081318/) gives you all the information you need. – Karl Knechtel Jul 13 '19 at 15:02

3 Answers3

3

If I print(range(start, 101, 3)), it doesn't [return an array]. Why?

Among the changes that Python 3 made from Python 2 was an emphasis on generators rather than lists or tuples. A list takes up memory for every item in the list, while a generator only creates one item at a time, whenever needed. A generator thus almost always uses less memory, a precious resource in a program. Also, since a generator needs to create only one item (at most) immediately after it is created and the other items may never be needed, it can also save a great deal of time compared to a list which needs to create all its items whether they are needed or not.

Thus many things that made a list in Python 2 were changed to create a generator instead. range is one of those items. So range is an object, but the items are created only when asked for in one way or another. So the command print(range(start, 101, 3)) creates the range object then prints the object. Python prints a note that basically says that the range is an object, a special range object, and gives a few more details.

As @ShadowRanger points out in a comment (and I meant to include but forgot), range is more than a generator. It can work as a sequence (you can pull one item out from the middle, not just the beginning) and has other special characteristics. That is why your command to print a range does not just show that it is an object, it shows that it is a range object which differs from other objects. I was speaking in general terms when I wrote of "generators"--there are other objects that are similar.

Are there any ways the range function prints an array without using list()?

If you want to print a range as a list, ask for the items. There are multiple ways:

 print(*range(start, 101, 3))

That uses Pythons "splat" operator * to get the items of the range in a form suitable as parameters to a function--in this case, the print function. This method comes the closest to never using a "list" to show the contents of the range. The printout is not an "array", just the items separated by spaces.

print([*range(start, 101, 3)])

This uses splat to create a list, then prints the list.

print(list(range(start, 101, 3))

That uses apparent type-casting to convert the range to a list immediately so the list can be printed. You said you do not want this method, but I show it for completeness.

print(tuple(range(start, 101, 3))

This uses a tuple rather than a list.

print([v for v in range(start, 101, 3)])

That uses a list comprehension to create the list. By adding an if clause in the comprehension you could get just some few desired items from the list. You could use a set or other kind of comprehension if you don't want a list.

lst = []
lst += range(start, 101, 3)
print(list)

For details on this one, see the end of this answer.

lst = []
for v in range(start, 101, 3):
    lst.append(v)
print(lst)

You could use a loop to get a list to print. There are many variations on this loop that would work.

How does this code lst += range(start, 101, 3) turn range into an array of numbers?

It doesn't. Using the += command on a list uses whatever is on the right side of the operator as an iterable, not a list. Your code picks the items one-by-one out of the range and appends them one-by-one to the list. The range is never converted to a list, it is just used to extend a list. You can see that by trying to execute lst = lst + range(start, 101, 3)--the range is not converted to a list so an error results.. See this link for a closely related question, though it talks about tuples rather than ranges.

Rory Daulton
  • 19,351
  • 5
  • 34
  • 45
  • 2
    Pedantic note: `range` is actually a sequence, not just a generator. It can be iterated multiple times, indexed, sliced, etc. Python 3 made many thing iterator/generator based, but it also used views and other lazy constructs like `range`. – ShadowRanger Jul 13 '19 at 15:05
  • @ShadowRanger: You are right, `range` is not just a generator. I meant to include that in my answer but I forgot. Thanks for the reminder--I'll add that now. – Rory Daulton Jul 13 '19 at 15:06
  • How does this code `lst += range(start, 101, 3)` turn `range` into an array of numbers? – Sharon Ng Jul 13 '19 at 15:12
  • @SharonNg: `list`'s `+=` operator takes *any* iterable and appends the elements from it to the `list`. It just reads the values from the `range` one at a time and appending them until it's exhausted. It's roughly equivalent to `list.extend`. It doesn't matter what the type of the right hand side is, as long as it's iterable, it will pull elements and append them until they run out. – ShadowRanger Jul 13 '19 at 15:48
0

In python 3, range return a immutable sequence type, the advantage is that the range object...

...will always take the same (small) amount of memory, no matter the size of the range it represents (as it only stores the start, stop and step values, calculating individual items and subranges as needed)

Range used to return a list in python 2.

bcdsant
  • 18
  • 4
0

The key is what:

 lst += range(start, 101, 3)

does when lst is a list which is:

 lst.extend(range(start, 101, 3))

extend adds all the items from its argument to the list as if it were:

for v in range(start, 101, 3):
    lst.append(v)

In both of these it doesn't matter if range returns an iterable or a list as both are iterable and iterate is what extend does to get the items from its argument.

Dan D.
  • 67,516
  • 13
  • 93
  • 109