# Episode 2: range doesn't return an array#491

Open
opened this issue Mar 21, 2018 · 11 comments
Open

# Episode 2: range doesn't return an array #491

opened this issue Mar 21, 2018 · 11 comments
Assignees
Labels
type:discussion Discussion or feedback about the lesson type:enhancement Propose enhancement to the lesson

### biavillasboas commented Mar 21, 2018

 In episode 2 (Repeating Actions with Loops) the first exercise is called "From 1 to N". This is a good exercise, but I believe its description might give rise to some confusion for novices. The exercise introduces the concept of looping through the elements of a collection using Python's built-in function "range". On the first bullet point explaining what range does, we have: If one parameter is given, range creates an array of that length ... However, the function range in Python2 returns a list and in Python3 returns an object of range type. Since learners had just been introduced to lists and arrays and how to find out type(some_thing), it would be important to be consistent and specific about types. Maybe to avoid going into the details of the type range this early in the lesson, we could simply use numpy.arange (which would return an array) throughout this exercise without compromising its overall goal. The text was updated successfully, but these errors were encountered:

### labrax commented Mar 21, 2018

 To avoid these problems we can write this point similar to the next ones: Instead of: If one parameter is given, range creates an array of that length, starting at zero and incrementing by 1. For example, range(3) produces the numbers 0, 1, 2. We can write as: If one parameter is given, range starts at 0 and ends just before the parameter given, incrementing by one. For example, range(3) produces the numbers 0, 1, 2. Using this approach we omit the explanation of the function return and explain what is the goal of the lesson.

changed the title Episode 2 - range doesn't return an array [instructor checkout] Episode 2 - range doesn't return an array Mar 21, 2018

### biavillasboas commented Mar 21, 2018

 Thanks for the suggestion. I agree this would be the simplest solution to the problem. However, I'm still a little concerned about the fact that the built-in range function in python3 returns an object of type range. I imagine that if a learner tries to understand what is going on the exercise and type `print(range(3))` the learner will not get 0, 1, 2, which is what you would expect from the explanation in the exercise: If one parameter is given, range starts at 0 and ends just before the parameter given, incrementing by one. For example, range(3) produces the numbers 0, 1, 2. I believe this could be rather confusing.

### labrax commented Mar 26, 2018

 Indeed, my solution will not help in the case of Python 3. Thank you. How about we create a case just like the ones before, something in the lines of: `````` Python has a built-in function called range that assists creating a sequence of numbers. range can accept 1, 2, or 3 parameters. If one parameter is given, _range_ will return to _for_ an array of that length, starting at zero and incrementing by 1. For example: for number in range(3): print(number) 0 1 2 If two parameters are given, our _for_ starts at the first and ends just before the second, incrementing by one. For example: for number in range(2,5): print(number) 2 3 4 If _range_ is given 3 parameters, our _for_ starts at the first one, ends just before the second one, and increments by the third one. For example: for number in range(3, 10, 2): print(number) 3 5 7 9 ``````

### annefou commented Mar 27, 2018

 I don't think we should bother about python 2 as our lesson is python 3. But you are right, the current lesson is a bit confusing because it does not really explain what the built-in range does. For instance, it is important to undersand why print(range(3)) returns range(0, 3) and not 0,1,2 It has important consequences on the memory usage. You can iterate over a huge number of values and range(n) (where n is a large number) will take as little memory as range(1).

### semodi commented Mar 27, 2018

 Instead of introducing the concept of the built-in range function, would it be enough to say that range() does only make sense in the context of a for-loop and should not be used by itself ? Also, I like @labrax's way of explaining it as 'instructions' for the for loop where to start and where to stop. Even though this might not be precisely what happens in the background, I think it's a good low-level explanation of how an iterator works. Anyway the expression 'array' should definitely be avoided as it is simply incorrect.

### maxim-belkin commented Mar 27, 2018

 hmmm, how about `list(range(4))` ?

changed the title [instructor checkout] Episode 2 - range doesn't return an array Episode 2: range doesn't return an array Mar 28, 2018

### maxim-belkin commented Mar 28, 2018 • edited

 SWC Python lesson has to have `range` in it. The fact that `range` does not return a list could be explained as follows: Let's say, we need to iterate over a loop 1,000,000 times. Sure we can iterate over a list with 1,000,000 elements... but every step we will be using only one element, so we don't really need to have all elements of a list at once. That is why Python 3+ does not create such a list when we call `range` and why `type(range(5))` returns `range`.

### iglpdc commented May 5, 2018

 I agree that the bullet points should be reworded and I think @labrax 's wording is pretty accurate (for the stage we are at in the lesson): If one parameter is given, range starts at 0 and ends just before the parameter given, incrementing by one. For example, range(3) produces the numbers 0, 1, 2. Apart from being iterable, `range` supports the interface you would expect on an array-like thing: ``````>>> a = range(1,4) # array-like 1, 2, 3 >>> len(a) 3 >>> a[0] 1 >>> a[1] 2 >>> a[-1] 3 >>> b = a[::2] # pick every other element, so 1, 3 >>> b[0] 1 >>> b[1] 3 `````` To me the fact that `range` returns a weird type of object or is "lazy" is just an implementation detail, which should not be a concern at this point.

### maxim-belkin commented May 6, 2018

 To me the fact that range returns a weird type of object or is "lazy" is just an implementation detail, which should not be a concern at this point. 100% agree.

added type:discussion Discussion or feedback about the lesson type:enhancement Propose enhancement to the lesson and removed discussion labels Jun 8, 2018

### gkanarek commented Jun 13, 2018

 It already says that "`range` creates a sequence of numbers". Why introduce extra (misleading) terminology? That bullet point could be: ``````If one parameter is given, range creates a sequence of that length, ... ``````

added a commit to appeltel/python-novice-inflammation that referenced this issue Mar 27, 2019
``` Rephrase "range" object return value ```
``` de524a6 ```
```Use the phrase "generates a sequence" to use consistent
language for lazy-evaluators as iterables in a for loop
and avoid suggesting that the sequence is stored as an
array in memory. See issue swcarpentry#491.```

### appeltel commented Mar 27, 2019

 I agree that using the word "array" here is suggesting an incorrect mental model of the `range` object as actually storing values in memory. I also agree that `range` should be taught as a basic Python concept. People coming from a background in C-family languages are naturally going to want an equivalent to `for ( int i = 0; i < 10; i++) { ... }` and its really common to need to run over a simple sequence of integers. It is silly to actually store a big array of sequential integers in memory, and `range` lets you avoid that with a simple and fast implementation. While this memory usage isn't an initial concern for the beginning programmer here, it is more than an implementation detail as it is guaranteed in the language reference: The advantage of the range type over a regular list or tuple is that a 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). A `range` object is a Sequence type which is a formally defined python term of something that interfaces essentially like an array and follows a specific interface. For example, I can access individual elements of a `range` by subscript: ``````>>> numbers = range(0, 100, 5) >>> numbers[6] 30 `````` So the best language that I can come up with here is "generates a sequence". These terms make sense informally so that the learner gets the idea without being burdened with the implementation of the object or the formalities of the python language reference. They also align with more formal Python language that might be understood later. A `range` object is formally a `Sequence` in Python, and the term "generate" will call to mind "generator functions" or "generator expressions". While a `range` object is not formally a generator object, these Python concepts all relate to the idea of lazy evaluation. Furthermore, the phrase "generates a sequence" is also used in the later `enumerate` example, so there would be consistent language applied to lazy evaluators mentioned in this lesson. Note that formally an `enumerate` object is not a `Sequence` as you can't call `len()` on it or access by subscript, but I think that it's probably overly pedantic to insist on changing that given how enumerate is commonly used.

mentioned this issue Mar 27, 2019
pushed a commit that referenced this issue Oct 23, 2020
``` only display Episodes drop-down if we have episodes to show (#491) ```
``` 70213c3 ```