Repository: exercism/python
Pull request #3219 (2022-11-26 17:15:35)

Fixes for Unpacking


Patch:
diff --git a/concepts/unpacking-and-multiple-assignment/.meta/config.json b/concepts/unpacking-and-multiple-assignment/.meta/config.json
index f984160f..36aa817b 100644
--- a/concepts/unpacking-and-multiple-assignment/.meta/config.json
+++ b/concepts/unpacking-and-multiple-assignment/.meta/config.json
@@ -1,5 +1,5 @@
 {
   "blurb": "Unpacking is the process of extracting individual elements of a collection, such as a list, tuple, or dictionary by iterating over them. Unpacked values can be assigned to variables within the same step. Multiple assignment is the ability to assign values to multiple variables in one line.",
   "authors": ["meatball133","bethanyg"],
-  "contributors": []
+  "contributors": ["MatthijsBlom"]
 }
diff --git a/concepts/unpacking-and-multiple-assignment/about.md b/concepts/unpacking-and-multiple-assignment/about.md
index 68c8e066..4e1e90a2 100644
--- a/concepts/unpacking-and-multiple-assignment/about.md
+++ b/concepts/unpacking-and-multiple-assignment/about.md
@@ -1,16 +1,21 @@
 # Unpacking and Multiple Assignment
 
 Unpacking refers to the act of extracting the elements of a collection, such as a `list`, `tuple`, or `dict`, using iteration.
-Unpacked values can be assigned to variables within the same step.
-With unpacking, there are some special operators used: `*` and `**`.
-When unpacking a list or tuple, the `*` operator can be used to assign all the remaining elements to a variable.
-When unpacking a dictionary, the `**` operator can be used to assign all the remaining key-value pairs to a variable.
+Unpacked values can then be assigned to variables within the same statement.
+A very common example of this behavior is `for item in list`, where `item` takes on the value of each `list` element in turn throughout the iteration.
 
-When these operators are used without a collection they will _pack_ a number of values into a `list`, `tuple`, or dictionary.
-It is common to use this kind of behavior when creating functions that take an arbitrary number of arguments.
+[Multiple assignment][multiple assignment] is the ability to assign multiple variables to unpacked values within one statement.
+This allows for code to be more concise and readable, and is done by separating the variables to be assigned with a comma such as `first, second, third = (1,2,3)` or `for index, item in enumerate(iterable)`.
 
-Multiple assignment is the ability to assign multiple variables in one line.
-This is done by separating the variables with a comma.
+The special operators `*` and `**` are often used in unpacking contexts.
+`*` can be used to combine multiple `lists`/`tuples` into one `list`/`tuple` by _unpacking_ each into a new common `list`/`tuple`.
+`**` can be used to combine multiple dictionaries into one dictionary by _unpacking_ each into a new common `dict`.
+
+When the `*` operator is used without a collection, it _packs_ a number of values into a `list`.
+This is often used in multiple assignment to group all "leftover" elements that do not have individual assignments into a single variable.
+
+It is common in Python to also exploit this unpacking/packing behavior when using or defining functions that take an arbitrary number of positional or keyword arguments.
+You will often see these "special" parameters defined as `def some_function(*args, **kwargs)` and the "special" arguments used as `some_function(*some_tuple, **some_dict)`.
 
 ```exercism/caution
 `*<variable_name>` and `**<variable_name>` should not be confused with `*` and `**`. While `*` and `**` are used for multiplication and exponentiation respectively, `*<variable_name>` and `**<variable_name>` are used as packing and unpacking operators.
@@ -18,9 +23,7 @@ This is done by separating the variables with a comma.
 
 ## Multiple assignment
 
-[Multiple assignment][multiple assignment] is the ability to assign multiple variables in one line.
-This allows for code to be more concise and readable.
-There has to be x number of variables on the left side of the `=` sign and x number of values on the right side of the `=` sign.
+In multiple assignment, the number of variables on the left side of the assignment operator (`=`) must match the number of values on the right side.
 To separate the values, use a comma `,`:
 
 ```python
@@ -29,8 +32,15 @@ To separate the values, use a comma `,`:
 1
 ```
 
-Multiple assignment is not limited to one data type but can instead be used with any data type.
-For example:
+If the multiple assignment gets an incorrect number of variables for the values given, a `ValueError` will be thrown:
+
+```python
+>>> x, y, z = 1, 2
+
+ValueError: too many values to unpack (expected 3, got 2)
+```
+
+Multiple assignment is not limited to one data type:
 
 ```python
 >>> x, y, z = 1, "Hello", True
@@ -44,8 +54,8 @@ For example:
 True
 ```
 
-Multiple assignment also allows for the swapping of variables in `lists`.
-This practice is pretty common in [linear sorting algorithms][sorting algorithms].
+Multiple assignment can be used to swap elements in `lists`.
+This practice is pretty common in [sorting algorithms][sorting algorithms].
 For example:
 
 ```python
@@ -55,26 +65,16 @@ For example:
 [2, 1]
 ```
 
-It is also possible to assign multiple variables to the same value:
-
-```python
->>> a = b = 1
->>> a
-1
->>> b
-1
-```
+Since `tuples` are immutable, you can't swap elements in a `tuple`.
 
 ## Unpacking
 
 ```exercism/note
-The examples below use lists but the same concepts apply to tuples.
+The examples below use `lists` but the same concepts apply to `tuples`.
 ```
 
-In Python, it is possible to [unpack a `list`/`tuple`/`dictionary`][unpacking] into distinct variables.
-Since values appear within lists in a specific order, it is therefore possible to _unpack_ a `list` into variables in the same order.
-
-Unpacking a list into variables:
+In Python, it is possible to [unpack the elements of `list`/`tuple`/`dictionary`][unpacking] into distinct variables.
+Since values appear within `lists`/`tuples` in a specific order, they are unpacked into variables in the same order:
 
 ```python
 >>> fruits = ["apple", "banana", "cherry"]
@@ -83,7 +83,7 @@ Unpacking a list into variables:
 "apple"
 ```
 
-If there are values that are not needed then you can use `_` to ignore those values:
+If there are values that are not needed then you can use `_` to flag them:
 
 ```python
 >>> fruits = ["apple", "banana", "cherry"]
@@ -92,7 +92,9 @@ If there are values that are not needed then you can use `_` to ignore those val
 "cherry"
 ```
 
-You can also do [deep unpacking][deep unpacking] on a `list`, which assigns values from a `list` within a `list` (_this is also known as nested list unpacking_):
+### Deep unpacking
+
+Unpacking and assigning values from a `list`/`tuple` inside of a `list` or `tuple` (_also known as nested lists/tuples_), works in the same way a shallow unpacking does, but often needs qualifiers to clarify the values context or position:
 
 ```python
 >>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
@@ -104,7 +106,7 @@ You can also do [deep unpacking][deep unpacking] on a `list`, which assigns valu
 "potato"
 ```
 
-Deep unpacking and normal unpacking can be mixed together:
+You can also deeply unpack just a portion of a nested `list`/`tuple`:
 
 ```python
 >>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
@@ -127,9 +129,9 @@ ValueError: too many values to unpack (expected 1)
 
 ### Unpacking a list/tuple with `*`
 
-When [unpacking a `list`/`tuple`][packing and unpacking] you can use the `*` operator to capture the remainder values.
-This can be used instead of slicing the `list`/`tuple`, which in some situations could be more readable.
-For example, we can extract the first element below and then pack the remaining values into a new `list` without the first element:
+When [unpacking a `list`/`tuple`][packing and unpacking] you can use the `*` operator to capture the "leftover" values.
+This is clearer than slicing the `list`/`tuple` (_which in some situations is less readable_).
+For example, we can extract the first element and then assign the remaining values into a new `list` without the first element:
 
 ```python
 >>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
@@ -168,8 +170,8 @@ We can also use `*` in deep unpacking:
 ### Unpacking a dictionary
 
 [Unpacking a dictionary][packing and unpacking] is a bit different than unpacking a `list`/`tuple`.
-Iteration over dictionaries defaults to the `keys`.
-So when unpacking a `dict`, you can only unpack the `keys` and not the `values`:
+Iteration over dictionaries defaults to the **keys**.
+So when unpacking a `dict`, you can only unpack the **keys** and not the **values**:
 
 ```python
 >>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
@@ -187,9 +189,9 @@ If you want to unpack the values then you can use the `values()` method:
 6
 ```
 
-If both `keys` and `values` are needed, use the `items()` method.
-Using `items()` will generate tuples with `key-value` pairs.
-This is because [`dict.items()` generates a `tuple`][items] and within it there is a `tuple` for each `key-value` pair:.
+If both **keys** and **values** are needed, use the `items()` method.
+Using `items()` will generate tuples with **key-value** pairs.
+This is because of [`dict.items()` generates an iterable with key-value `tuples`][items].
 
 ```python
 >>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
@@ -200,58 +202,72 @@ This is because [`dict.items()` generates a `tuple`][items] and within it there
 
 ## Packing
 
-As with unpacking, _packing_ uses the same `*` and `**` operators.
-[Packing][packing and unpacking]] is the ability to group multiple values into one variable.
-This is useful for when you want to _unpack_ values, make changes, and then _pack_ the results back into a variable.
+[Packing][packing and unpacking] is the ability to group multiple values into one `list` that is assigned to a variable.
+This is useful when you want to _unpack_ values, make changes, and then _pack_ the results back into a variable.
 It also makes it possible to perform merges on 2 or more `lists`/`tuples`/`dicts`.
 
 ### Packing a list/tuple with `*`
 
-Packing a `list`/`tuple` is done by using the `*` operator
-This will pack all the variables into a list/tuple.
+Packing a `list`/`tuple` can be done using the `*` operator.
+This will pack all the values into a `list`/`tuple`.
 
 ```python
->>> fruits = ["apple", "banana", "cherry"]
+>>> fruits = ("apple", "banana", "cherry")
 >>> more_fruits = ["orange", "kiwi", "melon", "mango"]
->>> combined_fruits_lists = [*fruits, *more_fruits]
 
->>> combined_fruits_lists
-["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
+# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
+>>> combined_fruits = *fruits, *more_fruits
+
+# If there is no * on to the left of the "=" the result is a tuple
+>>> combined_fruits
+("apple", "banana", "cherry", "orange", "kiwi", "melon", "mango")
+
+# If the * operator is used on the left side of "=" the result is a list
+>>> *combined_fruits_too, = *fruits, *more_fruits
+>>> combined_fruits_too
+['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']
 ```
 
 ### Packing a dictionary with `**`
 
 Packing a dictionary is done by using the `**` operator.
-This will pack all the variables into a dictionary.
+This will pack all **key**-**value** pairs from one dictionary into another dictionary, or combine two dictionaries together.
 
 ```python
 >>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
 >>> more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3}
+
+# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
 >>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}
 
+# then the pairs are packed into combined_fruits_inventory
 >>> combined_fruits_inventory
 {"apple": 6, "banana": 2, "cherry": 3, "orange": 4, "kiwi": 1, "melon": 2, "mango": 3}
 ```
 
-## Usage of `*` and `**` with a function
+## Usage of `*` and `**` with functions
 
 ### Packing with function parameters
 
-When you have a function that accepts an arbitrary or large number of arguments, you can use [`*args` or `**kwargs`][args and kwargs] to pack or group those parameters together.
-`*args` is used for packing/signaling an arbitrary number of positional (non-keyworded) arguments.
-`**kwargs` is used for packing/signaling an arbitrary number of keyword arguments to a function.
+When you create a function that accepts an arbitrary number of arguments, you can use [`*args` or `**kwargs`][args and kwargs] in the function definition.
+`*args` is used to pack an arbitrary number of positional (non-keyworded) arguments and
+`**kwargs` is used to pack an arbitrary number of keyword arguments.
 
 Usage of `*args`:
 
 ```python
+# This function is defined to take any number of positional arguments
+
 >>> def my_function(*args):
 ...     print(args)
 
+# Arguments given to the function are packed into a tuple
+
 >>> my_function(1, 2, 3)
 (1, 2, 3)
 
->>> my_function("Hello", "World")
-("Hello", "World")
+>>> my_function("Hello")
+("Hello")
 
 >>> my_function(1, 2, 3, "Hello", "Mars")
 (1, 2, 3, "Hello", "Mars")
@@ -260,9 +276,13 @@ Usage of `*args`:
 Usage of `**kwargs`:
 
 ```python
+# This function is defined to take any number of keyword arguments
+
 >>> def my_function(**kwargs):
 ...   print(kwargs)
 
+# Arguments given to the function are packed into a dictionary
+
 >>> my_function(a=1, b=2, c=3)
 {"a": 1, "b": 2, "c": 3}
 ```
@@ -273,7 +293,7 @@ Usage of `**kwargs`:
 >>> def my_function(*args, **kwargs):
 ...   print(sum(args))
 ...   for key, value in kwargs.items():
-...     print(f"{key} = {value}")
+...       print(str(key) + " = " + str(value))
 
 >>> my_function(1, 2, 3, a=1, b=2, c=3)
 6
@@ -321,7 +341,7 @@ TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b'
 ### Unpacking into function calls
 
 You can use `*` to unpack a `list`/`tuple` of arguments into a function call.
-This is very useful for functions that don't accept an `iterable` or `iterator`:
+This is very useful for functions that don't accept an `iterable`:
 
 ```python
 >>> def my_function(a, b, c):
@@ -337,7 +357,7 @@ numbers = [1, 2, 3]
 ```
 
 Using `*` unpacking with the `zip()` function is another common use case.
-Since `zip()` takes multiple iterables and returns a list of tuples with the values from each iterable grouped:
+Since `zip()` takes multiple iterables and returns a `list` of `tuples` with the values from each `iterable` grouped:
 
 ```python
 >>> values = (['x', 'y', 'z'], [1, 2, 3], [True, False, True])
@@ -346,10 +366,9 @@ Since `zip()` takes multiple iterables and returns a list of tuples with the val
 [('y', 2, False), ('z', 3, True)]
 ```
 
+[args and kwargs]: https://www.geeksforgeeks.org/args-kwargs-python/
+[items]: https://www.geeksforgeeks.org/python-dictionary-items-method/
 [multiple assignment]: https://www.geeksforgeeks.org/assigning-multiple-variables-in-one-line-in-python/
+[packing and unpacking]: https://www.geeksforgeeks.org/packing-and-unpacking-arguments-in-python/
 [sorting algorithms]: https://realpython.com/sorting-algorithms-python/
 [unpacking]: https://www.geeksforgeeks.org/unpacking-arguments-in-python/?ref=rp
-[deep unpacking]: https://mathspp.com/blog/pydonts/deep-unpacking#deep-unpacking
-[packing and unpacking]: https://www.geeksforgeeks.org/packing-and-unpacking-arguments-in-python/
-[items]: https://www.geeksforgeeks.org/python-dictionary-items-method/
-[args and kwargs]: https://www.geeksforgeeks.org/args-kwargs-python/
diff --git a/concepts/unpacking-and-multiple-assignment/introduction.md b/concepts/unpacking-and-multiple-assignment/introduction.md
index 0bb09dee..a4675a77 100644
--- a/concepts/unpacking-and-multiple-assignment/introduction.md
+++ b/concepts/unpacking-and-multiple-assignment/introduction.md
@@ -1,19 +1,21 @@
 # Unpacking and Multiple Assignment
 
 Unpacking refers to the act of extracting the elements of a collection, such as a `list`, `tuple`, or `dict`, using iteration.
-Unpacked values can be assigned to variables within the same step.
-With unpacking, there are some special operators used: `*` and `**`.
+Unpacked values can then be assigned to variables within the same statement.
+A very common example of this behavior is `for item in list`, where `item` takes on the value of each `list` element in turn throughout the iteration.
 
+[Multiple assignment][multiple assignment] is the ability to assign multiple variables to unpacked values within one statement.
+This allows for code to be more concise and readable, and is done by separating the variables to be assigned with a comma such as `first, second, third = (1,2,3)` or `for index, item in enumerate(iterable)`.
 
-When unpacking a list or tuple, the `*` operator can be used to assign all the remaining elements to a variable.
-When unpacking a dictionary, the `**` operator can be used to assign all the remaining key-value pairs to a variable.
-When these operators are used without a collection, they _pack_ a number of values into a `list`, `tuple`, or `dict`.
+The special operators `*` and `**` are often used in unpacking contexts.
+`*` can be used to combine multiple `lists`/`tuples` into one `list`/`tuple` by _unpacking_ each into a new common `list`/`tuple`.
+`**` can be used to combine multiple dictionaries into one dictionary by _unpacking_ each into a new common `dict`.
 
-It is common in Python to also exploit this unpacking/packing behavior when defining functions that take an arbitrary number of positional or keyword arguments.
-You will often see these "special" parameters defined as `def some_function(*args, **kwargs)`
+When the `*` operator is used without a collection, it _packs_ a number of values into a `list`.
+This is often used in multiple assignment to group all "leftover" elements that do not have individual assignments into a single variable.
 
-[Multiple assignment][multiple assignment] is the ability to assign multiple variables in one line.
-This allows for code to be more concise and readable, and is done by separating the variables with a comma.
+It is common in Python to also exploit this unpacking/packing behavior when using or defining functions that take an arbitrary number of positional or keyword arguments.
+You will often see these "special" parameters defined as `def some_function(*args, **kwargs)` and the "special" arguments used as `some_function(*some_tuple, **some_dict)`.
 
 ```exercism/caution
 `*<variable_name>` and `**<variable_name>` should not be confused with `*` and `**`. While `*` and `**` are used for multiplication and exponentiation respectively, `*<variable_name>` and `**<variable_name>` are used as packing and unpacking operators.
diff --git a/concepts/unpacking-and-multiple-assignment/links.json b/concepts/unpacking-and-multiple-assignment/links.json
index 8caff2f9..6ad50c21 100644
--- a/concepts/unpacking-and-multiple-assignment/links.json
+++ b/concepts/unpacking-and-multiple-assignment/links.json
@@ -1,7 +1,7 @@
 [
   {
     "url": "https://treyhunner.com/2018/10/asterisks-in-python-what-they-are-and-how-to-use-them/",
-    "description": "Trey Hunner: Astrisks in Python - What they are and How to Use Them."
+    "description": "Trey Hunner: Asterisks in Python - What they are and How to Use Them."
   },
   {
     "url": "https://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/",
diff --git a/config.json b/config.json
index 61cc1285..7350c2d7 100644
--- a/config.json
+++ b/config.json
@@ -142,7 +142,7 @@
         "uuid": "e1b8b9c9-21c3-47b1-b645-5938b3110c78",
         "concepts": ["unpacking-and-multiple-assignment"],
         "prerequisites": ["loops", "lists", "tuples", "dicts"],
-        "status": "wip"
+        "status": "beta"
       },
       {
         "slug": "cater-waiter",
diff --git a/exercises/concept/locomotive-engineer/.docs/hints.md b/exercises/concept/locomotive-engineer/.docs/hints.md
index 929448f2..6bfae5f3 100644
--- a/exercises/concept/locomotive-engineer/.docs/hints.md
+++ b/exercises/concept/locomotive-engineer/.docs/hints.md
@@ -2,7 +2,7 @@
 
 ## General
 
-- To extract multiple arguments in the function parameters so can you pack them with the `*args` operator for list or tuples or `kwargs` for keyword-based arguments.
+- To extract multiple arguments in the function parameters so can you pack them with the `*args` operator for `list` or `tuples` or `**kwargs` for keyword-based arguments.
 - To pack or unpack use the `*` or `**` operator.
 
 ## 1. Create a list of all wagons
@@ -11,25 +11,24 @@
 
 ## 2. Fix list of wagons
 
-- Using unpacking with the `*` operator, lets you extract the first two elements of a list while keeping the rest intact.
-- To add another list into an existing list, you can use the `*` operator to "spread" the list.
+- Using unpacking with the `*` operator, lets you extract the first two elements of a `list` while keeping the rest intact.
+- To add another `list` into an existing `list`, you can use the `*` operator to "spread" the `list`.
 
 ## 3. Add missing stops
 
 - Using `**kwargs` as a function parameter will allow an arbitrary amount of keyword arguments to be passed.
-- Using `**(dict)` as an argument will unpack a dictionary into keyword arguments.
+- Using `**<dict>` as an argument will unpack a dictionary into keyword arguments.
 - You can put keyword arguments in a `{}` or `dict()`.
 - To get the values out of a dictionary, you can use the `<dict>.values()` method.
 
 ## 4. Extend routing information
 
-- Using `**(dict)` as an argument will unpack a dictionary into keyword arguments.
+- Using `**<dict>` as an argument will unpack a dictionary into keyword arguments.
 - You can put keyword arguments in a `{}` or `dict()`.
 
 ## 5. Fix the wagon depot
 
-- `zip(*iterators)` can use used to transpose a nested list.
+- `zip(*iterators)` can use used to transpose a nested `list`.
 - To extract data from zipped iterators, you can use a for loop.
 - you can also unpack zipped iterators using `*`.  
   `[*content] = zip(iterator_1, iterator_2)` will unzip the `tuple` produced by `zip()` into a `list`.
-
diff --git a/exercises/concept/locomotive-engineer/.docs/instructions.md b/exercises/concept/locomotive-engineer/.docs/instructions.md
index 9b80b9ff..c81cedcf 100644
--- a/exercises/concept/locomotive-engineer/.docs/instructions.md
+++ b/exercises/concept/locomotive-engineer/.docs/instructions.md
@@ -1,19 +1,21 @@
 # Instructions
 
 Your friend Linus is a Locomotive Engineer who drives cargo trains between cities.
-Your friend is great at handling trains, although they aren't amazing at handling the logistics computers and would like your programming help organizing the train and correcting mistakes in the data.
+Although they are amazing at handling trains, they are not amazing at handling logistics or computers.
+They would like to enlist your programming help organizing train details and correcting mistakes in route data.
 
 ```exercism/note
-This exercise could easily be solved using `list` slicing, indexing, and `dict` methods.
-However, we'd like you to practice using Unpacking and Multiple Assignment to solve each of the tasks below.
+This exercise could easily be solved using slicing, indexing, and various `dict` methods.
+However, we would like you to practice packing, unpacking, and multiple assignment in solving each of the tasks below.
 ```
 
 ## 1. Create a list of all wagons
 
-Your friend has been keeping track of each wagon identifier, but they're never sure how many wagons they are going to have to process at any given time. It would be much easier for the rest of the logistics program to have the data to be returned as a `list`.
+Your friend has been keeping track of each wagon identifier (ID), but they are never sure how many wagons the system is going to have to process at any given time. It would be much easier for the rest of the logistics program to have this data packaged into a unified `list`.
 
-Implement a function `get_list_of_wagons` that accepts an arbitrary amount of positive integers which are the IDs of each wagon.
-It should then return the given IDs as a `list`.
+Implement a function `get_list_of_wagons()` that accepts an arbitrary number of wagon IDs.
+Each ID will be a positive integer.
+The function should then `return` the given IDs as a single `list`.
 
 ```python
 >>> get_list_of_wagons(1, 7, 12, 3, 14, 8, 5)
@@ -22,20 +24,20 @@ It should then return the given IDs as a `list`.
 
 ## 2. Fix the list of wagons
 
-At this point, you are starting to get a feel for your friend's data and how it's used in the logistics program.
-The train ID system works by assigning the locomotive an ID of `1` and then assigning the remainder of the wagons a randomly chosen ID greater than `1`.
+At this point, you are starting to get a feel for the data and how it's used in the logistics program.
+The ID system always assigns the locomotive an ID of **1**, with the remainder of the wagons in the train assigned a randomly chosen ID greater than **1**.
 
-But then your friend had to connect two new wagons to the train and forgot to update the system!
-Now the first two wagons in the `list` have to be moved to the back of the train, or everything will be out of order.
+Your friend had to connect two new wagons to the train and forgot to update the system!
+Now, the first two wagons in the train `list` have to be moved to the end, or everything will be out of order.
 
-Additionally, your friend just found a second `list` that appears to contain missing wagon IDs, and would like you to merge it together with the main wagon ID `list`.
-All they can remember is that once the new wagons are moved to the end, the values from the second list should be placed directly after the designated locomotive.
+To make matters more complicated, your friend just uncovered a second `list` that appears to contain missing wagon IDs.
+All they can remember is that once the new wagons are moved, the IDs from this second `list` should be placed directly after the designated locomotive.
 
-Your friend would be really grateful to you for fixing their mistakes and consolidating the data.
+Linus would be really grateful to you for fixing their mistakes and consolidating the data.
 
-Implement a function `fix_list_of_wagons` that takes two `lists` containing wagon IDs as the arguments.
-It should reposition the first two items of the first list to the end, and then insert the values from the second list behind the locomotive ID (`1`).
-The function should then `return` the `list` with the modifications.
+Implement a function `fix_list_of_wagons()` that takes two `lists` containing wagon IDs.
+It should reposition the first two items of the first `list` to the end, and insert the values from the second `list` behind (_on the right hand side of_) the locomotive ID (**1**).
+The function should then `return` a `list` with the modifications.
 
 ```python
 >>> fix_list_of_wagons([2, 5, 1, 7, 4, 12, 6, 3, 13], [3, 17, 6, 15])
@@ -44,35 +46,37 @@ The function should then `return` the `list` with the modifications.
 
 ## 3. Add missing stops
 
-Now that all the wagon data is correct, your friend would like you to update the system's routing information.
-During the journey, the train will stop at a few stations to pick up and/or drop off cargo.
-Each journey will have a different amount of stops. To simplify setting up the routing program your friend would like you to add the missing stops to the routing `dict`.
+Now that all the wagon data is correct, Linus would like you to update the system's routing information.
+Along a transport route, a train might make stops at a few different stations to pick up and/or drop off cargo.
+Each journey could have a different amount of these intermediary delivery points.
+Your friend would like you to update the systems routing `dict` with any missing/additional delivery information.
 
-Implement a function `add_missing_stops` that accepts a routing `dict` followed by an arbitrary amount of additional keyword arguments. These arguments could be in the form of a `dict` which holds one or more stops in order, or a number of `stop_number=city` pairs.
-The function should then return the routing `dict`, updated with a key that holds a list of all the stops in order.
+Implement a function `add_missing_stops()` that accepts a routing `dict` followed by a variable number of keyword arguments.
+These arguments could be in the form of a `dict` holding one or more stops, or any number of `stop_number=city` keyword pairs.
+Your function should then return the routing `dict` updated with an additional `key` that holds a `list` of all the added stops in order.
 
 ```python
->>> add_missing_stops({"from": "Berlin", "to": "Hamburg"}, {"stop_1": "Hamburg", "stop_2": "Hannover", "stop_3": "Frankfurt"})
-{"from": "Berlin", "to": "Hamburg", "stops": ["Hamburg", "Hannover", "Frankfurt"]}
+>>> add_missing_stops({"from": "New York", "to": "Miami"},
+                      stop_1="Washington, DC", stop_2="Charlotte", stop_3="Atlanta",
+                      stop_4="Jacksonville", stop_5="Orlando")
 
->>> add_missing_stops({"from": "New York", "to": "Miami"}, stop_1="Washington, DC", stop_2="Charlotte", stop_3="Atlanta", stop_4="Jacksonville", stop_5="Orlando")
 {"from": "New York", "to": "Miami", "stops": ["Washington, DC", "Charlotte", "Atlanta", "Jacksonville", "Orlando"]}
 ```
 
 ## 4. Extend routing information
 
-Your friend has been working on the routing program and has noticed that the routing information is missing some important details.
-Initial routing information has been constructed as a `dict`, and your friend would like you to update it with the additions provided.
-Every route requires slightly different information, so your friend would really prefer a generic solution.
+Linus has been working on the routing program and has noticed that certain routes are missing some important details.
+Initial route information has been constructed as a `dict` and your friend would like you to update that `dict` with whatever might be missing.
+Every route in the system requires slightly different details, so Linus would really prefer a generic solution.
 
-Implement a function `extend_route_information` that accepts two `dicts`.
-The first `dict` contains which cities the train route moves between.
+Implement a function called `extend_route_information()` that accepts two `dicts`.
+The first `dict` contains the origin and destination cities the train route runs between.
 
-The second `dict` contains other routing details such as train speed or length.
+The second `dict` contains other routing details such as train speed, length, or temperature.
 The function should return a consolidated `dict` with all routing information.
 
 ```exercism/note
-The second dict can contain different properties than the ones shown in the example.
+The second `dict` can contain different/more properties than the ones shown in the example.
 ```
 
 ```python
@@ -82,18 +86,19 @@ The second dict can contain different properties than the ones shown in the exam
 
 ## 5. Fix the wagon depot
 
-When your friend was surveying the wagon depot they noticed that the wagons were not getting stored in the correct order.
+When Linus was surveying the wagon depot they noticed that the wagons were not getting stored in the correct order.
 In addition to an ID, each wagon has a color that corresponds to the type of cargo it carries.
-Wagons are stored in the depot in grids, with each column in the grid grouped by wagon color.
+Wagons are stored in the depot in grids, where each column in the grid has wagons of the same color.
 
-In the control system, it appears that the lists of wagons to be stored in the depot have their _rows_ grouped by color. But for the storage grid to work correctly, each row has to have three different colors, so that the columns align properly.
-Your friend would like you to help them sort out the wagon depot lists, so that the wagons get stored correctly.
+However, the logistics system shows `lists` of wagons to be stored in the depot have their _rows_ grouped by color.
+But for the storage grid to work correctly, each _row_ should have three different colors so that the _columns_ align by color.
+Your friend would like you to sort out the wagon depot `lists`, so that the wagons get stored correctly.
 
-Implement a function `fix_wagon_depot` that accepts a nested `list`.
-The first `list` contains the first row of wagons, the second `list` contains the second row of wagons and the third `list` contains the third row of wagons. All rows are of equal length.
-Every wagon within a row is represented by a `tuple` with (`<wagon ID>`, `<wagon color>`).
+Implement a function called `fix_wagon_depot()` that accepts a `list` of three items.
+Each `list` item is a sublist (or "row") that contains three `tuples`.
+Each `tuple` is a `(<wagon ID>, <wagon color>)` pair.
 
-Your function should return a `list` with the three row `lists` reordered with the wagons swapped into their correct positions.
+Your function should return a `list` with the three "row" `lists` reordered to have the wagons swapped into their correct positions.
 
 ```python
 >>> fix_wagon_depot([
diff --git a/exercises/concept/locomotive-engineer/.docs/introduction.md b/exercises/concept/locomotive-engineer/.docs/introduction.md
index 779a6e05..103b5199 100644
--- a/exercises/concept/locomotive-engineer/.docs/introduction.md
+++ b/exercises/concept/locomotive-engineer/.docs/introduction.md
@@ -1,16 +1,9 @@
 # Unpacking and Multiple Assignment
 
 Unpacking refers to the act of extracting the elements of a collection, such as a `list`, `tuple`, or `dict`, using iteration.
-Unpacked values can be assigned to variables within the same step.
-With unpacking, there are some special operators used: `*` and `**`.
-When unpacking a list or tuple, the `*` operator can be used to assign all the remaining elements to a variable.
-When unpacking a dictionary, the `**` operator can be used to assign all the remaining key-value pairs to a variable.
+Unpacked values can then be assigned to variables within the same statement, which is commonly referred to as [Multiple assignment][multiple assignment].
 
-When these operators are used without a collection they will _pack_ a number of values into a `list`, `tuple`, or dictionary.
-It is common to use this kind of behavior when creating functions that take an arbitrary number of arguments.
-
-Multiple assignment is the ability to assign multiple variables in one line.
-This is done by separating the variables with a comma.
+The special operators `*` and `**` are often used in unpacking contexts and with multiple assignment.
 
 ```exercism/caution
 `*<variable_name>` and `**<variable_name>` should not be confused with `*` and `**`. While `*` and `**` are used for multiplication and exponentiation respectively, `*<variable_name>` and `**<variable_name>` are used as packing and unpacking operators.
@@ -18,9 +11,7 @@ This is done by separating the variables with a comma.
 
 ## Multiple assignment
 
-[Multiple assignment][multiple assignment] is the ability to assign multiple variables in one line.
-This allows for code to be more concise and readable.
-There has to be x number of variables on the left side of the `=` sign and x number of values on the right side of the `=` sign.
+In multiple assignment, the number of variables on the left side of the assignment operator (`=`) must match the number of values on the right side.
 To separate the values, use a comma `,`:
 
 ```python
@@ -29,31 +20,49 @@ To separate the values, use a comma `,`:
 1
 ```
 
-Multiple assignment is not limited to one data type but can instead be used with any data type.
-For example:
+If the multiple assignment gets an incorrect number of variables for the values given, a `ValueError` will be thrown:
 
 ```python
->>> a, b, c = 1, "Hello", True
->>> a
+>>> x, y, z = 1, 2
+
+ValueError: too many values to unpack (expected 3, got 2)
+```
+
+Multiple assignment is not limited to one data type:
+
+```python
+>>> x, y, z = 1, "Hello", True
+>>> x
 1
 
->>> b
+>>> y
 'Hello'
 
->>> c
+>>> z
 True
 ```
 
+Multiple assignment can be used to swap elements in `lists`.
+This practice is pretty common in [sorting algorithms][sorting algorithms].
+For example:
+
+```python
+>>> numbers = [1, 2]
+>>> numbers[0], numbers[1] = numbers[1], numbers[0]
+>>> numbers
+[2, 1]
+```
+
+Since `tuples` are immutable, you can't swap elements in a `tuple`.
+
 ## Unpacking
 
 ```exercism/note
-The examples below use lists but the same concepts apply to tuples.
+The examples below use `lists` but the same concepts apply to `tuples`.
 ```
 
-In Python, it is possible to [unpack a `list`/`tuple`/`dictionary`][unpacking] into distinct variables.
-Since values appear within lists in a specific order, it is therefore possible to _unpack_ a `list` into variables in the same order.
-
-Unpacking a list into variables:
+In Python, it is possible to [unpack the elements of `list`/`tuple`/`dictionary`][unpacking] into distinct variables.
+Since values appear within `lists`/`tuples` in a specific order, they are unpacked into variables in the same order:
 
 ```python
 >>> fruits = ["apple", "banana", "cherry"]
@@ -62,7 +71,7 @@ Unpacking a list into variables:
 "apple"
 ```
 
-If there are values that are not needed then you can use `_` to ignore those values:
+If there are values that are not needed then you can use `_` to flag them:
 
 ```python
 >>> fruits = ["apple", "banana", "cherry"]
@@ -71,7 +80,9 @@ If there are values that are not needed then you can use `_` to ignore those val
 "cherry"
 ```
 
-You can also do [deep unpacking][deep unpacking] on a `list`, which assigns values from a `list` within a `list` (_this is also known as nested list unpacking_):
+### Deep unpacking
+
+Unpacking and assigning values from a `list`/`tuple` inside of a `list` or `tuple` (_also known as nested lists/tuples_), works in the same way a shallow unpacking does, but often needs qualifiers to clarify the values context or position:
 
 ```python
 >>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
@@ -83,7 +94,7 @@ You can also do [deep unpacking][deep unpacking] on a `list`, which assigns valu
 "potato"
 ```
 
-Deep unpacking and normal unpacking can be mixed together:
+You can also deeply unpack just a portion of a nested `list`/`tuple`:
 
 ```python
 >>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
@@ -106,9 +117,9 @@ ValueError: too many values to unpack (expected 1)
 
 ### Unpacking a list/tuple with `*`
 
-When [unpacking a `list`/`tuple`][packing and unpacking] you can use the `*` operator to capture the remainder values.
-This can be used instead of slicing the `list`/`tuple`, which in some situations could be more readable.
-For example, we can extract the first element below and then pack the remaining values into a new `list` without the first element:
+When [unpacking a `list`/`tuple`][packing and unpacking] you can use the `*` operator to capture the "leftover" values.
+This is clearer than slicing the `list`/`tuple` (_which in some situations is less readable_).
+For example, we can extract the first element and then assign the remaining values into a new `list` without the first element:
 
 ```python
 >>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
@@ -132,11 +143,24 @@ We can also extract the values at the beginning and end of the `list` while grou
 ["banana", "cherry", "orange", "kiwi"]
 ```
 
+We can also use `*` in deep unpacking:
+
+```python
+>>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
+>>> [[a, *rest], b] = fruits_vegetables
+>>> a
+"apple"
+
+>>> rest
+["banana", "melon"]
+```
+
 ### Unpacking a dictionary
 
 [Unpacking a dictionary][packing and unpacking] is a bit different than unpacking a `list`/`tuple`.
-Iteration over dictionaries defaults to the `keys`.
-So when unpacking a `dict`, you can only unpack the `keys` and not the `values`:
+Iteration over dictionaries defaults to the **keys**.
+So when unpacking a `dict`, you can only unpack the **keys** and not the **values**:
+
 ```python
 >>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
 >>> x, y, z = fruits_inventory
@@ -153,60 +177,85 @@ If you want to unpack the values then you can use the `values()` method:
 6
 ```
 
+If both **keys** and **values** are needed, use the `items()` method.
+Using `items()` will generate tuples with **key-value** pairs.
+This is because of [`dict.items()` generates an iterable with key-value `tuples`][items].
+
+```python
+>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
+>>> x, y, z = fruits_inventory.items()
+>>> x
+("apple", 6)
+```
+
 ## Packing
 
-As with unpacking, _packing_ uses the same `*` and `**` operators.
-[Packing][packing and unpacking]] is the ability to group multiple values into one variable.
-This is useful for when you want to _unpack_ values, make changes, and then _pack_ the results back into a variable.
+[Packing][packing and unpacking] is the ability to group multiple values into one `list` that is assigned to a variable.
+This is useful when you want to _unpack_ values, make changes, and then _pack_ the results back into a variable.
 It also makes it possible to perform merges on 2 or more `lists`/`tuples`/`dicts`.
 
 ### Packing a list/tuple with `*`
 
-Packing a `list`/`tuple` is done by using the `*` operator
-This will pack all the variables into a list/tuple.
+Packing a `list`/`tuple` can be done using the `*` operator.
+This will pack all the values into a `list`/`tuple`.
 
 ```python
->>> fruits = ["apple", "banana", "cherry"]
+>>> fruits = ("apple", "banana", "cherry")
 >>> more_fruits = ["orange", "kiwi", "melon", "mango"]
->>> combined_fruits_lists = [*fruits, *more_fruits]
 
->>> combined_fruits_lists
-["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
+# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
+>>> combined_fruits = *fruits, *more_fruits
+
+# If there is no * on to the left of the "=" the result is a tuple
+>>> combined_fruits
+("apple", "banana", "cherry", "orange", "kiwi", "melon", "mango")
+
+# If the * operator is used on the left side of "=" the result is a list
+>>> *combined_fruits_too, = *fruits, *more_fruits
+>>> combined_fruits_too
+['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']
 ```
 
 ### Packing a dictionary with `**`
 
 Packing a dictionary is done by using the `**` operator.
-This will pack all the variables into a dictionary.
+This will pack all **key**-**value** pairs from one dictionary into another dictionary, or combine two dictionaries together.
 
 ```python
 >>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
 >>> more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3}
+
+# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
 >>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}
 
+# then the pairs are packed into combined_fruits_inventory
 >>> combined_fruits_inventory
 {"apple": 6, "banana": 2, "cherry": 3, "orange": 4, "kiwi": 1, "melon": 2, "mango": 3}
 ```
 
-## Usage of `*` and `**` with a function
+## Usage of `*` and `**` with functions
 
 ### Packing with function parameters
 
-When you have a function that accepts an arbitrary or large number of arguments, you can use [`*args` or `**kwargs`][args and kwargs] to pack or group those parameters together.
-`*args` is used for packing/signaling an arbitrary number of positional (non-keyworded) arguments.
-`**kwargs` is used for packing/signaling an arbitrary number of keyword arguments to a function.
+When you create a function that accepts an arbitrary number of arguments, you can use [`*args` or `**kwargs`][args and kwargs] in the function definition.
+`*args` is used to pack an arbitrary number of positional (non-keyworded) arguments and
+`**kwargs` is used to pack an arbitrary number of keyword arguments.
 
 Usage of `*args`:
 
 ```python
+# This function is defined to take any number of positional arguments
+
 >>> def my_function(*args):
 ...     print(args)
 
+# Arguments given to the function are packed into a tuple
+
 >>> my_function(1, 2, 3)
 (1, 2, 3)
 
->>> my_function("Hello", "World")
-("Hello", "World")
+>>> my_function("Hello")
+("Hello")
 
 >>> my_function(1, 2, 3, "Hello", "Mars")
 (1, 2, 3, "Hello", "Mars")
@@ -215,13 +264,35 @@ Usage of `*args`:
 Usage of `**kwargs`:
 
 ```python
+# This function is defined to take any number of keyword arguments
+
 >>> def my_function(**kwargs):
 ...   print(kwargs)
 
+# Arguments given to the function are packed into a dictionary
+
 >>> my_function(a=1, b=2, c=3)
 {"a": 1, "b": 2, "c": 3}
 ```
 
+`*args` and `**kwargs` can also be used in combination with one another:
+
+```python
+>>> def my_function(*args, **kwargs):
+...   print(sum(args))
+...   for key, value in kwargs.items():
+...       print(str(key) + " = " + str(value))
+
+>>> my_function(1, 2, 3, a=1, b=2, c=3)
+6
+a = 1
+b = 2
+c = 3
+```
+
+You can also write parameters before `*args` to allow for specific positional arguments.
+Individual keyword arguments then have to appear before `**kwargs`.
+
 ```exercism/caution
 [Arguments have to be structured][Positional and keyword arguments] like this:
 
@@ -258,7 +329,8 @@ TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b'
 ### Unpacking into function calls
 
 You can use `*` to unpack a `list`/`tuple` of arguments into a function call.
-This is very useful for functions that don't accept an `iterable` or `iterator`:
+This is very useful for functions that don't accept an `iterable`:
+
 ```python
 >>> def my_function(a, b, c):
 ...   print(c)
@@ -273,7 +345,7 @@ numbers = [1, 2, 3]
 ```
 
 Using `*` unpacking with the `zip()` function is another common use case.
-Since `zip()` takes multiple iterables and returns a list of tuples with the values from each iterable grouped:
+Since `zip()` takes multiple iterables and returns a `list` of `tuples` with the values from each `iterable` grouped:
 
 ```python
 >>> values = (['x', 'y', 'z'], [1, 2, 3], [True, False, True])
@@ -282,8 +354,9 @@ Since `zip()` takes multiple iterables and returns a list of tuples with the val
 [('y', 2, False), ('z', 3, True)]
 ```
 
+[args and kwargs]: https://www.geeksforgeeks.org/args-kwargs-python/
+[items]: https://www.geeksforgeeks.org/python-dictionary-items-method/
 [multiple assignment]: https://www.geeksforgeeks.org/assigning-multiple-variables-in-one-line-in-python/
-[unpacking]: https://www.geeksforgeeks.org/unpacking-arguments-in-python/?ref=rp
-[deep unpacking]: https://mathspp.com/blog/pydonts/deep-unpacking#deep-unpacking
 [packing and unpacking]: https://www.geeksforgeeks.org/packing-and-unpacking-arguments-in-python/
-[args and kwargs]: https://www.geeksforgeeks.org/args-kwargs-python/
+[sorting algorithms]: https://realpython.com/sorting-algorithms-python/
+[unpacking]: https://www.geeksforgeeks.org/unpacking-arguments-in-python/?ref=rp
diff --git a/exercises/concept/locomotive-engineer/.meta/design.md b/exercises/concept/locomotive-engineer/.meta/design.md
index af4109a9..933b7cb8 100644
--- a/exercises/concept/locomotive-engineer/.meta/design.md
+++ b/exercises/concept/locomotive-engineer/.meta/design.md
@@ -1,9 +1,8 @@
 # Design
 
-## TODO: Add introduction for this concept.
 ## Goal
 
-This concept exercise is meant to teach an understanding/use of `unpacking` and the `*` (splat) and `**` (double splat) operators  in Python.
+This concept exercise is meant to teach an understanding/use of `unpacking` and the `*` (splat) and `**` (double splat) operators in Python.
 
 <br>
 
@@ -11,40 +10,34 @@ This concept exercise is meant to teach an understanding/use of `unpacking` and
 
 - Understand/use `unpacking` through the use of `*` and `**` _prefix_ operators in various scenarios
   - `*` and `**` as _prefixes_ ..... not to be confused with `*` (_multiply_) and `**` (_exponentiation_) as _infix_, or mathematical operators (**consider a link in the links doc or a mention in dig deeper.**)
-  - ~~what happens in the process of "unpacking" - form, ordering, & iteration~~ (this will go in a **dig deeper** or the link docs.)
   - use in arguments to `functions`
-  - use in argument _capture_ for `functions` (_aka passing an arbitrary number of arguments -- *args * & **kwargs_)
-  - ~~use in defining `keyword only arguments`~~ (_topic moved to arguments exercise_).
+  - use in argument _capture_ for `functions` (_aka passing an arbitrary number of arguments -- *args * & \*\*kwargs_)
   - use in iterable (_mainly `tuple` and `list`_) unpacking & packing
   - use in `dict` unpacking & packing
 - Understand/use `unpacking` via `multiple assignment`
   - using `multiple assignment ` in place of `indexing`
-  - using `multiple assigment` + `*`  in place of `slicing`
-  - ~~using "list-like" syntax & "tuple-like" syntax~~
+  - using `multiple assignment` + `*` in place of `slicing`
   - unpacking plus "leftovers" via `*`
-- Differences between straight  `multiple assignment` and `*` & `**`
+- Differences between straight `multiple assignment` and `*` & `**`
 - Deep unpacking
 
-
 ## Concepts
 
 - `unpacking`
 - `unpacking generalizations`
 - `multiple assignment`
 
-
 ## Topics that are Out of scope
 
 - `classes`
 - `comprehensions`
 - `comprehensions` in `lambdas`
 - `map()`, `filter()` or `functools.reduce()` in a `comprehension`
--  `function-arguments` beyond explaining briefly how `*`, `**` work in function arguments.
+- `function-arguments` beyond explaining briefly how `*`, `**` work in function arguments.
 - `functools` beyond `functools.reduce()`(_this will get its own exercise_)
 - `generators`
 - using an `assignment expression` or "walrus" operator (`:=`) alone or in a `lambda`
 
-
 ## Prerequisites
 
 - `basics`
@@ -55,7 +48,7 @@ This concept exercise is meant to teach an understanding/use of `unpacking` and
 - `numbers`
 - `strings`
 - `tuples`
-
+- `loops`
 
 ## Representer
 
@@ -66,4 +59,4 @@ This exercise does not require any specific logic to be added to the [represente
 This exercise does not require any specific logic to be added to the [analyzer][analyzer].
 
 [analyzer]: https://github.com/exercism/python-analyzer
-[representer]: https://github.com/exercism/python-representer
\ No newline at end of file
+[representer]: https://github.com/exercism/python-representer
diff --git a/exercises/concept/locomotive-engineer/.meta/exemplar.py b/exercises/concept/locomotive-engineer/.meta/exemplar.py
index 861cce2f..bda295d2 100644
--- a/exercises/concept/locomotive-engineer/.meta/exemplar.py
+++ b/exercises/concept/locomotive-engineer/.meta/exemplar.py
@@ -2,6 +2,12 @@
 
 
 def get_list_of_wagons(*args):
+    """Return a list of wagons.
+
+    :param *args: arbitrary number of wagons.
+    :return: list - list of wagons.
+    """
+
     return list(args)
 
 
@@ -12,27 +18,31 @@ def fix_list_of_wagons(each_wagons_id, missing_wagons):
     :param missing_wagons: list - the list of missing wagons.
     :return: list - list of wagons.
     """
-    first, second, loctomotive, *rest = each_wagons_id
-    return [loctomotive, *missing_wagons, *rest, first, second]
+
+    first, second, locomotive, *rest = each_wagons_id
+
+    return [locomotive, *missing_wagons, *rest, first, second]
 
 
 def add_missing_stops(route, **kwargs):
     """Add missing stops to route dict.
 
     :param route: dict - the dict of routing information.
-    :param **kwards:  arbitrary number of stops.
+    :param **kwargs: arbitrary number of stops.
     :return: dict - updated route dictionary.
     """
+
     return {**route, "stops": list(kwargs.values())}
 
 
 def extend_route_information(route, more_route_information):
-    """Extend the route information with the more_route_information.
+    """Extend route information with more_route_information.
 
     :param route: dict - the route information.
-    :param more_route_information: dict -  extra route information.
+    :param more_route_information: dict - extra route information.
     :return: dict - extended route information.
     """
+
     return {**route, **more_route_information}
 
 
diff --git a/exercises/concept/locomotive-engineer/locomotive_engineer.py b/exercises/concept/locomotive-engineer/locomotive_engineer.py
index 6809958b..4166a24b 100644
--- a/exercises/concept/locomotive-engineer/locomotive_engineer.py
+++ b/exercises/concept/locomotive-engineer/locomotive_engineer.py
@@ -1,6 +1,14 @@
 """Functions which helps the locomotive engineer to keep track of the train."""
 
+
 # TODO: define the 'get_list_of_wagons' function
+def get_list_of_wagons():
+    """Return a list of wagons.
+
+    :param: arbitrary number of wagons.
+    :return: list - list of wagons.
+    """
+    pass
 
 
 # TODO: define the 'fixListOfWagons()' function
@@ -15,11 +23,19 @@ def fix_list_of_wagons(each_wagons_id, missing_wagons):
 
 
 # TODO: define the 'add_missing_stops()' function
+def add_missing_stops():
+    """Add missing stops to route dict.
+
+    :param route: dict - the dict of routing information.
+    :param: arbitrary number of stops.
+    :return: dict - updated route dictionary.
+    """
+    pass
 
 
 # TODO: define the 'extend_route_information()' function
 def extend_route_information(route, more_route_information):
-    """Extend the route information with the more_route_information.
+    """Extend route information with more_route_information.
 
     :param route: dict - the route information.
     :param more_route_information: dict -  extra route information.


Test patch:
diff --git a/exercises/concept/locomotive-engineer/locomotive_engineer_test.py b/exercises/concept/locomotive-engineer/locomotive_engineer_test.py
index 537ac75b..b3a46939 100644
--- a/exercises/concept/locomotive-engineer/locomotive_engineer_test.py
+++ b/exercises/concept/locomotive-engineer/locomotive_engineer_test.py
@@ -6,7 +6,8 @@ from locomotive_engineer import (get_list_of_wagons,
                                  extend_route_information,
                                  fix_wagon_depot)
 
-class InventoryTest(unittest.TestCase):
+
+class LocomotiveEngineerTest(unittest.TestCase):
 
     @pytest.mark.task(taskno=1)
     def test_get_list_of_wagons(self):
@@ -15,21 +16,25 @@ class InventoryTest(unittest.TestCase):
 
         for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
             with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
-                self.assertEqual(get_list_of_wagons(*input_data), output_data)
+                error_msg=f'Expected: {output_data} but got a different wagon list instead.'
+                self.assertEqual(get_list_of_wagons(*input_data), output_data, msg=error_msg)
 
     @pytest.mark.task(taskno=2)
-    def test_fix_list_of_wagons(self): # One extra case needed at first
-        input_data = [([3, 27, 1, 14, 10, 4, 12, 6, 23, 17, 13, 22, 28, 19], [8, 10, 5, 9, 36, 7, 20]),
+    def test_fix_list_of_wagons(self):
+        input_data = [([2, 5, 1, 7, 4, 12, 6, 3, 13], [3, 17, 6, 15]),
+                     ([3, 27, 1, 14, 10, 4, 12, 6, 23, 17, 13, 22, 28, 19], [8, 10, 5, 9, 36, 7, 20]),
                      ([4, 2, 1], [8, 6, 15]), 
                      ([3, 14, 1, 25, 7, 19, 10], [8, 6, 4, 5, 9, 21, 2, 13])
                      ]
-        output_data = [[1, 8, 10, 5, 9, 36, 7, 20, 14, 10, 4, 12, 6, 23, 17, 13, 22, 28, 19, 3, 27], 
+        output_data = [[1, 3, 17, 6, 15, 7, 4,  12, 6, 3, 13, 2, 5],
+                        [1, 8, 10, 5, 9, 36, 7, 20, 14, 10, 4, 12, 6, 23, 17, 13, 22, 28, 19, 3, 27], 
                         [1, 8, 6, 15, 4, 2], 
                         [1, 8, 6, 4, 5, 9, 21, 2, 13, 25, 7, 19, 10, 3, 14]
                     ]
         for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
             with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
-                self.assertEqual(fix_list_of_wagons(input_data[0], input_data[1]), output_data)
+                error_msg=f'Expected: {output_data} but got a different wagon list instead.'
+                self.assertEqual(fix_list_of_wagons(input_data[0], input_data[1]), output_data, msg=error_msg)
 
     @pytest.mark.task(taskno=3)
     def test_add_missing_stops(self): 
@@ -45,7 +50,8 @@ class InventoryTest(unittest.TestCase):
                     ]
         for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
             with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
-                self.assertEqual(add_missing_stops(input_data[0], **input_data[1]), output_data)
+                error_msg=f'Expected: {output_data} but got a different set of stops instead.'
+                self.assertEqual(add_missing_stops(input_data[0], **input_data[1]), output_data, msg=error_msg)
 
     @pytest.mark.task(taskno=4)
     def test_extend_route_information(self): 
@@ -59,7 +65,8 @@ class InventoryTest(unittest.TestCase):
 
         for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
             with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
-                self.assertEqual(extend_route_information(input_data[0], input_data[1]), output_data)
+                error_msg=f'Expected: {output_data} but got a different route dictionary instead.'
+                self.assertEqual(extend_route_information(input_data[0], input_data[1]), output_data, msg=error_msg)
 
     @pytest.mark.task(taskno=5)
     def test_fix_wagon_depot(self):
@@ -79,4 +86,5 @@ class InventoryTest(unittest.TestCase):
 
         for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
             with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
-                self.assertEqual(fix_wagon_depot(input_data), output_data)
\ No newline at end of file
+                error_msg=f'Expected: {output_data} but got a different wagon depot list instead.'
+                self.assertEqual(fix_wagon_depot(input_data), output_data, msg=error_msg)