Skip to content

Commit a986374

Browse files
kytrinyxBethanyG
andauthored
Launch plane tickets concept exercise in beta (#3530)
* Tweak plane tickets concept exercise I did a small pass through to tweak it a bit for flow and readability. This exercise is ready to be launched. * Turn on plane tickets exercise * (BG) Rather More Edits than Anticipated: This all started with me re-editing the docstrings to comply with https://peps.python.org/pep-0257/, but then it snowballed. Turns out that typing.Generator (https://docs.python.org/3/library/typing.html#typing.Generator) has been deprecated as an alias, so the tests needed some love...and that snowballed into reviewing the other docs. Also renamed the stub and test files to be in line with what we did with other concept exercises. --------- Co-authored-by: BethanyG <[email protected]>
1 parent 939b0e3 commit a986374

File tree

12 files changed

+272
-172
lines changed

12 files changed

+272
-172
lines changed

concepts/generators/about.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# About
22

3+
A `generator` is a function or expression that returns a special type of [iterator][iterator] called [generator iterator][generator-iterator].
4+
`Generator-iterators` are [lazy][lazy iterator]: they do not store their `values` in memory, but _generate_ their values when needed.
5+
6+
A generator function looks like any other function, but contains one or more [yield expressions][yield expression].
7+
Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_).
8+
When the generator resumes, it picks up state from the suspension - unlike regular functions which reset with every call.
9+
10+
311
## Constructing a generator
412

513
Generators are constructed much like other looping or recursive functions, but require a [`yield` expression](#the-yield-expression), which we will explore in depth a bit later.
@@ -131,5 +139,9 @@ Generators are also very helpful when a process or calculation is _complex_, _ex
131139

132140
Now whenever `__next__()` is called on the `infinite_sequence` object, it will return the _previous number_ + 1.
133141

142+
143+
[generator-iterator]: https://docs.python.org/3.11/glossary.html#term-generator-iterator
134144
[iterables]: https://wiki.python.org/moin/Iterator
145+
[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator
146+
[lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation
135147
[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions

concepts/generators/introduction.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
# Introduction
22

3-
A generator in Python is a _callable function_ that returns a [lazy iterator][lazy iterator].
3+
A generator in Python is a _callable function_ or expression that returns a special type of [iterator][iterator] called [generator iterator][generator-iterator].
4+
`Generator-iterators` are [lazy][lazy iterator]: they do not store their `values` in memory, but _generate_ their values when needed.
45

5-
_Lazy iterators_ are similar to `lists`, and other `iterators`, but with one key difference: They do not store their `values` in memory, but _generate_ their values when needed.
6+
A generator function looks like any other function, but contains one or more [yield expressions][yield expression].
7+
Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_).
8+
When the generator function resumes, it picks up state from the suspension - unlike regular functions which reset with every call.
69

710
[lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation
11+
[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator
12+
[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions
13+
[generator-iterator]: https://docs.python.org/3.11/glossary.html#term-generator-iterator

concepts/generators/links.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
[
22
{
3-
"url": "https://docs.python.org/3.10/reference/expressions.html#yield-expressions",
3+
"url": "https://docs.python.org/3.11/reference/expressions.html#yield-expressions",
44
"description": "Official Python 3.10 docs for the yield expression."
55
},
66
{
77
"url": "https://en.wikipedia.org/wiki/Lazy_evaluation",
88
"description": "Wikipedia page about lazy evaluation"
99
},
10+
{
11+
"url": "https://www.pythonmorsels.com/iterators/",
12+
"description": "Python Morsels: Iterators & Generators"
13+
},
1014
{
1115
"url": "https://realpython.com/introduction-to-python-generators/",
1216
"description": "Real python, introduction to generators and yield"

config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@
193193
"uuid": "3ba3fc89-3e1b-48a5-aff0-5aeaba8c8810",
194194
"concepts": ["generators"],
195195
"prerequisites": ["conditionals", "dicts", "lists", "loops", "classes"],
196-
"status": "wip"
196+
"status": "beta"
197197
},
198198
{
199199
"slug": "log-levels",

exercises/concept/plane-tickets/.docs/hints.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44

55
- The returned value should be of _type_ `generator`.
66
- You can have a sequence of letters from `A` to `D` and cycle through them.
7-
- And use `yield` to return the next letter.
7+
- Use `yield` to return the next letter.
88

9-
## 2. Generate an amount of seats
9+
## 2. Generate seats
1010

1111
- The returned value should be of _type_ `generator`.
1212
- Row `13` should be skipped, so go from `12` to `14`.
1313
- Keep in mind that the returned values should be ordered from low to high. `1A, 1B, 2A, ...`
14-
- It might be good to reuse or call other functions you have already completed here.
14+
- Here it might be good to reuse or call functions you have already defined.
1515

1616
## 3. Assign seats to passengers
1717

18-
- Make sure your seat numbers do not have any space in them.
19-
- It might be good to reuse or call other functions you have already completed here.
18+
- Make sure your seat numbers do not have any spaces in them.
19+
- Here it might be good to reuse or call functions you have already defined.
2020

2121
## 4. Ticket codes
2222

exercises/concept/plane-tickets/.docs/instructions.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
# Instructions
22

3-
Conda airlines is the programming-world's biggest airline, with over 10.000 flights a day!
3+
Conda Airlines is the programming-world's biggest airline, with over 10,000 flights a day!
44

5-
They are currently assigning all seats to passengers by hand, this will need to be automated.
5+
They are currently assigning all seats to passengers by hand; this will need to be automated.
66

7-
They have asked _you_ to create software to automate the assigning of seats to passengers.
7+
They have asked _you_ to create software to automate passenger seat assignments.
88
They require your software to be memory efficient and performant.
99

1010
## 1. Generate seat letters
1111

1212
Conda wants to generate seat letters for their airplanes.
1313
An airplane is made of rows of seats.
1414
Each row has _4 seats_.
15-
The rows seats has the same naming: `A`, `B`, `C`, `D`.
16-
Meaning the first seat in the row is `A`, the second seat in the row is `B`, and so on.
17-
After reaching `D` it should start again with `A`.
15+
The seats in each row are always named `A`, `B`, `C`, and `D`.
16+
The first seat in the row is `A`, the second seat in the row is `B`, and so on.
17+
After reaching `D`, it should start again with `A`.
1818

19-
Implement a function `generate_seat_letters()` that accepts an `int` that holds how many seat letters to be generated.
19+
Implement a function `generate_seat_letters(<number>)` that accepts an `int` that holds how many seat letters to be generated.
2020
The function should then return an _iterable_ of seat letters.
2121

2222
```python
@@ -27,9 +27,9 @@ The function should then return an _iterable_ of seat letters.
2727
"B"
2828
```
2929

30-
## 2. Generate an amount of seats
30+
## 2. Generate seats
3131

32-
Conda wants a system that can generate an amount of seats for their airplanes.
32+
Conda wants a system that can generate a given number of seats for their airplanes.
3333
Each airplane has _4 seats_ in each row.
3434
The rows are defined using numbers, starting from `1` and going up.
3535
The seats should be ordered, like: `1A`, `1B`, `1C`, `1D`, `2A`, `2B`, `2C`, `2D`, `3A`, `3B`, `3C`, `3D`, ...
@@ -45,7 +45,7 @@ Here is an example:
4545
Many airlines do not have _row_ number 13 on their flights, due to superstition amongst passengers.
4646
Conda Airlines also follows this convention, so make sure you _don't_ generate seats for _row_ number 13.
4747

48-
Implement a function `generate_seats()` that accepts an `int` that holds how many seats to be generated.
48+
Implement a function `generate_seats(<number>)` that accepts an `int` that holds how many seats to be generated.
4949
The function should then return an _iterable_ of seats given.
5050

5151
```python
@@ -60,7 +60,7 @@ The function should then return an _iterable_ of seats given.
6060

6161
Now that you have a function that generates seats, you can use it to assign seats to passengers.
6262

63-
Implement a function `assign_seats()` that accepts a `list` of passenger names.
63+
Implement a function `assign_seats(<passengers>)` that accepts a `list` of passenger names.
6464
The function should then return a _dictionary_ of `passenger` as _key_, and `seat_number` as _value_.
6565

6666
```python
@@ -74,13 +74,13 @@ The function should then return a _dictionary_ of `passenger` as _key_, and `sea
7474

7575
Conda Airlines would like to have a unique code for each ticket.
7676
Since they are a big airline, they have a lot of flights.
77-
Meaning that there are multiple flights with the same seat number.
77+
This means that there are multiple flights with the same seat number.
7878
They want you to create a system that creates a unique ticket that is _12_ characters long string code for identification.
7979

8080
This code begins with the `assigned_seat` followed by the `flight_id`.
8181
The rest of the code is appended by `0s`.
8282

83-
Implement a function `generate_codes()` that accepts a `list` of `seat_numbers` and a `string` with the flight number.
83+
Implement a function `generate_codes(<seat_numbers>, <flight_id>)` that accepts a `list` of `seat_numbers` and a `string` with the flight number.
8484
The function should then return a `generator` that yields a `ticket_number`.
8585

8686
```python

exercises/concept/plane-tickets/.docs/introduction.md

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
# About
1+
# Generators
2+
3+
A `generator` is a function or expression that returns a special type of [iterator][iterator] called [generator iterator][generator-iterator].
4+
`Generator-iterators` are [lazy][lazy iterator]: they do not store their `values` in memory, but _generate_ their values when needed.
5+
6+
A generator function looks like any other function, but contains one or more [yield expressions][yield expression].
7+
Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_).
8+
When the generator resumes, it picks up state from the suspension - unlike regular functions which reset with every call.
9+
210

311
## Constructing a generator
412

513
Generators are constructed much like other looping or recursive functions, but require a [`yield` expression](#the-yield-expression), which we will explore in depth a bit later.
614

7-
An example is a function that returns the _squares_ from a given list of numbers.
15+
An example is a function that returns the _squares_ from a given list of numbers.
816
As currently written, all input must be processed before any values can be returned:
917

1018
```python
@@ -23,13 +31,14 @@ You can convert that function into a generator like this:
2331
... yield number ** 2
2432
```
2533

26-
The rationale behind this is that you use a generator when you do not need all the values _at once_.
27-
34+
The rationale behind this is that you use a generator when you do not need to produce all the values _at once_.
2835
This saves memory and processing power, since only the value you are _currently working on_ is calculated.
2936

37+
3038
## Using a generator
3139

32-
Generators may be used in place of most `iterables` in Python. This includes _functions_ or _objects_ that require an `iterable`/`iterator` as an argument.
40+
Generators may be used in place of most `iterables` in Python.
41+
This includes _functions_ or _objects_ that require an `iterable`/`iterator` as an argument.
3342

3443
To use the `squares_generator()` generator:
3544

@@ -45,8 +54,8 @@ To use the `squares_generator()` generator:
4554
16
4655
```
4756

48-
Values within a generator can also be produced/accessed via the `next()` function.
49-
`next()` calls the `__next__()` method of a generator object, "advancing" or evaluating the generator code up to its `yield` expression, which then "yields" or returns the value.
57+
Values within a `generator` can also be produced/accessed via the `next()` function.
58+
`next()` calls the `__next__()` method of a generator-iterator object, "advancing" or evaluating the code up to its `yield` expression, which then "yields" or returns a value:
5059

5160
```python
5261
>>> squared_numbers = squares_generator([1, 2])
@@ -57,7 +66,7 @@ Values within a generator can also be produced/accessed via the `next()` functio
5766
4
5867
```
5968

60-
When a `generator` is fully consumed and has no more values to return, it throws a `StopIteration` error.
69+
When a `generator-iterator` is fully consumed and has no more values to return, it throws a `StopIteration` error.
6170

6271
```python
6372
>>> next(squared_numbers)
@@ -66,34 +75,35 @@ Traceback (most recent call last):
6675
StopIteration
6776
```
6877

69-
### Difference between iterables and generators
7078

71-
Generators are a special sub-set of _iterators_.
72-
`Iterators` are the mechanism/protocol that enables looping over _iterables_.
73-
Generators and the iterators returned by common Python [`iterables`][iterables] act very similarly, but there are some important differences to note:
74-
75-
- Generators are _one-way_; there is no "backing up" to a previous value.
76-
77-
- Iterating over generators consume the returned values; no resetting.
79+
~~~~exercism/note
7880
79-
- Generators (_being lazily evaluated_) are not sortable and can not be reversed.
81+
Generator-iterators are a special sub-set of [iterators][iterator].
82+
`Iterators` are the mechanism/protocol that enables looping over _iterables_.
83+
Generator-iterators and the iterators returned by common Python [`iterables`][iterables] act very similarly, but there are some important differences to note:
8084
81-
- Generators do _not_ have `indexes`, so you can't reference a previous or future value using addition or subtraction.
85+
- They are _[lazily evaluated][lazy evaluation]_; iteration is _one-way_ and there is no "backing up" to a previous value.
86+
- They are _consumed_ by iterating over the returned values; there is no resetting or saving in memory.
87+
- They are not sortable and cannot be reversed.
88+
- They are not sequence types, and _do not_ have `indexes`.
89+
You cannot reference a previous or future value using addition or subtraction and you cannot use bracket (`[]`) notation or slicing.
90+
- They cannot be used with the `len()` function, as they have no length.
91+
- They can be _finite_ or _infinite_ - be careful when collecting all values from an _infinite_ `generator-iterator`!
8292
83-
- Generators cannot be used with the `len()` function.
93+
[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator
94+
[iterables]: https://wiki.python.org/moin/Iterator
95+
[lazy evaluation]: https://en.wikipedia.org/wiki/Lazy_evaluation
96+
~~~~
8497

85-
- Generators can be _finite_ or _infinite_, be careful when collecting all values from an _infinite_ generator.
8698

8799
## The yield expression
88100

89101
The [yield expression][yield expression] is very similar to the `return` expression.
90-
91102
_Unlike_ the `return` expression, `yield` gives up values to the caller at a _specific point_, suspending evaluation/return of any additional values until they are requested.
92-
93103
When `yield` is evaluated, it pauses the execution of the enclosing function and returns any values of the function _at that point in time_.
94-
95104
The function then _stays in scope_, and when `__next__()` is called, execution resumes until `yield` is encountered again.
96105

106+
97107
~~~~exercism/note
98108
Using `yield` expressions is prohibited outside of functions.
99109
~~~~
@@ -112,11 +122,12 @@ Using `yield` expressions is prohibited outside of functions.
112122
1
113123
```
114124

115-
## Why generators?
125+
126+
## Why Create a Generator?
116127

117128
Generators are useful in a lot of applications.
118129

119-
When working with a large collection, you might not want to put all of its values into `memory`.
130+
When working with a potentially large collection of values, you might not want to put all of them into memory.
120131
A generator can be used to work on larger data piece-by-piece, saving memory and improving performance.
121132

122133
Generators are also very helpful when a process or calculation is _complex_, _expensive_, or _infinite_:
@@ -131,5 +142,10 @@ Generators are also very helpful when a process or calculation is _complex_, _ex
131142

132143
Now whenever `__next__()` is called on the `infinite_sequence` object, it will return the _previous number_ + 1.
133144

145+
146+
[generator-iterator]: https://docs.python.org/3.11/glossary.html#term-generator-iterator
134147
[iterables]: https://wiki.python.org/moin/Iterator
148+
[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator
149+
[lazy evaluation]: https://en.wikipedia.org/wiki/Lazy_evaluation
150+
[lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation
135151
[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions

exercises/concept/plane-tickets/.meta/config.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@
33
"J08K"
44
],
55
"contributors": [
6-
"BethanyG"
6+
"BethanyG",
7+
"kytrinyx",
8+
"meatball133"
79
],
810
"files": {
911
"solution": [
10-
"plane_tickets.py"
12+
"generators.py"
1113
],
1214
"test": [
13-
"plane_tickets_test.py"
15+
"generators_test.py"
1416
],
1517
"exemplar": [
1618
".meta/exemplar.py"
1719
]
1820
},
1921
"icon": "new-passport",
20-
"blurb": "Learn about generators by assigning seats to passengers."
22+
"blurb": "Learn about generators by assigning seats to passengers on Anaconda Airlines."
2123
}

0 commit comments

Comments
 (0)