diff --git a/concepts/binary-octal-hexadecimal/about.md b/concepts/binary-octal-hexadecimal/about.md index 67646aed2f2..21caa2d2eba 100644 --- a/concepts/binary-octal-hexadecimal/about.md +++ b/concepts/binary-octal-hexadecimal/about.md @@ -219,7 +219,7 @@ As with binary and octal, giving the wrong base will raise a `ValueError`. [binary]: https://en.wikipedia.org/wiki/Binary_number -[bit_count]: https://docs.python.org/3/library/stdtypes.html#int.bit_count +[bit_count]: https://docs.python.org/3/library/stdtypes.html#int.bit_count [bit_length]: https://docs.python.org/3/library/stdtypes.html#int.bit_length [hexadecimal]: https://en.wikipedia.org/wiki/Hexadecimal [numeral-systems]: https://en.wikipedia.org/wiki/Numeral_system diff --git a/concepts/classes/about.md b/concepts/classes/about.md index 9b6a8a0dfb7..53449d39fb6 100644 --- a/concepts/classes/about.md +++ b/concepts/classes/about.md @@ -2,7 +2,7 @@ `Classes` combine data with behavior. Classes are used to create copies or `instances` of bundled data and behavior, commonly known as `objects`. -Objects can represent real world entities (_such as cars or cats_) - or more abstract concepts (_such as integers, vehicles, or mammals_). +Objects can represent real world entities (_such as cars or cats_) — or more abstract concepts (_such as integers, vehicles, or mammals_). Classes are integral to an [object oriented programming][oop] (OOP) approach, which asks the programmer to think about modeling a problem as one or more objects that interact with one another, keep state, and act upon data. ## Classes @@ -41,7 +41,7 @@ An instance (_object_) of `MyClass` can be created and bound to a name: <__main__.MyClass at 0x15adc55b0> ``` -`Class attributes` are shared across all objects (_or instances_) created from a class, and can be accessed via [`dot notation`][dot notation] - a `.` placed after the object name and before the attribute name: +`Class attributes` are shared across all objects (_or instances_) created from a class, and can be accessed via [`dot notation`][dot notation] — a `.` placed after the object name and before the attribute name: ```python >>> new_object = MyClass() @@ -66,7 +66,7 @@ True ``` Class attributes are defined in the body of the class itself, before any other methods. -They are owned by the class - allowing them to be shared across instances. +They are owned by the class — allowing them to be shared across instances. Because these attributes are shared by all instances of the class, their value can be accessed and manipulated from the class directly. Altering the value of class attributes alters the value _**for all objects instantiated from the class**_: @@ -289,7 +289,7 @@ class MyClass: In previous concept exercises and practice exercise stubs, you will have seen the `pass` keyword used within the body of functions in place of actual code. -The `pass` keyword is a syntactically valid placeholder - it prevents Python from throwing a syntax error for an empty function or class definition. +The `pass` keyword is a syntactically valid placeholder — it prevents Python from throwing a syntax error for an empty function or class definition. Essentially, it is a way to say to the Python interpreter, 'Don't worry! I _will_ put code here eventually, I just haven't done it yet.' ```python diff --git a/concepts/classes/introduction.md b/concepts/classes/introduction.md index aef39f76c75..99f2ef0f76b 100644 --- a/concepts/classes/introduction.md +++ b/concepts/classes/introduction.md @@ -2,7 +2,7 @@ Classes are definitions combining data (_otherwise known as `attributes`, `properties`,`data members`, `variables`, or `fields`_) with `functions` (_otherwise known as `methods`_). Class definitions are used to create copies or `instances` of the `class`, commonly known as `objects`. -Objects can represent real world entities (_such as cars or cats_) - or more abstract concepts (_such as integers, vehicles, or mammals_). +Objects can represent real world entities (_such as cars or cats_) — or more abstract concepts (_such as integers, vehicles, or mammals_). Each object is unique in computer memory and represents some part of an overall model. Classes and objects can be found in several programming paradigms, but are integral to [object oriented programming][oop] (OOP), in which programs are made up of objects that interact with one another. diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md index 9aa681ff9f5..ca4ce66aa52 100644 --- a/concepts/comparisons/about.md +++ b/concepts/comparisons/about.md @@ -82,7 +82,7 @@ False Strings (`str`) are compared [_lexicographically_][lexographic order], using their individual Unicode code points (_the result of passing each code point in the `str` to the built-in function [`ord()`][ord], which returns an `int`_). If all code points in both strings match and are _**in the same order**_, the two strings are considered equal. -This comparison is done in a 'pair-wise' fashion - first-to-first, second-to-second, etc. +This comparison is done in a 'pair-wise' fashion — first-to-first, second-to-second, etc. In Python 3.x, `str` and `bytes` cannot be directly coerced/compared. ```python @@ -116,7 +116,7 @@ False ## Comparing Container Data Types -Container data types (_`lists`, `tuples`, `sets`, `dicts`, etc._) also compare [_lexicographically_][lexographic order] - they are equal if both containers have the same data **and** the same data types (_in the case of `lists` and `tuples`, they must also have the same **ordering**_), unequal otherwise. +Container data types (_`lists`, `tuples`, `sets`, `dicts`, etc._) also compare [_lexicographically_][lexographic order] — they are equal if both containers have the same data **and** the same data types (_in the case of `lists` and `tuples`, they must also have the same **ordering**_), unequal otherwise. ```python >>> [1, 2] == [1, 2] @@ -148,7 +148,7 @@ Comparison operators can be chained _arbitrarily_. Note that the evaluation of an expression takes place from `left` to `right`. For example, `x < y <= z` is equivalent to `x < y and y <= z`, except that `y` is evaluated **only once**. In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`. -This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined. +This is often called `short-circuit evaluation` — the evaluation stops if the truth value of the expression has already been determined. `Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python. Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence. diff --git a/concepts/complex-numbers/about.md b/concepts/complex-numbers/about.md index 2b0de864e7b..1afe01fe630 100644 --- a/concepts/complex-numbers/about.md +++ b/concepts/complex-numbers/about.md @@ -44,6 +44,7 @@ ValueError: complex() arg is a malformed string >>> z2 (2+1.5j) ``` + The end result is identical to using the `complex()` constructor. @@ -98,6 +99,7 @@ However, it is still a complex number in Python: You may have heard that "`i` (or `j`) is the square root of -1". For now, all this means is that the imaginary part _by definition_ satisfies the equality + ```python 1j * 1j == -1 # => True ``` @@ -148,7 +150,7 @@ Integer division is ___not___ possible on complex numbers, so the `//` and `%` o There are two functions implemented for numeric types that are very useful when working with complex numbers: -- `.conjugate()` simply flips the sign of the imaginary part of a complex number (_from + to - or vice-versa_). +- `.conjugate()` simply flips the sign of the imaginary part of a complex number (_from `+` to `-` or vice-versa_). - Because of the way complex multiplication works, this is more useful than you might think. - `abs()` is guaranteed to return a real number with no imaginary part. @@ -212,7 +214,7 @@ It was strange and new in the 16th century. ### Why would anyone use these? It turns out that complex numbers are the simplest way to describe anything that rotates or anything with a wave-like property. -So they are used widely in electrical engineering, audio processing, physics, computer gaming, and navigation - to name only a few applications. +So they are used widely in electrical engineering, audio processing, physics, computer gaming, and navigation — to name only a few applications. You can see things rotate. Complex numbers may not make the world go round, but they are great for explaining _what happens_ as a result of the world going round: look at any satellite image of a major storm. @@ -257,4 +259,3 @@ So, you are probably using technology that relies on complex number calculations [engineering-complex]: https://www.khanacademy.org/science/electrical-engineering/ee-circuit-analysis-topic/ee-ac-analysis/v/ee-complex-numbers [ints]: https://docs.python.org/3/library/functions.html#int [floats]: https://docs.python.org/3/library/functions.html#float - diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 2c13888ac90..5e97411a3e7 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -71,10 +71,11 @@ function3 = decorator_with_default_arg()(function3) Most decorators are intended to _extend_ or _replace_ the behavior of another function, but some decorators may do nothing but return the functions they are wrapping. -Decorators are functions which take at least one argument - the function which they are wrapping. +Decorators are functions which take at least one argument — the function which they are wrapping. They usually return either the wrapped function or the result of an expression that uses the wrapped function. -A simple decorator - one that simply returns its wrapped function - can be written as follows: +A simple decorator — one that simply returns its wrapped function — can be written as follows: + ```python >>> def do_nothing(func): ... return func diff --git a/concepts/dict-methods/about.md b/concepts/dict-methods/about.md index 7af90a77145..eec1c44b016 100644 --- a/concepts/dict-methods/about.md +++ b/concepts/dict-methods/about.md @@ -2,7 +2,7 @@ The `dict` class in Python provides many useful [methods][dict-methods] for working with dictionaries. Some were introduced in the concept for `dict`s. -Here we cover a few more - along with some techniques for iterating through and manipulating dictionaries. +Here we cover a few more — along with some techniques for iterating through and manipulating dictionaries. - `.setdefault()` automatically adds keys without throwing a KeyError. - `.fromkeys(, )` creates a new `dict` from any number of iterables. diff --git a/concepts/functions/introduction.md b/concepts/functions/introduction.md index a6db0ad25d9..c931d0f493d 100644 --- a/concepts/functions/introduction.md +++ b/concepts/functions/introduction.md @@ -5,13 +5,13 @@ Functions are used to perform specific and repetitive tasks. More formally: a function is any Python object to which the [`function call`][calls] operation can be applied. A function may be used to [`return`][return] one or more values as a result of some operation(s), or it may be used for one or more [`side effects`][side effects]. -If a function does not specify a return value it will still return `None`. +If a function does not specify a return value it will still return `None`. Following is an example of a function with a side effect: ```python >>> def hello(): -... print("Hello") +... print("Hello") ... >>> hello() Hello @@ -28,8 +28,8 @@ The argument is used by the `print` function to know what to print. Note that the body of the function is indented. The indentation is important because Python relies on it to know where that block of code ends. The function body ends at either the end of the program or just before the next line of code that is _not_ indented. -Since `hello()` does not specify a `return` value, it executes its side effect - which is calling `print()` -- and then returns `None`. -Finally, we call the function by using its name and the parentheses - which signals to the Python interpreter that this is a _callable_ name. +Since `hello()` does not specify a `return` value, it executes its side effect — which is calling `print()` — and then returns `None`. +Finally, we call the function by using its name and the parentheses — which signals to the Python interpreter that this is a _callable_ name. Following is an example of a function with a return value: @@ -61,7 +61,7 @@ Following is an example of a function which accepts an argument: >>> def hello(name): ... return f"Hello, {name}" ... ->>>print(hello("Bob")) +>>> print(hello("Bob")) Hello, Bob ``` @@ -81,6 +81,8 @@ Traceback (most recent call last): print(hello()) TypeError: hello() missing 1 required positional argument: 'name' +``` + If we don't want the program to error with no argument (_but want to allow the calling code to not supply one_), we can define a [default argument][default arguments]. A default argument defines what value to use if the argument is missing when the function is called. @@ -92,7 +94,6 @@ Following is an example of a function with a default argument: ... >>> print(hello()) Hello, you - ``` The `name` parameter is given the default argument of `"you"`, so the program outputs `Hello, you`, if not passed a `name` argument. @@ -103,7 +104,8 @@ For more about function arguments, please see the [function arguments][function [arguments]: https://www.w3schools.com/python/gloss_python_function_arguments.asp [calls]: https://docs.python.org/3/reference/expressions.html#calls [def]: https://www.geeksforgeeks.org/python-def-keyword/ -[function arguments]: ../function-arguments/about.md +[default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ +[function arguments]: https://exercism.org/tracks/python/concepts/function-arguments [function]: https://docs.python.org/3/glossary.html#term-function [parameters]: https://www.codecademy.com/learn/flask-introduction-to-python/modules/learn-python3-functions/cheatsheet [return]: https://www.geeksforgeeks.org/python-return-statement/ diff --git a/concepts/generators/about.md b/concepts/generators/about.md index 4b2e74cbad2..3f24fc7b2a2 100644 --- a/concepts/generators/about.md +++ b/concepts/generators/about.md @@ -5,7 +5,7 @@ A `generator` is a function or expression that returns a special type of [iterat A generator function looks like any other function, but contains one or more [yield expressions][yield expression]. Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_). -When the generator resumes, it picks up state from the suspension - unlike regular functions which reset with every call. +When the generator resumes, it picks up state from the suspension — unlike regular functions which reset with every call. ## Constructing a generator @@ -55,7 +55,7 @@ Generator-iterators and the iterators returned by common Python [`iterables`][it - They are not sequence types, and _do not_ have `indexes`. You cannot reference a previous or future value using addition or subtraction and you cannot use bracket (`[]`) notation or slicing. - They cannot be used with the `len()` function, as they have no length. -- They can be _finite_ or _infinite_ - be careful when collecting all values from an _infinite_ `generator-iterator`! +- They can be _finite_ or _infinite_ — be careful when collecting all values from an _infinite_ `generator-iterator`! [iterator]: https://docs.python.org/3.11/glossary.html#term-iterator [iterables]: https://wiki.python.org/moin/Iterator diff --git a/concepts/generators/introduction.md b/concepts/generators/introduction.md index ad1175ca0b6..09bb4f10681 100644 --- a/concepts/generators/introduction.md +++ b/concepts/generators/introduction.md @@ -5,7 +5,7 @@ A generator in Python is a _callable function_ or expression that returns a spec A generator function looks like any other function, but contains one or more [yield expressions][yield expression]. Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_). -When the generator function resumes, it picks up state from the suspension - unlike regular functions which reset with every call. +When the generator function resumes, it picks up state from the suspension — unlike regular functions which reset with every call. [lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation [iterator]: https://docs.python.org/3.11/glossary.html#term-iterator diff --git a/concepts/list-methods/about.md b/concepts/list-methods/about.md index 00b41f325e5..fa71c7eba84 100644 --- a/concepts/list-methods/about.md +++ b/concepts/list-methods/about.md @@ -1,16 +1,16 @@ # About A [`list`][list] is a mutable collection of items in _sequence_. - Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold references to any (or multiple) data type(s) - including other lists. - They're considered a [sequence][sequence type] in Python, and can be copied in whole or in part via [slice notation][slice notation]. +Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold references to any (or multiple) data type(s) — including other lists. +They're considered a [sequence][sequence type] in Python, and can be copied in whole or in part via [slice notation][slice notation]. Like any sequence, elements within `lists` can be referenced by `0-based index` number from the left, or `-1-based index` number from the right. Lists support both [common][common sequence operations] and [mutable][mutable sequence operations] sequence operations such as `min()`/`max()`, `.index()`, `.append()` and `.reverse()`. - Items can be iterated over using the `for item in ` construct, and `for index, item in enumerate()` when both the element and element index are needed. +Items can be iterated over using the `for item in ` construct, and `for index, item in enumerate()` when both the element and element index are needed. Python provides many useful [methods][list-methods] for working with lists. - Because lists are mutable, list-methods **alter the original list object** passed into the method. +Because lists are mutable, list-methods **alter the original list object** passed into the method. If mutation is undesirable, a `shallow copy` (_at minimum_) of the original `list` needs to be made via `slice` or `.copy()`. @@ -70,7 +70,7 @@ Using `.append()` in this circumstance would add the entire iterable ## Removing Items `.remove()` can be used to remove an element from the list. - `.remove()` will throw a `ValueError` if the element is not present in the list. +`.remove()` will throw a `ValueError` if the element is not present in the list. ```python @@ -143,7 +143,7 @@ The Python docs offer [additional tips and techniques for sorting][sorting how t ~~~~exercism/note - From 2002 to 2022, Python used an algorithm called [`Timsort`][timsort] internally to arrange lists, but switched to [`Powersort`][powersort] from `Python 3.11` onward. +From 2002 to 2022, Python used an algorithm called [`Timsort`][timsort] internally to arrange lists, but switched to [`Powersort`][powersort] from `Python 3.11` onward. You can read more details and discussion on the change from the core Python team in the GitHub [issue 78742][78742]. For technical details on the algorithm, see the J. Ian Munro and Sebastian Wild paper [Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs][nearly-optimal-mergesorts] @@ -178,15 +178,15 @@ To sort a list in _descending_ order, pass a `reverse=True` argument to the meth For cases where mutating the original `list` is undesirable, the built-in functions [`sorted()`][sorted] and [`reversed()`][reversed] can be used. - `sorted()` will return a sorted _copy_, and takes the same parameters as `.sort()`. - `reversed()` returns an _iterator_ that yields the list's items in reverse order. - `Iterators` will be covered in detail in another exercise. +`sorted()` will return a sorted _copy_, and takes the same parameters as `.sort()`. +`reversed()` returns an _iterator_ that yields the list's items in reverse order. +`Iterators` will be covered in detail in another exercise. ## Occurrences of an item in a list Finding the number of occurrences of an element in a list can be done with the help of `.count()`. - It returns the total number of times `` appears as an element in the list. +It returns the total number of times `` appears as an element in the list. ```python @@ -200,9 +200,9 @@ Finding the number of occurrences of an element in a list can be done with the h ## Finding the index of items `.index()` will return the index number of the _first occurrence_ of an item passed in. - If there are no occurrences, a `ValueError` is raised. - Indexing is `0-based` from the left, meaning the position of the first item is index `0`. - Indexing from the right is also supported, starting with index `-1`. +If there are no occurrences, a `ValueError` is raised. +Indexing is `0-based` from the left, meaning the position of the first item is index `0`. +Indexing from the right is also supported, starting with index `-1`. ```python @@ -240,18 +240,18 @@ True ## Making Copies Remember that variables in Python are names that point to underlying objects. - Names can be bound or re-bound to different objects over the life of a program. - Assigning a `list` object to a new variable _**name**_ does not copy the object or any of its referenced data. - The new name and old name will both point at the same `list` object. - Additionally, lists are a _container_ type object - to save space, containers only hold _references_ to member items, not the items themselves. - This "optimization" can have unintended consequences for the unwary. +Names can be bound or re-bound to different objects over the life of a program. +Assigning a `list` object to a new variable _**name**_ does not copy the object or any of its referenced data. +The new name and old name will both point at the same `list` object. +Additionally, lists are a _container_ type object — to save space, containers only hold _references_ to member items, not the items themselves. +This "optimization" can have unintended consequences for the unwary. `.copy()` will create a new `list` object, but **will not** create new objects for the referenced list _elements_ -- the copy is "shallow". - A `shallow copy` is usually enough when you want to add or remove items from one of the `list` objects without modifying the other. - But if there is any chance that the _underlying elements_ of a `list` might be accidentally mutated (_thereby mutating all related shallow copies_), [`copy.deepcopy()`][deepcopy] in the `copy` module should be used to create a complete or "deep" copy of **all** references and objects. +A `shallow copy` is usually enough when you want to add or remove items from one of the `list` objects without modifying the other. +But if there is any chance that the _underlying elements_ of a `list` might be accidentally mutated (_thereby mutating all related shallow copies_), [`copy.deepcopy()`][deepcopy] in the `copy` module should be used to create a complete or "deep" copy of **all** references and objects. For a detailed explanation of names, values, list, and nested list behavior, take a look at this excellent blog post from [Ned Batchelder][ned batchelder] -- [Names and values: making a game board][names and values]. - [Shallow vs Deep Copying of Python Objects][shallow vs deep] also offers a good rundown of copy considerations. +[Shallow vs Deep Copying of Python Objects][shallow vs deep] also offers a good rundown of copy considerations. [common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations diff --git a/concepts/list-methods/introduction.md b/concepts/list-methods/introduction.md index e7054394370..435e6489005 100644 --- a/concepts/list-methods/introduction.md +++ b/concepts/list-methods/introduction.md @@ -1,12 +1,12 @@ # Introduction A [list][list] is a mutable collection of items in _sequence_. - Lists can hold reference to any (or multiple) data type(s) - including other lists or data structures such as [tuples][tuples], [sets][sets], or [dicts][dicts]. - Content can be iterated over using `for item in ` construct. - If indexes are needed with the content, `for index, item in enumerate()` can be used. - Elements within a `list` can be accessed via `0-based index` number from the left, or `-1-based index` number from the right. - Lists can be copied in whole or in part using _slice notation_ or `.copy()`. - Python provides many useful and convenient [methods][list-methods] for working with lists. +Lists can hold reference to any (or multiple) data type(s) — including other lists or data structures such as [tuples][tuples], [sets][sets], or [dicts][dicts]. +Content can be iterated over using `for item in ` construct. +If indexes are needed with the content, `for index, item in enumerate()` can be used. +Elements within a `list` can be accessed via `0-based index` number from the left, or `-1-based index` number from the right. +Lists can be copied in whole or in part using _slice notation_ or `.copy()`. +Python provides many useful and convenient [methods][list-methods] for working with lists. [dicts]: https://github.com/exercism/python/tree/main/concepts/dicts [list-methods]: https://docs.python.org/3/tutorial/datastructures.html#more-on-lists diff --git a/concepts/lists/about.md b/concepts/lists/about.md index 51c44060d5c..05bb3083afb 100644 --- a/concepts/lists/about.md +++ b/concepts/lists/about.md @@ -1,25 +1,25 @@ # About A [`list`][list] is a mutable collection of items in _sequence_. - Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) - including other lists. - Like any [sequence][sequence type], items can be accessed via `0-based index` number from the left and `-1-based index` from the right. - Lists can be copied in whole or in part via [slice notation][slice notation] or `.copy()`. +Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) — including other lists. +Like any [sequence][sequence type], items can be accessed via `0-based index` number from the left and `-1-based index` from the right. +Lists can be copied in whole or in part via [slice notation][slice notation] or `.copy()`. Lists support both [common][common sequence operations] and [mutable][mutable sequence operations] sequence operations such as `min()`/`max()`, `.index()`, `.append()` and `.reverse()`. - List elements can be iterated over using the `for item in ` construct. `for index, item in enumerate()` can be used when both the element index and the element value are needed. +List elements can be iterated over using the `for item in ` construct. `for index, item in enumerate()` can be used when both the element index and the element value are needed. Lists are implemented as [dynamic arrays][dynamic array] -- similar to Java's [`Arraylist`][arraylist] type, and are most often used to store groups of similar data (_strings, numbers, sets etc._) of unknown length (_the number of entries may arbitrarily expand or shrink_). Accessing elements, checking for membership via `in`, or appending items to the "right-hand" side of a list are all very efficient. - Prepending (_appending to the "left-hand" side_) or inserting into the middle of a list are much _less_ efficient because those operations require shifting elements to keep them in sequence. - For a similar data structure that supports memory efficient `appends`/`pops` from both sides, see [`collections.deque`][deque], which has approximately the same O(1) performance in either direction. +Prepending (_appending to the "left-hand" side_) or inserting into the middle of a list are much _less_ efficient because those operations require shifting elements to keep them in sequence. +For a similar data structure that supports memory efficient `appends`/`pops` from both sides, see [`collections.deque`][deque], which has approximately the same O(1) performance in either direction. Because lists are mutable and can contain references to arbitrary Python objects, they also take up more space in memory than an [`array.array`][array.array] or a [`tuple`][tuple] (_which is immutable_) of the same apparent length. - Despite this, lists are an extremely flexible and useful data structure and many built-in methods and operations in Python produce lists as their output. +Despite this, lists are an extremely flexible and useful data structure and many built-in methods and operations in Python produce lists as their output. ## Construction @@ -292,6 +292,7 @@ This can lead to multiple potential issues when working with lists, if not handl ### Assigning more than one variable name + Assigning a `list` object to a new variable _name_ **does not copy the `list` object nor its elements**. Any change made to the elements in the `list` under the _new_ name _impact the original_. diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md index bd68b9a9d59..6469195fb5a 100644 --- a/concepts/lists/introduction.md +++ b/concepts/lists/introduction.md @@ -1,12 +1,12 @@ # Introduction A [list][list] is a mutable collection of items in _sequence_. - They are an extremely flexible and useful data structure that many `built-in` methods and operations in Python produce as output. - Lists can hold reference to any (or multiple) data type(s) - including other lists or data structures such as [tuples][tuples], [sets][sets], or [dicts][dicts]. - Content can be iterated over using `for item in ` construct. - If indexes are needed with the content, `for index, item in enumerate()` can be used. - Elements within a `list` can be accessed via `0-based index` number from the left, or `-1-based index` number from the right. - Lists can be copied in whole or in part using _slice notation_ or `.copy()`. +They are an extremely flexible and useful data structure that many `built-in` methods and operations in Python produce as output. +Lists can hold reference to any (or multiple) data type(s) — including other lists or data structures such as [tuples][tuples], [sets][sets], or [dicts][dicts]. +Content can be iterated over using `for item in ` construct. +If indexes are needed with the content, `for index, item in enumerate()` can be used. +Elements within a `list` can be accessed via `0-based index` number from the left, or `-1-based index` number from the right. +Lists can be copied in whole or in part using _slice notation_ or `.copy()`. [dicts]: https://github.com/exercism/python/tree/main/concepts/dicts [list]: https://docs.python.org/3/library/stdtypes.html#list diff --git a/concepts/recursion/about.md b/concepts/recursion/about.md index 3d11c7ca270..26403348dae 100644 --- a/concepts/recursion/about.md +++ b/concepts/recursion/about.md @@ -208,5 +208,5 @@ To learn more about using recursion in Python you can start with [memoization]: https://dbader.org/blog/python-memoization [python-programming: recursion]: https://www.programiz.com/python-programming/recursion [stack-frame]: https://shanechang.com/p/python-frames-systems-programming-connection/ -[sys.setrecursionlimit]: https://docs.python.org/3.8/library/sys.html#sys.setrecursionlimit +[sys.setrecursionlimit]: https://docs.python.org/3.8/library/sys.html#sys.setrecursionlimit [what-is-the-call-stack]: https://en.wikipedia.org/wiki/Call_stack diff --git a/concepts/sets/about.md b/concepts/sets/about.md index 944f98d1b52..807f885ac02 100644 --- a/concepts/sets/about.md +++ b/concepts/sets/about.md @@ -358,13 +358,13 @@ The operator version of this method is ` - - - # Methods will take any iterable as an argument. >>> berries = berries_and_veggies.difference(veggies) -{'Blackberries','Currants','Goji Berries', +{'Blackberries', 'Currants', 'Goji Berries', 'Goose Berries', 'Strawberries'} # Operators require sets. >>> berries_and_veggies - berries -{'Artichokes','Asparagus','Broccoli','Kale', -'Ramps','Rhubarb','Walking Onions','Watercress'} +{'Artichokes', 'Asparagus', 'Broccoli', 'Kale', + 'Ramps', 'Rhubarb', 'Walking Onions', 'Watercress'} ``` ### Set Intersections @@ -373,20 +373,20 @@ The operator version of this method is ` - - - The operator version of this method is ` & & & ... & ` ```python ->>> perennials = {'Annatto','Asafetida','Asparagus','Azalea', - 'Winter Savory', 'Broccoli','Curry Leaf','Fennel', - 'Kaffir Lime','Kale','Lavender','Mint','Oranges', +>>> perennials = {'Annatto', 'Asafetida', 'Asparagus', 'Azalea', + 'Winter Savory', 'Broccoli', 'Curry Leaf', 'Fennel', + 'Kaffir Lime', 'Kale', 'Lavender', 'Mint', 'Oranges', 'Oregano', 'Tarragon', 'Wild Bergamot'} >>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Marjoram', - 'Summer Squash', 'Okra','Shallots', 'Basil', + 'Summer Squash', 'Okra', 'Shallots', 'Basil', 'Cilantro', 'Cumin', 'Sunflower', 'Chervil', 'Summer Savory'} ->>> herbs = ['Annatto','Asafetida','Basil','Chervil','Cilantro', - 'Curry Leaf','Fennel','Kaffir Lime','Lavender', - 'Marjoram','Mint','Oregano','Summer Savory', - 'Tarragon','Wild Bergamot','Wild Celery', +>>> herbs = ['Annatto', 'Asafetida', 'Basil', 'Chervil', 'Cilantro', + 'Curry Leaf', 'Fennel', 'Kaffir Lime', 'Lavender', + 'Marjoram', 'Mint','Oregano', 'Summer Savory', + 'Tarragon', 'Wild Bergamot', 'Wild Celery', 'Winter Savory'] @@ -397,13 +397,13 @@ The operator version of this method is ` & & & . # Operators require both groups be sets. >>> annuals & set(herbs) - {'Basil', 'Chervil', 'Marjoram', 'Cilantro'} +{'Basil', 'Chervil', 'Marjoram', 'Cilantro'} ``` ### Set Symmetric Differences `.symmetric_difference()` returns a new `set` that contains elements that are in `` OR ``, but **not in both**. -The operator version of this method is ` ^ `. +The operator version of this method is ` ^ `. ```python >>> plants_1 = {'🌲','🍈','🌵', '🥑','🌴', '🥭'} @@ -457,7 +457,7 @@ To obtain only items unique to each `set` in the series, intersections between a 'olive oil','salt','soy sauce', 'sugar','water'} # The ^ operation will include some of the items in intersections, -# which means it is not a "clean" symmetric difference - there +# which means it is not a "clean" symmetric difference — there # are overlapping members. >>> (one ^ two ^ three ^ four) & intersections {'black pepper', 'garlic', 'soy sauce', 'water'} diff --git a/concepts/string-methods/about.md b/concepts/string-methods/about.md index 6c9c843b97c..3dfd1a83449 100644 --- a/concepts/string-methods/about.md +++ b/concepts/string-methods/about.md @@ -4,12 +4,12 @@ A `str` is an [immutable sequence][text sequence] of [Unicode code points][unico This may include letters, diacritical marks, positioning characters, numbers, currency symbols, emoji, punctuation, space and line breaks, and more. Strings implement all [common sequence operations][common sequence operations] and can be iterated through using `for item in ` or `for index, item in enumerate()` syntax. - Individual code points (_strings of length 1_) can be referenced by `0-based index` number from the left, or `-1-based index` number from the right. +Individual code points (_strings of length 1_) can be referenced by `0-based index` number from the left, or `-1-based index` number from the right. - Strings can be concatenated using ` + ` or `.join()` and split via `.split()`. - They also offer multiple other formatting and assembly options. +Strings can be concatenated using ` + ` or `.join()` and split via `.split()`. +They also offer multiple other formatting and assembly options. - To further work with strings, Python provides a rich set of [string methods][str-methods] for searching, cleaning, transforming, translating, and many other operations. +To further work with strings, Python provides a rich set of [string methods][str-methods] for searching, cleaning, transforming, translating, and many other operations. Some of the more commonly used `str` methods include: @@ -64,12 +64,12 @@ There may also be [locale][locale] rules in place for a language or character se [`.strip()`][str-strip] returns a copy of the `str` with leading and trailing `` removed. -The code points specified in `` are not a prefix or suffix - **all combinations** of the code points will be removed starting from **both ends** of the string. - If nothing is specified for ``, all combinations of whitespace code points will be removed. - If only left-side or right-side removal is wanted, `.lstrip()` and `.rstrip()` can be used. +The code points specified in `` are not a prefix or suffix — **all combinations** of the code points will be removed starting from **both ends** of the string. +If nothing is specified for ``, all combinations of whitespace code points will be removed. +If only left-side or right-side removal is wanted, `.lstrip()` and `.rstrip()` can be used. - ```python +```python # This will remove "https://", because it can be formed from "/stph:". >>> 'https://unicode.org/emoji/'.strip('/stph:') 'unicode.org/emoji' @@ -88,7 +88,7 @@ The code points specified in `` are not a prefix or suffix - **all combin >>> ' unaddressed '.strip('dnue ') 'address' - ``` +``` [`.replace(, )`][str-replace] returns a copy of the string with all occurrences of `` replaced with ``. diff --git a/concepts/strings/about.md b/concepts/strings/about.md index 19920adad31..49476385514 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -7,7 +7,7 @@ For a deep dive on what information a string encodes (or, _"how does a computer The Python docs also provide a very detailed [unicode HOWTO][unicode how-to] that discusses Python's support for the Unicode specification in the `str`, `bytes` and `re` modules, considerations for locales, and some common issues with encoding and translation. Strings implement all [common sequence operations][common sequence operations] and can be iterated through using `for item in ` or `for index, item in enumerate()` syntax. - Individual code points (_strings of length 1_) can be referenced by `0-based index` number from the left, or `-1-based index` number from the right. +Individual code points (_strings of length 1_) can be referenced by `0-based index` number from the left, or `-1-based index` number from the right. Strings can be concatenated with ` + ` or `.join()` and split via `.split()`. They also offer multiple additional formatting, assembly, and templating options. @@ -27,11 +27,11 @@ Multi-line strings are declared with `'''` or `"""`. ```python >>> triple_quoted = '''Three single quotes or "double quotes" in a row allow for multi-line string literals. - Line break characters, tabs and other whitespace is fully supported. Remember - The escape "\" character is also available if needed (as can be seen below). + Line break characters, tabs and other whitespace is fully supported. Remember — The escape "\" character is also available if needed (as can be seen below). You\'ll most often encounter multi-line strings as "doc strings" or "doc tests" written just below the first line of a function or class definition. - They\'re often used with auto documentation ✍ tools. - ''' + They\'re often used with auto documentation ✍ tools. + ''' ``` The [`str()` constructor][str-constructor] can be used to create/coerce strings from other objects: @@ -68,7 +68,6 @@ creative = '창의적인' >>> creative[3] '인' - ``` Indexing also works from the right, starting with a `-1-based index`: @@ -84,7 +83,6 @@ creative = '창의적인' >>> creative[-1] '인' - ``` There is no separate “character” or "rune" type in Python, so indexing a string produces a new `str` of **length 1**: @@ -211,7 +209,7 @@ If a `list`, `tuple`, `set` or other collection of individual strings needs to b >>> upper_words = ['upper', 'crust', 'case', 'classmen', 'most', 'cut'] >>> separator = ' 🌟 ' + upper_words[0] # This becomes one string, similar to ' ⤴️ under'. >>> separator.join(upper_words) - 'upper 🌟 uppercrust 🌟 uppercase 🌟 upperclassmen 🌟 uppermost 🌟 uppercut' +'upper 🌟 uppercrust 🌟 uppercase 🌟 upperclassmen 🌟 uppermost 🌟 uppercut' ``` Strings support all [common sequence operations][common sequence operations]. diff --git a/concepts/tuples/about.md b/concepts/tuples/about.md index e61cd39eadb..50460091d50 100644 --- a/concepts/tuples/about.md +++ b/concepts/tuples/about.md @@ -66,10 +66,9 @@ which will return an iterator of (`key`, `value`) `tuples`. (('fish', 'gold'), ('monkey', 'brown')) ``` -#### Declaring a tuple as a _literal_ : +#### Declaring a tuple as a _literal_: -Because the `tuple()` constructor only takes _iterables_ (or nothing) as arguments, it is much easier to create - a one-tuple via the literal method. +Because the `tuple()` constructor only takes _iterables_ (or nothing) as arguments, it is much easier to create a one-tuple via the literal method. ```python >>> no_elements = () @@ -79,7 +78,7 @@ Because the `tuple()` constructor only takes _iterables_ (or nothing) as argumen ("Guava",) ``` -Note that generally parentheses are **not** required to create a `tuple` literal - only commas. +Note that generally parentheses are **not** required to create a `tuple` literal — only commas. However, using `(, )` is considered more readable in most circumstances. Parentheses are also required in cases of ambiguity, such as an empty or one-item tuple or where a function takes a tuple as an argument. @@ -178,19 +177,19 @@ Using a mutable data type within a `tuple` will make the enclosing `tuple` **un- ```python >>> cmyk_color_map = { - (.69, .3, .48, .1) : ("Teal 700", (59, 178, 146), 0x3BB292), - (0, .5, 1, 0) : ("Pantone 151", (247, 127, 1), 0xF77F01), - (.37, .89, 0, .44) : ("Pantone 267", (89, 16, 142), 0x59108E), - (0, 1, .46, .45) : ("Pantone 228", (140, 0, 76), 0x8C004C) - } + (.69, .3, .48, .1) : ("Teal 700", (59, 178, 146), 0x3BB292), + (0, .5, 1, 0) : ("Pantone 151", (247, 127, 1), 0xF77F01), + (.37, .89, 0, .44) : ("Pantone 267", (89, 16, 142), 0x59108E), + (0, 1, .46, .45) : ("Pantone 228", (140, 0, 76), 0x8C004C) +} >>> unique_rgb_colors = { - (59, 178, 146), - (247, 127, 1), - (89, 16, 142), - (140, 0, 76), - (76, 0, 140) - } + (59, 178, 146), + (247, 127, 1), + (89, 16, 142), + (140, 0, 76), + (76, 0, 140) +} >>> teal_700 = hash((59, 178, 146)) diff --git a/docs/LEARNING.md b/docs/LEARNING.md index 4a85339a936..d5cbfbb4097 100644 --- a/docs/LEARNING.md +++ b/docs/LEARNING.md @@ -1,12 +1,13 @@ # Learning ## Learning Python From Scratch -Python is (_as [Wikipedia says][wikipython]_), a *general-purpose and high-level programming language*. - It can be used to write a wide variety of different kinds of software, from video games to HTTP servers to command-line tools - and a whole lot else. - It is especially good at 'gluing' different systems and programs together. +Python is (_as [Wikipedia says][wikipython]_), a _general-purpose and high-level programming language_. +It can be used to write a wide variety of different kinds of software, from video games to HTTP servers to command-line tools — and a whole lot else. +It is especially good at 'gluing' different systems and programs together. -And we think the best way to learn is to _play_ and to _practice_ with coding projects big and small - or with small problems like the ones here on exercism! + +And we think the best way to learn is to _play_ and to _practice_ with coding projects big and small — or with small problems like the ones here on Exercism! Below you will find some additional jumping-off places to start your learning journey, recommended by our community. diff --git a/docs/PROBLEM-SOLVING.md b/docs/PROBLEM-SOLVING.md index 47a99e8a8ab..7a31755245f 100644 --- a/docs/PROBLEM-SOLVING.md +++ b/docs/PROBLEM-SOLVING.md @@ -2,20 +2,20 @@ As the first article here states, `Problem solving is a meta-skill`. -We find that often, the syntax or structure of a programming language isn't the most difficult part of solving a challenge - figuring out _what to code_ or _where to start_ is. +We find that often, the syntax or structure of a programming language isn't the most difficult part of solving a challenge — figuring out _what to code_ or _where to start_ is. Developing strategies and a system to break down problems into code-able steps is a **great** skill to cultivate. Below are some community-sourced articles, videos, and books that can help you develop this super-skill. -- Free Code Camp offers a good overview article on [How to Think Like a Programmer - Lessons in Problem-Solving][free-code-camp-think-like-a-programmer]. +- Free Code Camp offers a good overview article on [How to Think Like a Programmer — Lessons in Problem-Solving][free-code-camp-think-like-a-programmer]. - Jeremy Howard, founder of fast.ai has a nice summary of [G. Polya's Problem Solving Techniques][g-polya-how-to-solve-it-summary]. - Originally written in 1945 as guidance for tackling complicated math problems,[G. Polya's How To Solve It][g-polya-how-to-solve-it] (full book) is still _excellent_ advice for problem-solving in general. - Kurtis Pykes writing for Towards Data Science has a nice [hands-on tutorial for problem-solving][Kurtis Pykes: Hands-on Tutorial - How to Improve Your Problem-Solving Skills as A Programmer]. - Mentioned in the Free Code Camp Article, V. Anton Spraul's [Think Like a Programmer: An Introduction to Creative Problem Solving][v-anton-spraul-think-like-a-programmer] is a more modern and programming-focused take on the same general methods Polya outlines for mathematics. - [Felienne Hermans][felienne-hermans] is more focused on _how_ people learn the art of coding and how that maps to learning in general. - She has written [The Programmers Brian][programmers-brain-free-online], with strategies for reading code better, thinking about code clearly, writing better code, and becoming a better code collaborator. - - You can order a physical copy of her book [here][programmers-brain-manning]. - - She also has two interesting videos on the same topic: [How to Teach Programming (and other things??)][felienne-hermans-how-to-teach-programming] and [Programming is Writing is Programming ][felienne-hermans-programming-is-writing-is-programming]. + She has written [The Programmer's Brain][programmers-brain-free-online], with strategies for reading code better, thinking about code clearly, writing better code, and becoming a better code collaborator. + - You can order a physical copy of her book [here][programmers-brain-manning]. + - She also has two interesting videos on the same topic: [How to Teach Programming (and other things??)][felienne-hermans-how-to-teach-programming] and [Programming is Writing is Programming][felienne-hermans-programming-is-writing-is-programming]. - [Algorithmic Thinking (Daniel Zingaro)][daniel-zingaro-algorithmic-thinking] from No Starch Press and [How to think like a programmer (Paul Vickers)][paul-vickers-how-to-think-like-a-programmer] also cover problem-solving when coding. - [Computational Thinking: A beginner's guide to problem-solving and programming (Karl Beecher)][beecher-computational-thinking] and [Computational Thinking for the Modern Problem-Solver (Riley and Hunt)][riley-and-hunt-computational-thinking]. Also offer strategies for thinking about problems and breaking them down for coding solutions. - [From Computing to Computational Thinking (Paul S. Wang)][wang-computational-thinking] is a bit more generalized and academic, but offers problem-solving strategies and structures that can apply to more than coding, and does not require prior programming knowledge. diff --git a/exercises/concept/black-jack/.docs/introduction.md b/exercises/concept/black-jack/.docs/introduction.md index ec19d2f71f7..eb1036e7e87 100644 --- a/exercises/concept/black-jack/.docs/introduction.md +++ b/exercises/concept/black-jack/.docs/introduction.md @@ -1,3 +1,5 @@ +# Introduction + ## Comparisons Python supports the following basic comparison operators: @@ -79,7 +81,7 @@ False Unlike numbers, strings (`str`) are compared [_lexicographically_][lexographic order], using their individual Unicode code points (_the result of passing each code point in the `str` to the built-in function [`ord()`][ord], which returns an `int`_). If all code points in both strings match and are _**in the same order**_, the two strings are considered equal. -This comparison is done in a 'pair-wise' fashion - first-to-first, second-to-second, etc. +This comparison is done in a 'pair-wise' fashion — first-to-first, second-to-second, etc. In Python 3.x, `str` and `bytes` cannot be directly coerced/compared. ```python @@ -113,12 +115,12 @@ False ## Comparison Chaining -Comparison operators can be chained _arbitrarily_ -- meaning that they can be used in any combination of any length. +Comparison operators can be chained _arbitrarily_ — meaning that they can be used in any combination of any length. Note that the evaluation of an expression takes place from `left` to `right`. As an example, `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated **only once**. In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`. -This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined. +This is often called `short-circuit evaluation` — the evaluation stops if the truth value of the expression has already been determined. `Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python. Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence. diff --git a/exercises/concept/card-games/.docs/instructions.md b/exercises/concept/card-games/.docs/instructions.md index 3b60d0b6fed..0867ff6ac12 100644 --- a/exercises/concept/card-games/.docs/instructions.md +++ b/exercises/concept/card-games/.docs/instructions.md @@ -1,13 +1,13 @@ # Instructions Elyse is really looking forward to playing some poker (and other card games) during her upcoming trip to Vegas. - Being a big fan of "self-tracking" she wants to put together some small functions that will help her with tracking tasks and has asked for your help thinking them through. +Being a big fan of "self-tracking" she wants to put together some small functions that will help her with tracking tasks and has asked for your help thinking them through. ## 1. Tracking Poker Rounds -Elyse is especially fond of poker, and wants to track how many rounds she plays - and _which rounds_ those are. - Every round has its own number, and every table shows the round number currently being played. - Elyse chooses a table and sits down to play her first round. She plans on playing three rounds. +Elyse is especially fond of poker, and wants to track how many rounds she plays — and _which rounds_ those are. +Every round has its own number, and every table shows the round number currently being played. +Elyse chooses a table and sits down to play her first round. She plans on playing three rounds. Implement a function `get_rounds()` that takes the current round number and returns a single `list` with that round and the _next two_ that are coming up: @@ -19,7 +19,7 @@ Implement a function `get_rounds()` that takes the current round n ## 2. Keeping all Rounds in the Same Place Elyse played a few rounds at the first table, then took a break and played some more rounds at a second table ... but ended up with a different list for each table! - She wants to put the two lists together, so she can track all of the poker rounds in the same place. +She wants to put the two lists together, so she can track all of the poker rounds in the same place. Implement a function `concatenate_rounds(, )` that takes two lists and returns a single `list` consisting of all the rounds in the first `list`, followed by all the rounds in the second `list`: @@ -31,10 +31,10 @@ Implement a function `concatenate_rounds(, )` that takes two ## 3. Finding Prior Rounds Talking about some of the prior Poker rounds, another player remarks how similarly two of them played out. - Elyse is not sure if she played those rounds or not. +Elyse is not sure if she played those rounds or not. Implement a function `list_contains_round(, )` that takes two arguments, a list of rounds played and a round number. - The function will return `True` if the round is in the list of rounds played, `False` if not: +The function will return `True` if the round is in the list of rounds played, `False` if not: ```python >>> list_contains_round([27, 28, 29, 35, 36], 29) @@ -47,8 +47,8 @@ False ## 4. Averaging Card Values Elyse wants to try out a new game called Black Joe. - It's similar to Black Jack - where your goal is to have the cards in your hand add up to a target value - but in Black Joe the goal is to get the _average_ of the card values to be 7. - The average can be found by summing up all the card values and then dividing that sum by the number of cards in the hand. +It's similar to Black Jack — where your goal is to have the cards in your hand add up to a target value — but in Black Joe the goal is to get the _average_ of the card values to be 7. +The average can be found by summing up all the card values and then dividing that sum by the number of cards in the hand. Implement a function `card_average()` that will return the average value of a hand of Black Joe. @@ -86,7 +86,7 @@ False ## 6. More Averaging Techniques Intrigued by the results of her averaging experiment, Elyse is wondering if taking the average of the cards at the _even_ positions versus the average of the cards at the _odd_ positions would give the same results. - Time for another test function! +Time for another test function! Implement a function `average_even_is_average_odd()` that returns a Boolean indicating if the average of the cards at even indexes is the same as the average of the cards at odd indexes. @@ -103,7 +103,7 @@ False Every 11th hand in Black Joe is a bonus hand with a bonus rule: if the last card you draw is a Jack, you double its value. Implement a function `maybe_double_last()` that takes a hand and checks if the last card is a Jack (11). - If the last card **is** a Jack (11), double its value before returning the hand. +If the last card **is** a Jack (11), double its value before returning the hand. ```python >>> hand = [5, 9, 11] diff --git a/exercises/concept/card-games/.docs/introduction.md b/exercises/concept/card-games/.docs/introduction.md index bb0c2381171..abb0176c37d 100644 --- a/exercises/concept/card-games/.docs/introduction.md +++ b/exercises/concept/card-games/.docs/introduction.md @@ -1,15 +1,15 @@ # Introduction A [`list`][list] is a mutable collection of items in _sequence_. -Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) - including other lists. +Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) — including other lists. Like any [sequence][sequence type], items can be accessed via `0-based index` number from the left and `-1-based index` from the right. Lists can be copied in whole or in part via [slice notation][slice notation] or `.copy()`. Lists support both [common][common sequence operations] and [mutable][mutable sequence operations] sequence operations such as `min()`/`max()`, `.index()`, `.append()` and `.reverse()`. List elements can be iterated over using the `for item in ` construct. - `for index, item in enumerate()` can be used when both the element index and the element value are needed. +`for index, item in enumerate()` can be used when both the element index and the element value are needed. -Under the hood, `lists` are implemented as [dynamic arrays][dynamic array] -- similar to Java's [`ArrayList`][arraylist] type, and are most often used to store groups of similar data (_strings, numbers, sets etc._) of unknown length. +Under the hood, `lists` are implemented as [dynamic arrays][dynamic array] — similar to Java's [`ArrayList`][arraylist] type, and are most often used to store groups of similar data (_strings, numbers, sets etc._) of unknown length. Lists are an extremely flexible and useful data structure and many built-in methods and operations in Python produce lists as their output. @@ -65,7 +65,7 @@ For readability, line breaks can be used when there are many elements or nested ``` The `list()` constructor can be used empty or with an _iterable_ as an argument. - Elements in the iterable are cycled through by the constructor and added to the `list` in order: +Elements in the iterable are cycled through by the constructor and added to the `list` in order: ```python @@ -111,7 +111,7 @@ Results when using a `list` constructor with a `string` or a `dict` may be surpr ``` Because the `list` constructor will only take _iterables_ (or nothing) as arguments, objects that are _not_ iterable will throw a type error. - Consequently, it is much easier to create a one-item `list` via the literal method. +Consequently, it is much easier to create a one-item `list` via the literal method. ```python # Numbers are not iterable, and so attempting to create a list with a number passed to the constructor fails. @@ -130,7 +130,7 @@ TypeError: 'int' object is not iterable ## Accessing elements Items inside lists (_as well as items in other sequence types `str` & `tuple`_) can be accessed via `0-based index` and _bracket notation_. - Indexes can be from **`left`** --> **`right`** (_starting at zero_) or **`right`** --> **`left`** (_starting at -1_). +Indexes can be from **`left`** --> **`right`** (_starting at zero_) or **`right`** --> **`left`** (_starting at -1_). @@ -169,8 +169,8 @@ Items inside lists (_as well as items in other sequence types `str` & `tuple`_) ``` A section of the elements inside a `list` can be accessed via _slice notation_ (`[start:stop]`). - A _slice_ is defined as an element sequence at position `index`, such that `start <= index < stop`. - _Slicing_ returns a copy of the "sliced" items and does not modify the original `list`. +A _slice_ is defined as an element sequence at position `index`, such that `start <= index < stop`. +_Slicing_ returns a copy of the "sliced" items and does not modify the original `list`. A `step` parameter can also be used `[start:stop:step]` to "skip over" or filter the `list` elements (_for example, a `step` of 2 will select every other element in the range_): diff --git a/exercises/concept/cater-waiter/.docs/instructions.md b/exercises/concept/cater-waiter/.docs/instructions.md index 4ed51a444d5..d9bc9410ce2 100644 --- a/exercises/concept/cater-waiter/.docs/instructions.md +++ b/exercises/concept/cater-waiter/.docs/instructions.md @@ -5,10 +5,10 @@ You and your business partners operate a small catering company. You've just agr ## 1. Clean up Dish Ingredients The event recipes were added from various sources and their ingredients appear to have duplicate (_or more_) entries — you don't want to end up purchasing excess items! - Before the shopping and cooking can commence, each dish's ingredient list needs to be "cleaned". +Before the shopping and cooking can commence, each dish's ingredient list needs to be "cleaned". Implement the `clean_ingredients(, )` function that takes the name of a dish and a `list` of ingredients. - This function should return a `tuple` with the name of the dish as the first item, followed by the de-duped `set` of ingredients. +This function should return a `tuple` with the name of the dish as the first item, followed by the de-duped `set` of ingredients. ```python @@ -19,12 +19,12 @@ Implement the `clean_ingredients(, )` function that ## 2. Cocktails and Mocktails -The event is going to include both cocktails and "mocktails" - mixed drinks _without_ the alcohol. - You need to ensure that "mocktail" drinks are truly non-alcoholic and the cocktails do indeed _include_ alcohol. +The event is going to include both cocktails and "mocktails" — mixed drinks _without_ the alcohol. +You need to ensure that "mocktail" drinks are truly non-alcoholic and the cocktails do indeed _include_ alcohol. Implement the `check_drinks(, )` function that takes the name of a drink and a `list` of ingredients. - The function should return the name of the drink followed by "Mocktail" if the drink has no alcoholic ingredients, and drink name followed by "Cocktail" if the drink includes alcohol. - For the purposes of this exercise, cocktails will only include alcohols from the ALCOHOLS constant in `sets_categories_data.py`: +The function should return the name of the drink followed by "Mocktail" if the drink has no alcoholic ingredients, and drink name followed by "Cocktail" if the drink includes alcohol. +For the purposes of this exercise, cocktails will only include alcohols from the ALCOHOLS constant in `sets_categories_data.py`: ```python >>> from sets_categories_data import ALCOHOLS @@ -68,7 +68,7 @@ These ingredients need to be tagged/annotated for each dish so that they don't c Implement the `tag_special_ingredients()` function that takes a `tuple` with the dish name in the first position, and a `list` or `set` of ingredients for that dish in the second position. Return the dish name followed by the `set` of ingredients that require a special note on the dish description. Dish ingredients inside a `list` may or may not have duplicates. - For the purposes of this exercise, all allergens or special ingredients that need to be labeled are in the SPECIAL_INGREDIENTS constant imported from `sets_categories_data.py`. +For the purposes of this exercise, all allergens or special ingredients that need to be labeled are in the SPECIAL_INGREDIENTS constant imported from `sets_categories_data.py`. ```python >>> from sets_categories_data import SPECIAL_INGREDIENTS @@ -103,7 +103,7 @@ dishes = [ {'tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar ## 6. Pull out Appetizers for Passing on Trays The hosts have given you a list of dishes they'd like prepped as "bite-sized" appetizers to be served on trays. - You need to pull these from the main list of dishes being prepared as larger servings. +You need to pull these from the main list of dishes being prepared as larger servings. Implement the `separate_appetizers(, )` function that takes a `list` of dish names and a `list` of appetizer names. The function should return the `list` of dish names with appetizer names removed. diff --git a/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md b/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md index 0a5bf25ff0d..d45ed453d53 100644 --- a/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md +++ b/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md @@ -7,7 +7,7 @@ Chaitana owns a very popular theme park. There are two queues for this ride, each represented as a `list`: 1. Normal Queue -2. Express Queue (_also known as the Fast-track_) - where people pay extra for priority access. +2. Express Queue (_also known as the Fast-track_) — where people pay extra for priority access. You have been asked to write some code to better manage the guests at the park. diff --git a/exercises/concept/chaitanas-colossal-coaster/.docs/introduction.md b/exercises/concept/chaitanas-colossal-coaster/.docs/introduction.md index bfbf0537522..5394b1bfd88 100644 --- a/exercises/concept/chaitanas-colossal-coaster/.docs/introduction.md +++ b/exercises/concept/chaitanas-colossal-coaster/.docs/introduction.md @@ -1,20 +1,20 @@ # Introduction A [`list`][list] is a mutable collection of items in _sequence_. - Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) - including other lists. - Lists can be copied in whole or in part via [slice notation][slice notation] or through the use of `.copy()`. - Like any [sequence][sequence type], elements within `lists` are referenced by `0-based index` number from the left, or `-1-based index` number from the right. +Like most collections (_see the built-ins [`tuple`][tuple], [`dict`][dict] and [`set`][set]_), lists can hold reference to any (or multiple) data type(s) — including other lists. +Lists can be copied in whole or in part via [slice notation][slice notation] or through the use of `.copy()`. +Like any [sequence][sequence type], elements within `lists` are referenced by `0-based index` number from the left, or `-1-based index` number from the right. Lists support both [common][common sequence operations] and [mutable][mutable sequence operations] sequence operations such as `min()`/`max()`, `.index()`, `.append()` and `.reverse()`. - Elements inside a `list` can be iterated over using the `for item in ` construct. - `for index, item in enumerate()` can be used when both the element index and element value are needed. +Elements inside a `list` can be iterated over using the `for item in ` construct. +`for index, item in enumerate()` can be used when both the element index and element value are needed. Python also provides many useful [list-methods][list-methods] for working with lists. - A selection of these `list methods` is covered below. +A selection of these `list methods` is covered below. Note that when you manipulate a `list` with a `list-method`, **you alter the list** object that has been passed. - If you do not wish to mutate the original `list`, you will need to at least make a `shallow copy` of it via slice or `.copy()`. +If you do not wish to mutate the original `list`, you will need to at least make a `shallow copy` of it via slice or `.copy()`. ## Adding Items @@ -36,7 +36,7 @@ It takes 2 parameters: 2. the `` to be inserted. **Note**: If the given `index` is 0, the item will be added to the start ("left-hand side") of the `list`. - If the supplied `index` is greater than the final `index` on the `list`, the item will be added in the final position -- the equivalent of using `.append()`. +If the supplied `index` is greater than the final `index` on the `list`, the item will be added in the final position — the equivalent of using `.append()`. ```python @@ -54,7 +54,7 @@ It takes 2 parameters: `.extend()` can be used to combine an existing list with the elements from another iterable (for example, a `set`, `tuple`, `str`, or `list`). - The iterable is _unpacked_ and elements are appended in order (_Using `.append()` in this circumstance would add the entire iterable as a **single item**._). +The iterable is _unpacked_ and elements are appended in order (_Using `.append()` in this circumstance would add the entire iterable as a **single item**._). ```python @@ -81,7 +81,7 @@ It takes 2 parameters: ## Removing Items To delete an item from a list use `.remove()`, passing the item to be removed as an argument. - `.remove()` will throw a `ValueError` if the item is not present in the `list`. +`.remove()` will throw a `ValueError` if the item is not present in the `list`. ```python @@ -101,8 +101,8 @@ Alternatively, using the `.pop()` method will both remove **and** ` `.pop()` takes one optional parameter: the `index` of the item to be removed and returned. - If the (optional) `index` argument is not specified, the final element of the `list` will be removed and returned. - If the `index` specified is higher than the final item `index`, an `IndexError` is raised. +If the (optional) `index` argument is not specified, the final element of the `list` will be removed and returned. +If the `index` specified is higher than the final item `index`, an `IndexError` is raised. ```python @@ -155,7 +155,7 @@ Default sort order is _ascending_ from the left. The Python docs offer [additional tips and techniques for sorting][sorting how to]. ~~~~exercism/note - From 2002 to 2022, Python used an algorithm called [`Timsort`][timsort] internally to arrange lists, but switched to [`Powersort`][powersort] from `Python 3.11` onward. +From 2002 to 2022, Python used an algorithm called [`Timsort`][timsort] internally to arrange lists, but switched to [`Powersort`][powersort] from `Python 3.11` onward. [powersort]: https://www.wild-inter.net/publications/munro-wild-2018 [timsort]: https://en.wikipedia.org/wiki/Timsort @@ -209,8 +209,8 @@ The number of occurrences of an element in a list can be calculated with the hel ## Finding the index of items `.index()` will return the `index` number of the _first occurrence_ of an item passed in. - If there are no occurrences, a `ValueError` is raised. - If the exact position of an item isn't needed, the built-in `in` operator is more efficient for checking if a list contains a given value. +If there are no occurrences, a `ValueError` is raised. +If the exact position of an item isn't needed, the built-in `in` operator is more efficient for checking if a list contains a given value. Indexing is zero-based from the left, so the position of the "first" item is `0`. diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md index 7a103d4df6a..38011ea5ca6 100644 --- a/exercises/concept/currency-exchange/.docs/instructions.md +++ b/exercises/concept/currency-exchange/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Your friend Chandler plans to visit exotic countries all around the world. Sadly, Chandler's math skills aren't good. He's pretty worried about being scammed by currency exchanges during his trip - and he wants you to make a currency calculator for him. Here are his specifications for the app: +Your friend Chandler plans to visit exotic countries all around the world. Sadly, Chandler's math skills aren't good. He's pretty worried about being scammed by currency exchanges during his trip — and he wants you to make a currency calculator for him. Here are his specifications for the app: ## 1. Estimate value after exchange diff --git a/exercises/concept/ellens-alien-game/.docs/introduction.md b/exercises/concept/ellens-alien-game/.docs/introduction.md index fead4bf6401..76c51c0ca53 100644 --- a/exercises/concept/ellens-alien-game/.docs/introduction.md +++ b/exercises/concept/ellens-alien-game/.docs/introduction.md @@ -4,7 +4,7 @@ If you have been programming in a [functional][functional], [declarative][declarative], or [imperative][imperative] style, shifting focus to [object oriented programming][oop] (OOP) may feel a bit foreign. An OOP approach asks the programmer to think about modeling a problem as one or more `objects` that interact with one another, keep state, and act upon data. -Objects can represent real world entities (_such as cars or cats_) - or more abstract concepts (_such as integers, vehicles, or mammals_). +Objects can represent real world entities (_such as cars or cats_) — or more abstract concepts (_such as integers, vehicles, or mammals_). Each object becomes a unique instance in computer memory and represents some part of the overall model. ## Classes @@ -43,7 +43,7 @@ An instance (_object_) of `MyClass` can be created and bound to a name by [_call <__main__.MyClass at 0x15adc55b0> ``` -`Class attributes` are shared across all objects (_or instances_) created from a class, and can be accessed via [`dot notation`][dot notation] - a `.` placed after the object name and before the attribute name: +`Class attributes` are shared across all objects (_or instances_) created from a class, and can be accessed via [`dot notation`][dot notation] — a `.` placed after the object name and before the attribute name: ```python >>> new_object = MyClass() @@ -69,7 +69,7 @@ True ``` Class attributes are defined in the body of the class itself, before any other methods. -They are owned by the class - allowing them to be shared across instances of the class. +They are owned by the class — allowing them to be shared across instances of the class. Because these attributes are shared, their value can be accessed and manipulated from the class _directly_. Altering the value of class attributes alters the value _**for all objects instantiated from the class**_: @@ -230,7 +230,7 @@ class MyClass: ## Placeholding or Stubbing Implementation with Pass In previous concept exercises and practice exercise stubs, you will have seen the `pass` keyword used within the body of functions in place of actual code. -The `pass` keyword is a syntactically valid placeholder - it prevents Python from throwing a syntax error for an empty function or class definition. +The `pass` keyword is a syntactically valid placeholder — it prevents Python from throwing a syntax error for an empty function or class definition. Essentially, it is a way to say to the Python interpreter, 'Don't worry! I _will_ put code here eventually, I just haven't done it yet.' ```python diff --git a/exercises/concept/little-sisters-essay/.docs/introduction.md b/exercises/concept/little-sisters-essay/.docs/introduction.md index 0eacedfee07..51d5df35aab 100644 --- a/exercises/concept/little-sisters-essay/.docs/introduction.md +++ b/exercises/concept/little-sisters-essay/.docs/introduction.md @@ -59,11 +59,11 @@ False ``` [`.strip()`][str-strip] returns a copy of the `str` with leading and trailing `` removed. -The code points specified in `` are not a prefix or suffix - **all combinations** of the code points will be removed starting from **both ends** of the string. - If nothing is specified for ``, all combinations of whitespace code points will be removed. +The code points specified in `` are not a prefix or suffix — **all combinations** of the code points will be removed starting from **both ends** of the string. +If nothing is specified for ``, all combinations of whitespace code points will be removed. - ```python +```python # This will remove "https://", because it can be formed from "/stph:". >>> 'https://unicode.org/emoji/'.strip('/stph:') 'unicode.org/emoji' diff --git a/exercises/concept/little-sisters-vocab/.docs/instructions.md b/exercises/concept/little-sisters-vocab/.docs/instructions.md index 991845a7043..34ca356001b 100644 --- a/exercises/concept/little-sisters-vocab/.docs/instructions.md +++ b/exercises/concept/little-sisters-vocab/.docs/instructions.md @@ -1,8 +1,8 @@ # Instructions You are helping your younger sister with her English vocabulary homework, which she is finding very tedious. - Her class is learning to create new words by adding _prefixes_ and _suffixes_. - Given a set of words, the teacher is looking for correctly transformed words with correct spelling by adding the prefix to the beginning or the suffix to the ending. +Her class is learning to create new words by adding _prefixes_ and _suffixes_. +Given a set of words, the teacher is looking for correctly transformed words with correct spelling by adding the prefix to the beginning or the suffix to the ending. The assignment has four activities, each with a set of text or words to work with. @@ -10,7 +10,7 @@ The assignment has four activities, each with a set of text or words to work wit ## 1. Add a prefix to a word One of the most common prefixes in English is `un`, meaning "not". - In this activity, your sister needs to make negative, or "not" words by adding `un` to them. +In this activity, your sister needs to make negative, or "not" words by adding `un` to them. Implement the `add_prefix_un()` function that takes `word` as a parameter and returns a new `un` prefixed word: @@ -32,13 +32,13 @@ There are four more common prefixes that your sister's class is studying: `auto` (_meaning 'self' or 'same'_), and `inter` (_meaning 'between' or 'among'_). - In this exercise, the class is creating groups of vocabulary words using these prefixes, so they can be studied together. - Each prefix comes in a list with common words it's used with. - The students need to apply the prefix and produce a string that shows the prefix applied to all of the words. +In this exercise, the class is creating groups of vocabulary words using these prefixes, so they can be studied together. +Each prefix comes in a list with common words it's used with. +The students need to apply the prefix and produce a string that shows the prefix applied to all of the words. Implement the `make_word_groups()` function that takes a `vocab_words` as a parameter in the following form: - `[, , .... ]`, and returns a string with the prefix applied to each word that looks like: - `' :: :: :: '`. +`[, , .... ]`, and returns a string with the prefix applied to each word that looks like: +`' :: :: :: '`. Creating a `for` or `while` loop to process the input is not needed here. Think carefully about which string methods (and delimiters) you could use instead. @@ -80,14 +80,14 @@ Implement the `remove_suffix_ness()` function that takes in a `word`, and ## 4. Extract and transform a word Suffixes are often used to change the part of speech a word is assigned to. - A common practice in English is "verbing" or "verbifying" -- where an adjective _becomes_ a verb by adding an `en` suffix. +A common practice in English is "verbing" or "verbifying" -- where an adjective _becomes_ a verb by adding an `en` suffix. In this task, your sister is going to practice "verbing" words by extracting an adjective from a sentence and turning it into a verb. - Fortunately, all the words that need to be transformed here are "regular" - they don't need spelling changes to add the suffix. +Fortunately, all the words that need to be transformed here are "regular" — they don't need spelling changes to add the suffix. Implement the `adjective_to_verb(, )` function that takes two parameters. - A `sentence` using the vocabulary word, and the `index` of the word, once that sentence is split apart. - The function should return the extracted adjective as a verb. +A `sentence` using the vocabulary word, and the `index` of the word, once that sentence is split apart. +The function should return the extracted adjective as a verb. ```python diff --git a/exercises/concept/mecha-munch-management/.docs/introduction.md b/exercises/concept/mecha-munch-management/.docs/introduction.md index 6f63d8acd60..9e9d724f6de 100644 --- a/exercises/concept/mecha-munch-management/.docs/introduction.md +++ b/exercises/concept/mecha-munch-management/.docs/introduction.md @@ -2,9 +2,9 @@ The `dict` class in Python provides many useful [methods][dict-methods] for working with dictionaries. Some were introduced in the concept for `dicts`. -Here we cover a few more - along with some techniques for iterating through and manipulating dictionaries. +Here we cover a few more — along with some techniques for iterating through and manipulating dictionaries. -### Use `setdefault()` for Error-Free Insertion +## Use `setdefault()` for Error-Free Insertion The dictionary concept previously covered that `.get(key, )` returns an existing `value` or the `default value` if a `key` is not found in a dictionary, thereby avoiding a `KeyError`. This works well in situations where you would rather not have extra error handling but cannot trust that a looked-for `key` will be present. diff --git a/exercises/concept/plane-tickets/.docs/introduction.md b/exercises/concept/plane-tickets/.docs/introduction.md index ac0a53a8ef2..678a9a06789 100644 --- a/exercises/concept/plane-tickets/.docs/introduction.md +++ b/exercises/concept/plane-tickets/.docs/introduction.md @@ -5,7 +5,7 @@ A `generator` is a function or expression that returns a special type of [iterat A generator function looks like any other function, but contains one or more [yield expressions][yield expression]. Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_). -When the generator resumes, it picks up state from the suspension - unlike regular functions which reset with every call. +When the generator resumes, it picks up state from the suspension — unlike regular functions which reset with every call. ## Constructing a generator @@ -88,7 +88,7 @@ Generator-iterators and the iterators returned by common Python [`iterables`][it - They are not sequence types, and _do not_ have `indexes`. You cannot reference a previous or future value using addition or subtraction and you cannot use bracket (`[]`) notation or slicing. - They cannot be used with the `len()` function, as they have no length. -- They can be _finite_ or _infinite_ - be careful when collecting all values from an _infinite_ `generator-iterator`! +- They can be _finite_ or _infinite_ — be careful when collecting all values from an _infinite_ `generator-iterator`! [iterator]: https://docs.python.org/3.11/glossary.html#term-iterator [iterables]: https://wiki.python.org/moin/Iterator diff --git a/exercises/concept/pretty-leaflet/.docs/instructions.md b/exercises/concept/pretty-leaflet/.docs/instructions.md index d09c7363643..a09d019357e 100644 --- a/exercises/concept/pretty-leaflet/.docs/instructions.md +++ b/exercises/concept/pretty-leaflet/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -Your acquaintance Erin needs to print thousands of handbills for multiple events and they need your help! They've asked you to create the layout for a leaflet containing a header, an optional date, and a list of artists -- each associated with a _unicode icon_. The goal is to `print` and distribute your cool new leaflet design - and you'll need all your Python string formatting skills to succeed. +Your acquaintance Erin needs to print thousands of handbills for multiple events and they need your help! They've asked you to create the layout for a leaflet containing a header, an optional date, and a list of artists — each associated with a _unicode icon_. The goal is to `print` and distribute your cool new leaflet design — and you'll need all your Python string formatting skills to succeed. ## 1. Create the class with a capitalized header diff --git a/exercises/practice/acronym/.approaches/generator-expression/content.md b/exercises/practice/acronym/.approaches/generator-expression/content.md index 47ec9aa8f89..2337f7a3e87 100644 --- a/exercises/practice/acronym/.approaches/generator-expression/content.md +++ b/exercises/practice/acronym/.approaches/generator-expression/content.md @@ -28,9 +28,9 @@ As of this writing, both of these methods benchmark slower than using `str.repla A [`generator-expression`][generator-expression] is then used to iterate through the phrase and select the first letters of each word via [`bracket notation`][subscript notation]. -Generator expressions are short-form [generators][generators] - lazy iterators that produce their values _on demand_, instead of saving them to memory. +Generator expressions are short-form [generators][generators] — lazy iterators that produce their values _on demand_, instead of saving them to memory. This generator expression is consumed by [`str.join()`][str-join], which joins the generated letters together using an empty string. -Other "separator" strings can be used with `str.join()` - see [concept:python/string-methods]() for some additional examples. +Other "separator" strings can be used with `str.join()` — see [concept:python/string-methods]() for some additional examples. Since the generator expression and `join()` are fairly succinct, they are put directly on the `return` line rather than assigning and returning an intermediate variable for the acronym. diff --git a/exercises/practice/acronym/.approaches/list-comprehension/content.md b/exercises/practice/acronym/.approaches/list-comprehension/content.md index 7e98f45c74f..abeab2377fb 100644 --- a/exercises/practice/acronym/.approaches/list-comprehension/content.md +++ b/exercises/practice/acronym/.approaches/list-comprehension/content.md @@ -24,12 +24,12 @@ As of this writing, both of these methods benchmark slower than using `str.repla A [`list comprehension`][list comprehension] is then used to iterate through the phrase and select the first letters of each word via [`bracket notation`][subscript notation]. -This comprehension is passed into [`str.join()`][str-join], which unpacks the `list` of first letters and joins them together using an empty string - the acronym. -Other "separator" strings besides an empty string can be used with `str.join()` - see [concept:python/string-methods]() for some additional examples. +This comprehension is passed into [`str.join()`][str-join], which unpacks the `list` of first letters and joins them together using an empty string — the acronym. +Other "separator" strings besides an empty string can be used with `str.join()` — see [concept:python/string-methods]() for some additional examples. Since the comprehension and `join()` are fairly succinct, they are put directly on the `return` line rather than assigning and returning an intermediate variable for the acronym. -The weakness of this solution is that it is taking up extra space with the `list comprehension`, which is creating and saving a `list` in memory - only to have that list immediately unpacked by the `str.join()` method. +The weakness of this solution is that it is taking up extra space with the `list comprehension`, which is creating and saving a `list` in memory — only to have that list immediately unpacked by the `str.join()` method. While this is trivial for the inputs this problem is tested against, it could become a problem if the inputs get longer. It could also be an issue if the code were deployed in a memory-constrained environment. A [generator expression][generator-expression] here would be more memory-efficient, though there are speed tradeoffs. diff --git a/exercises/practice/acronym/.approaches/map-function/content.md b/exercises/practice/acronym/.approaches/map-function/content.md index f237bd823bd..501bf7d03f6 100644 --- a/exercises/practice/acronym/.approaches/map-function/content.md +++ b/exercises/practice/acronym/.approaches/map-function/content.md @@ -29,8 +29,8 @@ The application of the function travels from left to right, and function results Using code from the example above, `map(lambda word: word[0], ['GNU', 'IMAGE', 'MANIPULATION', 'PROGRAM'])` would calculate `'GNU'[0], 'IMAGE'[0], 'MANIPULATION'[0]), 'PROGRAM'[0]` in order as a stream of data. - `word[0]` is the function, which extracts the letter at index zero for every word in the phrase list. -This stream of data can then be 'consumed' - either in a `loop`, or by being 'unpacked' by another function or process. +`word[0]` is the function, which extracts the letter at index zero for every word in the phrase list. +This stream of data can then be 'consumed' — either in a `loop`, or by being 'unpacked' by another function or process. Here, the `iterator` from `map()` is immediately consumed/unpacked by [`join()`][str-join], which glues the results together with an empty string to produce the acronym. diff --git a/exercises/practice/acronym/.approaches/regex-join/content.md b/exercises/practice/acronym/.approaches/regex-join/content.md index 227ba06d5ea..33d073371a1 100644 --- a/exercises/practice/acronym/.approaches/regex-join/content.md +++ b/exercises/practice/acronym/.approaches/regex-join/content.md @@ -72,9 +72,9 @@ Once `findall()` or `finditer()` completes, a [`generator-expression`][generator Note that when using `finditer()`, the `Match object` has to be unpacked via `match.group(0)`/`match[0]` before the first letter can be selected. -Generator expressions are short-form [generators][generators] - lazy iterators that produce their values _on demand_, instead of saving them to memory. +Generator expressions are short-form [generators][generators] — lazy iterators that produce their values _on demand_, instead of saving them to memory. This generator expression is consumed by [`str.join()`][str-join], which joins the generated letters together using an empty string. -Other "separator" strings can be used with `str.join()` - see [concept:python/string-methods]() for some additional examples. +Other "separator" strings can be used with `str.join()` — see [concept:python/string-methods]() for some additional examples. Finally, the result of `.join()` is capitalized using the [chained][chaining] [`.upper()`][str-upper]. @@ -82,7 +82,7 @@ Alternatively, `.upper()` can be used on `to_abbreviate` within `findall()`/`fin Since the generator expression + join + upper is fairly succinct, they can be placed directly on the `return` line rather than assigning and returning an intermediate variable for the acronym. -This approach was less performant in benchmarks than those using `loop`, `map`, `list-comprehension`, and `reduce`. +This approach was less performant in benchmarks than those using `loop`, `map`, `list-comprehension`, and `reduce`. [chaining]: https://pyneng.readthedocs.io/en/latest/book/04_data_structures/method_chaining.html [generator-expression]: https://dbader.org/blog/python-generator-expressions diff --git a/exercises/practice/acronym/.approaches/regex-sub/content.md b/exercises/practice/acronym/.approaches/regex-sub/content.md index 4f1b447d81f..f9451362bc6 100644 --- a/exercises/practice/acronym/.approaches/regex-sub/content.md +++ b/exercises/practice/acronym/.approaches/regex-sub/content.md @@ -53,7 +53,7 @@ This means that this expression will match any collection or repeat of the lette 3. `[ ,\-_]` matches any of the characters ` -_,` (_space, hyphen, underscore, comma_) once. -Because these matches are used in the `re.sub()` method, an empty string is _substituted_ - so the matches are _removed_ from the result. +Because these matches are used in the `re.sub()` method, an empty string is _substituted_ — so the matches are _removed_ from the result. As an example, for the input phrase `The Road _Not_ Taken`, the regex will match `he`, ` `, `oad`, ` `, `-`, `ot`, `-`, ` `, and `aken`, replacing each match with ''. diff --git a/exercises/practice/atbash-cipher/.approaches/introduction.md b/exercises/practice/atbash-cipher/.approaches/introduction.md index ce9786409a8..9866879554f 100644 --- a/exercises/practice/atbash-cipher/.approaches/introduction.md +++ b/exercises/practice/atbash-cipher/.approaches/introduction.md @@ -53,4 +53,4 @@ For more detail, [read here][approach-mono-function]. [approach-separate-functions]: https://exercism.org/tracks/python/exercises/atbash-cipher/approaches/separate-functions [approach-mono-function]: https://exercism.org/tracks/python/exercises/atbash-cipher/approaches/mono-function -[generator-expression]: https://www.programiz.com/python-programming/generator +[generator-expression]: https://www.programiz.com/python-programming/generator#expression diff --git a/exercises/practice/atbash-cipher/.approaches/separate-functions/content.md b/exercises/practice/atbash-cipher/.approaches/separate-functions/content.md index 1890625819c..48847679a8d 100644 --- a/exercises/practice/atbash-cipher/.approaches/separate-functions/content.md +++ b/exercises/practice/atbash-cipher/.approaches/separate-functions/content.md @@ -59,5 +59,5 @@ def chunk(text): return text[:5] + " " + chunk(text[5:]) ``` -[generator-expression]: https://www.programiz.com/python-programming/generator +[generator-expression]: https://www.programiz.com/python-programming/generator#expression [str-maketrans]: https://www.programiz.com/python-programming/methods/string/maketrans diff --git a/exercises/practice/darts/.approaches/booleans-as-ints/content.md b/exercises/practice/darts/.approaches/booleans-as-ints/content.md index c948f3d631c..cc9ecbd8f02 100644 --- a/exercises/practice/darts/.approaches/booleans-as-ints/content.md +++ b/exercises/practice/darts/.approaches/booleans-as-ints/content.md @@ -1,13 +1,11 @@ # Using Boolean Values as Integers - ```python def score(x_coord, y_coord): radius_squared = x_coord**2 + y_coord**2 return (radius_squared<=1)*5 + (radius_squared<=25)*4 + (radius_squared<=100)*1 ``` - In Python, the [Boolean values `True` and `False` are _subclasses_ of `int`][bools-as-ints] and can be interpreted as `0` (False) and `1` (True) in a mathematical context. This approach leverages that interpretation by checking which areas the throw falls into and multiplying each Boolean `int` by a scoring multiple. For example, a throw that lands on the 25 (_or 5 if using `math.sqrt(x**2 + y**2)`_) circle should have a score of 5: @@ -17,20 +15,18 @@ For example, a throw that lands on the 25 (_or 5 if using `math.sqrt(x**2 + y**2 5 ``` - -This makes for very compact code and has the added boost of not requiring any `loops` or additional data structures. +This makes for very compact code and has the added boost of not requiring any `loop`s or additional data structures. However, it is considered bad form to rely on Boolean interpretation. Instead, the Python documentation recommends an explicit conversion to `int`: - ```python def score(x_coord, y_coord): radius_squared = x_coord**2 + y_coord**2 return int(radius_squared<=1)*5 + int(radius_squared<=25)*4 + int(radius_squared<=100)*1 ``` -Beyond that recommendation, the terseness of this approach might be harder to reason about or decode — especially if a programmer is coming from a programming langauge that does not treat Boolean values as `ints`. +Beyond that recommendation, the terseness of this approach might be harder to reason about or decode — especially if a programmer is coming from a programming langauge that does not treat Boolean values as `int`s. Despite the "radius_squared" variable name, it is also more difficult to relate the scoring "rings" of the Dartboard to the values being checked and calculated in the `return` statement. If using this code in a larger program, it would be strongly recommended that a docstring be provided to explain the Dartboard rings, scoring rules, and the corresponding scores. -[bools-as-ints]: https://docs.python.org/3/library/stdtypes.html#boolean-type-bool \ No newline at end of file +[bools-as-ints]: https://docs.python.org/3/library/stdtypes.html#boolean-type-bool diff --git a/exercises/practice/darts/.approaches/dict-and-dict-get/content.md b/exercises/practice/darts/.approaches/dict-and-dict-get/content.md index 62c79f36a0d..9344c811333 100644 --- a/exercises/practice/darts/.approaches/dict-and-dict-get/content.md +++ b/exercises/practice/darts/.approaches/dict-and-dict-get/content.md @@ -1,6 +1,5 @@ # Using a Dictionary and `dict.get()` - ```python def score(x_coord, y_coord): point = x_coord**2 + y_coord**2 @@ -27,8 +26,7 @@ To see this in action, you can view this code on [Python Tutor][dict-get-python- Because of the listed dictionary qualities, **_order matters_**. -This approach depends on the outermost scoring circle containing all smaller circles and that -checks proceed from largest --> smallest circle. +This approach depends on the outermost scoring circle containing all smaller circles, and that checks proceed from largest to smallest circle. Iterating in the opposite direction will not resolve to the correct score. The following code variations do not pass the exercise tests: diff --git a/exercises/practice/darts/.approaches/dict-and-generator/content.md b/exercises/practice/darts/.approaches/dict-and-generator/content.md index 041ce80f1e4..c9a56de8fbf 100644 --- a/exercises/practice/darts/.approaches/dict-and-generator/content.md +++ b/exercises/practice/darts/.approaches/dict-and-generator/content.md @@ -66,7 +66,7 @@ def score(x_coord, y_coord): While all of these variations do pass the tests, they suffer from even more over-engineering/performance caution than the earlier tuple and loop approach (_although for the data in this problem, the performance hit is slight_). Additionally, the dictionary will take much more space in memory than using a `tuple` of tuples to hold scoring values. -In some circumstances, these variations might also be harder to reason about for those not familiar with `generator-expressions` or `list comprehensions`. +In some circumstances, these variations might also be harder to reason about for those not familiar with `generator-expressions` or `list-comprehensions`. [approach-tuple-and-loop]: https://exercism.org/tracks/python/exercises/darts/approaches/tuple-and-loop diff --git a/exercises/practice/darts/.approaches/if-statements/content.md b/exercises/practice/darts/.approaches/if-statements/content.md index 9bbb7ecf8c4..67b3c542179 100644 --- a/exercises/practice/darts/.approaches/if-statements/content.md +++ b/exercises/practice/darts/.approaches/if-statements/content.md @@ -1,10 +1,9 @@ # Use `if-statements` - ```python import math -# Checks scores from the center --> edge. +# Checks scores from the center to the edge. def score(x_coord, y_coord): distance = math.sqrt(x_coord**2 + y_coord**2) @@ -25,7 +24,7 @@ To avoid importing the `math` module (_for a very very slight speedup_), (`x**2 ```python -# Checks scores from the center --> edge. +# Checks scores from the center to the edge. def score(x_coord, y_coord): distance_squared = x_coord**2 + y_coord**2 @@ -39,11 +38,10 @@ def score(x_coord, y_coord): ## Variation 1: Check from Edge to Center Using Upper and Lower Bounds - ```python import math -# Checks scores from the edge --> center +# Checks scores from the edge to the center def score(x_coord, y_coord): distance = math.sqrt(x_coord**2 + y_coord**2) @@ -56,10 +54,10 @@ def score(x_coord, y_coord): This variant checks from the edge moving inward, checking both a lower and upper bound due to the overlapping scoring circles in this direction. -Scores for any of these solutions can also be assigned to a variable to avoid multiple `returns`, but this isn't really necessary: +Scores for any of these solutions can also be assigned to a variable to avoid multiple `return`s, but this isn't really necessary: ```python -# Checks scores from the edge --> center +# Checks scores from the edge to the center def score(x_coord, y_coord): distance_squared = x_coord**2 + y_coord**2 points = 10 diff --git a/exercises/practice/darts/.approaches/introduction.md b/exercises/practice/darts/.approaches/introduction.md index f4ca20dcf0c..dd44c98c9ad 100644 --- a/exercises/practice/darts/.approaches/introduction.md +++ b/exercises/practice/darts/.approaches/introduction.md @@ -7,7 +7,7 @@ Among them are: - Using `if-statements` - Using a `tuple` (or `list` or `dict`) and a `for-loop` - Using a `dict` (or `tuple` or `list`) and a `generator-expression` -- Using `boolean` values as `ints` +- Using `boolean` values as `int`s - Using a `dict` and `dict.get()` - Using `match/case` (_Python 3.10+ only_) @@ -29,11 +29,10 @@ Darts that fall on a _boundary_ are scored based on the area below the line (_cl ## Approach: Using `if` statements - ```python import math -# Checks scores from the center --> edge. +# Checks scores from the center to the edge. def score(x_coord, y_coord): distance = math.sqrt(x_coord**2 + y_coord**2) @@ -111,7 +110,7 @@ def score(x_coord, y_coord): return scores.get(True, 0) ``` -This approach uses a dictionary to hold the distance --> scoring mappings and `dict.get()` to retrieve the correct points value. +This approach uses a dictionary to hold the distance-to-scoring mappings and `dict.get()` to retrieve the correct points value. For more details, read the [`Dictionary and dict.get()`][approach-dict-and-dict-get] approach. @@ -137,9 +136,10 @@ For more details, see the [structural pattern matching][approach-match-case] app ## Which approach to use? -Many of these approaches are a matter of personal preference - there are not significant memory or performance differences. +Many of these approaches are a matter of personal preference — there are not significant memory or performance differences. Although a strong argument could be made for simplicity and clarity — many listed solutions (_while interesting_) are harder to reason about or are over-engineered for the current scope of the exercise. + [approach-booleans-as-ints]: https://exercism.org/tracks/python/exercises/darts/approaches/booleans-as-ints [approach-dict-and-dict-get]: https://exercism.org/tracks/python/exercises/darts/approaches/dict-and-dict-get [approach-dict-and-generator]: https://exercism.org/tracks/python/exercises/darts/approaches/dict-and-generator diff --git a/exercises/practice/darts/.approaches/tuple-and-loop/content.md b/exercises/practice/darts/.approaches/tuple-and-loop/content.md index ec92b3142e9..d673a2bb141 100644 --- a/exercises/practice/darts/.approaches/tuple-and-loop/content.md +++ b/exercises/practice/darts/.approaches/tuple-and-loop/content.md @@ -14,7 +14,7 @@ def score(x_coord, y_coord): This approach uses a loop to iterate through the _rules_ `tuple`, unpacking each (`distance`, `points`) pair (_For a little more on unpacking, see [Tuple Unpacking Improves Python Code Readability][tuple-unpacking]_). If the calculated distance of the throw is less than or equal to a given distance, the score for that region is returned. -A `list` of `lists`, a `list` of `tuples`, or a dictionary could be used here to the same effect: +A `list` of `list`s, a `list` of `tuple`s, or a dictionary could be used here to the same effect: ```python def score(x_coord, y_coord): diff --git a/exercises/practice/darts/.docs/hints.md b/exercises/practice/darts/.docs/hints.md index fa866f9fc9e..3985140380d 100644 --- a/exercises/practice/darts/.docs/hints.md +++ b/exercises/practice/darts/.docs/hints.md @@ -2,18 +2,18 @@ ## General -- This challenge is all about calculating if a point falls _on, in, or outside_ a given circle. -- There are two different ways of calculating if a point falls on, in, or outside a circle. - - This _Stack Overflow_ Post: [Equation for Testing if a Point is Inside a Circle][point-circle-equation] outlines one method. - - This _DoubleRoot_ post [Position of a point relative to a circle][point-to-circle] outlines a different one. - - This _Math is Fun_ post covers a more general [Distance Between 2 Points][distance-between-two-points] calculation. +- This challenge is all about calculating if a point falls _on, in, or outside_ a given circle. +- There are two different ways of calculating if a point falls on, in, or outside a circle. + - This _Stack Overflow_ Post: [Equation for Testing if a Point is Inside a Circle][point-circle-equation] outlines one method. + - This _DoubleRoot_ post [Position of a point relative to a circle][point-to-circle] outlines a different one. + - This _Math is Fun_ post covers a more general [Distance Between 2 Points][distance-between-two-points] calculation. - Because the dart board is a set of _concentric_ circles, the order in which you calculate points could change the answer significantly. You should pay attention to which direction your calculations "move" in. -- Remember that this exercise has many potential solutions and many paths you can take along the way. - No path is manifestly "better" than another, although a particular path may be more interesting or better suited to what you want to learn or explore right now. -- Some paths may trade speed for clarity. - Others might take up more memory but be more scalable or maintainable. -- We encourage you to try out more than one programming strategy to see what happens. +- Remember that this exercise has many potential solutions and many paths you can take along the way. + No path is manifestly "better" than another, although a particular path may be more interesting or better suited to what you want to learn or explore right now. +- Some paths may trade speed for clarity. + Others might take up more memory but be more scalable or maintainable. +- We encourage you to try out more than one programming strategy to see what happens. [point-circle-equation]: https://stackoverflow.com/questions/481144/equation-for-testing-if-a-point-is-inside-a-circle [point-to-circle]: https://doubleroot.in/lessons/circle/position-of-a-point/ diff --git a/exercises/practice/dnd-character/.approaches/dice-roll-static-method/content.md b/exercises/practice/dnd-character/.approaches/dice-roll-static-method/content.md index ef358c60698..7f466351dc0 100644 --- a/exercises/practice/dnd-character/.approaches/dice-roll-static-method/content.md +++ b/exercises/practice/dnd-character/.approaches/dice-roll-static-method/content.md @@ -32,7 +32,7 @@ This approach separates the `ability()` method from a [`static method`][staticme `ability()` returns the value of a randomly chosen character ability using [`random.choice`][random-choice] but does not roll dice or calculate values. Instead, `dice_rolls()` handles the rolls/values using [`random.choice`][random-choice] for selection. -The argument for this is that the logic/functionality of rolling dice 4 times and summing the top three values is not really related to a DnD character or their abilities - it is independent and likely useful across a wider scope than just the character class. +The argument for this is that the logic/functionality of rolling dice 4 times and summing the top three values is not really related to a DnD character or their abilities — it is independent and likely useful across a wider scope than just the character class. However, it might be tidier to include it in the character class, rather than "clutter" the program or module with an additional stand-alone function. Declaring `dice_rolls()` as a static method allows other callers to use the function with or without instantiating a new `Character` object. It also makes it cleaner to maintain, should the method or number of the dice rolls change. diff --git a/exercises/practice/dnd-character/.approaches/stand-alone-dice-roll-function/content.md b/exercises/practice/dnd-character/.approaches/stand-alone-dice-roll-function/content.md index 66d293a07d6..4b849fef94c 100644 --- a/exercises/practice/dnd-character/.approaches/stand-alone-dice-roll-function/content.md +++ b/exercises/practice/dnd-character/.approaches/stand-alone-dice-roll-function/content.md @@ -33,7 +33,7 @@ def modifier(constitution): This approach separates the `ability()` method from a stand-alone function that calculates dice rolls. `ability()` returns the value of a randomly chosen character ability using [`random.choice`][randon-choice], but does not roll dice or calculate values. Instead, `dice_rolls()` handles the rolls/values, using [`random.randint`][random-randint] to generate them. -The argument for this is that the logic/functionality of rolling dice 4 times and summing the top three values is not really related to a DnD character or their abilities - it is independent and likely useful across a wider scope than just the character class. +The argument for this is that the logic/functionality of rolling dice 4 times and summing the top three values is not really related to a DnD character or their abilities — it is independent and likely useful across a wider scope than just the character class. It also makes it cleaner to maintain, should the method or number of the dice rolls change. `dice_rolls()` is then called in `__init__()` to populate the listed-out character attributes. @@ -47,7 +47,7 @@ The "too few" rule encourages you to think about the design of the class: is it What other functionality should this class hold? Should the `dice_roll()` function be outside or inside (_as a regular method or a static method_) the class? -None of these (_including the analyzer complaint about too few methods_) is a hard and fast rule or requirement - all are considerations for the class as you build out a larger program. +None of these (_including the analyzer complaint about too few methods_) is a hard and fast rule or requirement — all are considerations for the class as you build out a larger program. An alternative is to write a [dataclass][dataclass], although the design discussion and questions above remain the same: diff --git a/exercises/practice/hamming/.approaches/introduction.md b/exercises/practice/hamming/.approaches/introduction.md index 3272a8bd05a..b701fd7443d 100644 --- a/exercises/practice/hamming/.approaches/introduction.md +++ b/exercises/practice/hamming/.approaches/introduction.md @@ -1,7 +1,7 @@ # Introduction There are various ways to solve Hamming. -One approach is to iterate over either a range of indexes or to use [zip][zip]. +One approach is to iterate over either a range of indexes or to use [`zip`][zip]. Another approach is to use the range of indexes. Some other approaches include the use of [`enumerate`][enumerate], or [`filter`][filter] with a [`lambda`][lambda]. @@ -49,7 +49,7 @@ def distance(strand_a, strand_b): return count ``` -For more information, check the [zip approach][approach-zip]. +For more information, check the [`zip` approach][approach-zip]. ## Approach: Using sum @@ -78,18 +78,17 @@ def distance(strand_a, strand_b): index in range(len(strand_a))) ``` -For more information, check the [sum approach][approach-sum]. +For more information, check the [`sum` approach][approach-sum]. [approach-range]: https://exercism.org/tracks/python/exercises/hamming/approaches/range [approach-sum]: https://exercism.org/tracks/python/exercises/hamming/approaches/sum [approach-zip]: https://exercism.org/tracks/python/exercises/hamming/approaches/zip -[built-in-functions]: https://docs.python.org/3.10/library/functions.html -[enumerate]: https://docs.python.org/3.10/library/functions.html#enumerate +[built-in-functions]: https://docs.python.org/3.10/library/functions.html +[enumerate]: https://docs.python.org/3.10/library/functions.html#enumerate [filter]: https://docs.python.org/3.10/library/functions.html#filter -[generator-expression]: https://docs.python.org/3/reference/expressions.html#grammar-token-python-grammar-generator_expression +[generator-expression]: https://peps.python.org/pep-0289/ [iterators]: https://docs.python.org/3/glossary.html#term-iterator [lambda]: https://docs.python.org/3/glossary.html#term-lambda -[range]: https://docs.python.org/3.10/library/functions.html#func-range +[range]: https://docs.python.org/3.10/library/functions.html#func-range [sum]: https://docs.python.org/3/library/functions.html#sum [zip]: https://docs.python.org/3.10/library/functions.html#zip - diff --git a/exercises/practice/luhn/.approaches/introduction.md b/exercises/practice/luhn/.approaches/introduction.md index 2eff18ae075..ba9657277c8 100644 --- a/exercises/practice/luhn/.approaches/introduction.md +++ b/exercises/practice/luhn/.approaches/introduction.md @@ -93,7 +93,7 @@ The `replace()`, reverse, `enumerate()` approach benchmarked the fastest. To compare performance of the approaches, check the [Performance article][article-performance]. -[approach-reversed-for]: https://exercism.org/tracks/python/exercises/luhn/approaches/reversed-for +[approach-reversed-for]: https://exercism.org/tracks/python/exercises/luhn/approaches/reversed-for [approach-replace-reverse-enumerate]: https://exercism.org/tracks/python/exercises/luhn/approaches/replace-reverse-enumerate [approach-recursion]: https://exercism.org/tracks/python/exercises/luhn/approaches/recursion [article-performance]: https://exercism.org/tracks/python/exercises/luhn/articles/performance diff --git a/exercises/practice/luhn/.articles/performance/content.md b/exercises/practice/luhn/.articles/performance/content.md index 5069a2e53db..33637b89b0d 100644 --- a/exercises/practice/luhn/.articles/performance/content.md +++ b/exercises/practice/luhn/.articles/performance/content.md @@ -24,7 +24,7 @@ The `reversed()` with a `for` loop approach was a bit slower, at `10783` nanosec The recursive approach was much slower, at about `24321` nanoseconds. [approaches]: https://exercism.org/tracks/python/exercises/luhn/approaches -[approach-reversed-for]: https://exercism.org/tracks/python/exercises/luhn/approaches/reversed-for +[approach-reversed-for]: https://exercism.org/tracks/python/exercises/luhn/approaches/reversed-for [approach-replace-reverse-enumerate]: https://exercism.org/tracks/python/exercises/luhn/approaches/replace-reverse-enumerate [approach-recursion]: https://exercism.org/tracks/python/exercises/luhn/approaches/recursion [benchmark-application]: https://github.com/exercism/python/blob/main/exercises/practice/luhn/.articles/performance/code/Benchmark.py diff --git a/exercises/practice/nth-prime/.approaches/generator-fun/content.md b/exercises/practice/nth-prime/.approaches/generator-fun/content.md index b7fc867ab77..958c100479d 100644 --- a/exercises/practice/nth-prime/.approaches/generator-fun/content.md +++ b/exercises/practice/nth-prime/.approaches/generator-fun/content.md @@ -1,7 +1,9 @@ # Generator Fun + The key of this approach is to not store the elements you do not need. This is a code representation: + ```python from itertools import islice, count @@ -13,10 +15,10 @@ def prime(number): return next(gen) ``` -Let's dissect it! `itertools.count` is like `range` without un upper bound - calling it returns a generator, and `for ... in count_obj` will result in an infinite loop. +Let's dissect it! `itertools.count` is like `range` without un upper bound — calling it returns a generator, and `for ... in count_obj` will result in an infinite loop. Using a lambda expression, we `filter` out any numbers above two that are prime. -Doesn't this result in an infinite loop? +Doesn't this result in an infinite loop? No - `filter` _also_ returns a generator object (which are [evaluated lazily][generator]), so while it's too will produce values infinitely if evaluated, it doesn't hang to program at the time of instantiation. `itertools.islice` takes in a generator object and an end count, returning a generator object which _only evaluates until that end count_. diff --git a/exercises/practice/nth-prime/.approaches/tracking/content.md b/exercises/practice/nth-prime/.approaches/tracking/content.md index 7e6398c92f7..959fa663e7b 100644 --- a/exercises/practice/nth-prime/.approaches/tracking/content.md +++ b/exercises/practice/nth-prime/.approaches/tracking/content.md @@ -47,6 +47,7 @@ def prime(number): ~~~~exercism/advanced Tip: you can use `for... else` to make your code more idiomatic here. + ```python ... for test in range(2, int(counter ** 0.5) + 1): @@ -57,9 +58,9 @@ else: if prime_count == number: return counter ``` -The else block is executed if the `for` loop completes normally - that is, without `break`ing. -Read more on [for/else][for-else] -~~~~ +The else block is executed if the `for` loop completes normally — that is, without `break`ing. +Read more on [`for`/`else`][for-else] -[for-else]: https://book.pythontips.com/en/latest/for_-_else.html \ No newline at end of file +[for-else]: https://book.pythontips.com/en/latest/for_-_else.html +~~~~ diff --git a/exercises/practice/pythagorean-triplet/.approaches/introduction.md b/exercises/practice/pythagorean-triplet/.approaches/introduction.md index 0a8cb171416..b6565819da6 100644 --- a/exercises/practice/pythagorean-triplet/.approaches/introduction.md +++ b/exercises/practice/pythagorean-triplet/.approaches/introduction.md @@ -184,7 +184,7 @@ This is likely due to the overhead of creating and tracking the iterator for the [approaches-linear]: https://exercism.org/tracks/python/exercises/pythagorean-triplet/approaches/linear [approaches-quadratic]: https://exercism.org/tracks/python/exercises/pythagorean-triplet/approaches/quadratic [article-performance]:https://exercism.org/tracks/python/exercises/pythagorean-triplet/articles/performance -[asymptotic-notation]: https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/asymptotic-notation +[asymptotic-notation]: https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/asymptotic-notation [numba]: https://numba.pydata.org/ [numpy]: https://numpy.org/ [time-complexity]: https://yourbasic.org/algorithms/time-complexity-explained/ diff --git a/exercises/practice/raindrops/.approaches/functools-reduce/content.md b/exercises/practice/raindrops/.approaches/functools-reduce/content.md index 36dd2222fd7..99673eba9e9 100644 --- a/exercises/practice/raindrops/.approaches/functools-reduce/content.md +++ b/exercises/practice/raindrops/.approaches/functools-reduce/content.md @@ -36,5 +36,5 @@ def convert(number): [lambda]: https://dbader.org/blog/python-lambda-functions [functools-reduce]: https://docs.python.org/3/library/functools.html#functools.reduce -[approach-itertools-compress]: https://exercism.org/tracks/python/exercises/raindrops/approaches/itertools-compress +[approach-itertools-compress]: https://exercism.org/tracks/python/exercises/raindrops/approaches/itertools-compress [zip]: https://docs.python.org/3/library/functions.html#zip diff --git a/exercises/practice/raindrops/.approaches/if-statements/content.md b/exercises/practice/raindrops/.approaches/if-statements/content.md index 80fe84bd926..4ac61ef2988 100644 --- a/exercises/practice/raindrops/.approaches/if-statements/content.md +++ b/exercises/practice/raindrops/.approaches/if-statements/content.md @@ -12,7 +12,7 @@ def convert(num): ``` -This approach is the most straightforward or 'naive' - it replicates in code what the instructions say, using `if` statements to check the modulo for each factor. +This approach is the most straightforward or 'naive' — it replicates in code what the instructions say, using `if` statements to check the modulo for each factor. If the number is evenly divisible by the factor (modulo == 0), the corresponding string is concatenated to _sounds_ via the `+` operator. Sounds is returned if it is not empty (_see [Truth Value Testing][truth-value-testing] for more info_). Otherwise, a `str` version of the input number is returned. @@ -20,7 +20,7 @@ Otherwise, a `str` version of the input number is returned. This, of course incurs the 'penalty' of string concatenation. But since there are only three factors to check and the strings are small, the concatenation is at a minimum. -In fact, this solution - and most others described in the approaches here - are `O(1)` time complexity. +In fact, this solution — and most others described in the approaches here — are `O(1)` time complexity. There are a constant number of factors to iterate through, and the work that is done never increases, even as the input numbers get bigger. This holds true for space complexity as well. diff --git a/exercises/practice/raindrops/.approaches/introduction.md b/exercises/practice/raindrops/.approaches/introduction.md index 50e83d706ee..6dac621015c 100644 --- a/exercises/practice/raindrops/.approaches/introduction.md +++ b/exercises/practice/raindrops/.approaches/introduction.md @@ -54,7 +54,7 @@ def convert(num): return sounds if sounds else str(num) ``` -This approach is the most straightforward or 'naive' - it replicates in code what the instructions say, using `if` statements to check the modulus for each factor. +This approach is the most straightforward or 'naive' — it replicates in code what the instructions say, using `if` statements to check the modulus for each factor. Each is then concatenated to the 'sounds' string. If the 'sounds' string is empty, a string version of the number is returned instead. @@ -265,12 +265,12 @@ Since the number of factors is fixed here, this is unlikely to create issues unl To compare the performance of this and the other approaches, take a look at the [Performance article][article-performance]. [approach-dict-and-join ]: https://exercism.org/tracks/python/exercises/raindrops/approaches/dict-and-join -[approach-functools-reduce]: https://exercism.org/tracks/python/exercises/raindrops/approaches/functools-reduce -[approach-if-statements]: https://exercism.org/tracks/python/exercises/raindrops/approaches/if-statements -[approach-itertools-compress]: https://exercism.org/tracks/python/exercises/raindrops/approaches/itertools-compress +[approach-functools-reduce]: https://exercism.org/tracks/python/exercises/raindrops/approaches/functools-reduce +[approach-if-statements]: https://exercism.org/tracks/python/exercises/raindrops/approaches/if-statements +[approach-itertools-compress]: https://exercism.org/tracks/python/exercises/raindrops/approaches/itertools-compress [approach-loop-and-fstring]: https://exercism.org/tracks/python/exercises/raindrops/approaches/loop-and-fstring [approach-sequence-with-join]: https://exercism.org/tracks/python/exercises/raindrops/approaches/sequence-with-join -[approach-truthy-and-falsey-with-fstring]: https://exercism.org/tracks/python/exercises/raindrops/approaches/truthy-and-falsey-with-fstring +[approach-truthy-and-falsey-with-fstring]: https://exercism.org/tracks/python/exercises/raindrops/approaches/truthy-and-falsey-with-fstring [article-performance]: https://exercism.org/tracks/python/exercises/raindrops/articles/performance [divmod]: https://docs.python.org/3/library/functions.html#divmod [fmod]: https://docs.python.org/3/library/math.html#math.fmod diff --git a/exercises/practice/raindrops/.approaches/truthy-and-falsey-with-fstring/content.md b/exercises/practice/raindrops/.approaches/truthy-and-falsey-with-fstring/content.md index 816052c3b12..38b2b87c7eb 100644 --- a/exercises/practice/raindrops/.approaches/truthy-and-falsey-with-fstring/content.md +++ b/exercises/practice/raindrops/.approaches/truthy-and-falsey-with-fstring/content.md @@ -19,7 +19,7 @@ def convert(number): return f'{threes}{fives}{sevens}' or str(number) ``` -This is very similar to the [`if-statement`][approach-if-statements] approach logic, but uses [ternary expressions][ternary expression] to assign either an empty string or a drop sound to a variable. +This is very similar to the [`if-statement`][approach-if-statements] approach logic, but uses [ternary expressions][ternary-expression] to assign either an empty string or a drop sound to a variable. The variables are then used in an `f-string` to compose the result, avoiding the use of `join()`, or a `loop`. If the `f-string` is empty _(evaluating to False in a [boolean context][truth-value-testing]_), a `str` of the input number is returned instead. @@ -28,12 +28,12 @@ This has `O(1)` time and space complexity. These two variations both exploit the fact that boolean `True` and `False` are a subtype of `int` in Python. 0 evaluates to `False`, and 1 to `True`. So the expression `'Pling' if not number % 3 else ''` can be read as "return 'Pling" if number % 3 not False" where `False` is 0, and (not `False`) is 1. -The expression `'' if number % 3 else 'Pling'` is the inverse: "return '' if number % 3 is True" - where number % 3 > 0 is `True`, and number % 3 == 0 is `False`. +The expression `'' if number % 3 else 'Pling'` is the inverse: "return '' if number % 3 is True" — where number % 3 > 0 is `True`, and number % 3 == 0 is `False`. Like the `if-statement` approach, these solutions are nicely readable and to-the-point, but will grow in length and get harder to read if many more factors are added or business logic changes. The `f-string` in particular could get unwieldy beyond about 5 factors. Other solutions using data structures to hold factors and `join()` to assemble strings might be a better option in 'high change' situations. -[approach-if-statements]: https://exercism.org/tracks/python/exercises/raindrops/approaches/if-statements -[ternary expression]: https://docs.python.org/3/reference/expressions.html#conditional-expressions +[approach-if-statements]: https://exercism.org/tracks/python/exercises/raindrops/approaches/if-statements +[ternary-expression]: https://docs.python.org/3/reference/expressions.html#conditional-expressions [truth-value-testing]: https://docs.python.org/3/library/stdtypes.html#truth-value-testing diff --git a/exercises/practice/raindrops/.articles/performance/content.md b/exercises/practice/raindrops/.articles/performance/content.md index 82ade02c90f..d54cc00dfd7 100644 --- a/exercises/practice/raindrops/.articles/performance/content.md +++ b/exercises/practice/raindrops/.articles/performance/content.md @@ -47,9 +47,9 @@ The [`timeit`][timeit] module docs have more details, and [note.nkmk.me][note_nk [PEP0622]: https://peps.python.org/pep-0622/ [approach-dict-and-join ]: https://exercism.org/tracks/python/exercises/raindrops/approaches/dict-and-join -[approach-functools-reduce]: https://exercism.org/tracks/python/exercises/raindrops/approaches/functools-reduce -[approach-if-statements]: https://exercism.org/tracks/python/exercises/raindrops/approaches/if-statements -[approach-itertools-compress]: https://exercism.org/tracks/python/exercises/raindrops/approaches/itertools-compress +[approach-functools-reduce]: https://exercism.org/tracks/python/exercises/raindrops/approaches/functools-reduce +[approach-if-statements]: https://exercism.org/tracks/python/exercises/raindrops/approaches/if-statements +[approach-itertools-compress]: https://exercism.org/tracks/python/exercises/raindrops/approaches/itertools-compress [approach-loop-and-fstring]: https://exercism.org/tracks/python/exercises/raindrops/approaches/loop-and-fstring [approach-sequence-with-join]: https://exercism.org/tracks/python/exercises/raindrops/approaches/sequence-with-join [approach-truthy-and-falsey-with-fstring]: https://exercism.org/tracks/python/exercises/raindrops/approaches/truthy-and-falsey-with-fstring diff --git a/exercises/practice/robot-name/.approaches/mass-name-generation/content.md b/exercises/practice/robot-name/.approaches/mass-name-generation/content.md index a245195fa50..10c68e1971e 100644 --- a/exercises/practice/robot-name/.approaches/mass-name-generation/content.md +++ b/exercises/practice/robot-name/.approaches/mass-name-generation/content.md @@ -33,7 +33,7 @@ numbers = (str(i).zfill(3) for i in range(1000)) names = [l + n for l in letter_pairs for n in numbers] ``` -After the name generation, the names are shuffled - using the [default `seed`][random-seed] in the `random` module (the current timestamp). +After the name generation, the names are shuffled — using the [default `seed`][random-seed] in the `random` module (the current timestamp). When the tests reseed `random`, this has no effect as the names were shuffled before that. We then set `NAMES` to the iterable of names, and in `reset`, set the robot's name to the `next(name)`. @@ -41,7 +41,7 @@ If you are interested, you can read more on [`iter` and `next`][iter-and-next]. Unlike the [on the fly approach][approach-name-on-the-fly], this has a relatively short "generation" time, because we are merely giving the `next` name instead of generating it. However, this has a huge startup memory and time cost, as 676,000 strings have to be calculated and stored. -For an approximate calculation, 676,000 strings * 5 characters / string * 1 byte / character gives 3380000 bytes or 3.38 MB of RAM - and that's just the memory aspect of it. +For an approximate calculation, 676,000 strings * 5 characters / string * 1 byte / character gives 3380000 bytes or 3.38 MB of RAM — and that's just the memory aspect of it. Sounds small, but this might be a relatively significant startup cost. Thus, this approach is inefficient in cases where only a small number of names are needed _and_ the time to set/reset the robot isn't crucial. diff --git a/exercises/practice/robot-name/.approaches/name-on-the-fly/content.md b/exercises/practice/robot-name/.approaches/name-on-the-fly/content.md index 494b32b2d10..7122616172a 100644 --- a/exercises/practice/robot-name/.approaches/name-on-the-fly/content.md +++ b/exercises/practice/robot-name/.approaches/name-on-the-fly/content.md @@ -53,7 +53,7 @@ def reset(self): self.name = name ``` -We call `reset` from `__init__` - it is syntactically valid to do it the other way around, but it is not considered good practice to call [dunder methods][dunder-methods] directly. +We call `reset` from `__init__` — it is syntactically valid to do it the other way around, but it is not considered good practice to call [dunder methods][dunder-methods] directly. This has almost no startup time and memory, apart from declaring an empty `set`. Note that the _generation_ time is the same as the [mass generation approach][approach-mass-name-generation], as a similar method is used. diff --git a/exercises/practice/yacht/.approaches/functions/content.md b/exercises/practice/yacht/.approaches/functions/content.md index 2c6bfe527df..aab52734dec 100644 --- a/exercises/practice/yacht/.approaches/functions/content.md +++ b/exercises/practice/yacht/.approaches/functions/content.md @@ -1,4 +1,5 @@ -## Approach: Using Lambdas with Functions +# Approach: Using Lambdas with Functions + Each bit of functionality for each category can be encoded in an anonymous function (otherwise known as a [`lambda` expression][lambda] or lambda form), and the constant name set to that function. In `score`, we call the category (as it now points to a function) passing in `dice` as an argument. @@ -22,7 +23,7 @@ CHOICE = sum def score(dice, category): return category(dice) -``` +``` Instead of setting each constant in `ONES` through `SIXES` to a separate function, we create a function `digits` that returns a function, using [closures][closures] transparently. @@ -31,11 +32,12 @@ For `LITTLE_STRAIGHT` and `BIG_STRAIGHT`, we first sort the dice and then check Another way to solve this would be to check if `sum(dice) == 20 and len(set(dice)) == 5` (15 in `LITTLE_STRAIGHT`). In `CHOICE`, `lambda number : sum(number)` is shortened to just `sum`. -In `FULL_HOUSE`, we create a `set` to remove the duplicates and check the set's length along with the individual counts. -For `FOUR_OF_A_KIND`, we check if the first and the fourth element are the same or the second and the last element are the same - if so, there are (at least) four of the same number in the array. +In `FULL_HOUSE`, we create a `set` to remove the duplicates and check the set's length along with the individual counts. +For `FOUR_OF_A_KIND`, we check if the first and the fourth element are the same or the second and the last element are the same — if so, there are (at least) four of the same number in the array. -This solution is a succinct way to solve the exercise, although some of the one-liners can get a little long and hard to read. +This solution is a succinct way to solve the exercise, although some of the one-liners can get a little long and hard to read. Additionally, [PEP8][pep8] does not recommend assigning constant or variable names to `lambda` expressions, so it is a better practice to use `def`: + ```python def digits(num): return lambda dice: dice.count(num) * num @@ -59,6 +61,7 @@ def score(dice, category): As you can see from the examples, the [ternary operator][ternary-operator] (_or ternary form_) is crucial in solving the exercise using one liners. As functions are being used, it might be a better strategy to spread the code over multiple lines to improve readability. + ```python def YACHT(dice): if dice.count(dice[0]) == len(dice): @@ -68,5 +71,5 @@ def YACHT(dice): [closures]: https://www.programiz.com/python-programming/closure [ternary-operator]: https://www.tutorialspoint.com/ternary-operator-in-python -[lambda]: https://docs.python.org/3/howto/functional.html?highlight=lambda#small-functions-and-the-lambda-expression +[lambda]: https://docs.python.org/3/howto/functional.html?highlight=lambda#small-functions-and-the-lambda-expression [pep8]: https://peps.python.org/pep-0008/ \ No newline at end of file diff --git a/exercises/practice/yacht/.approaches/introduction.md b/exercises/practice/yacht/.approaches/introduction.md index 5a37d16881b..0c1de9715be 100644 --- a/exercises/practice/yacht/.approaches/introduction.md +++ b/exercises/practice/yacht/.approaches/introduction.md @@ -1,16 +1,20 @@ # Introduction + Yacht in Python can be solved in many ways. The most intuitive approach is to use an `if` structure. Alternatively, you can create functions and set their names to the constant names. ## General guidance -The main thing in this exercise is to map a category (_here defined as constants in the stub file_) to a function or a standalone piece of code. + +The main thing in this exercise is to map a category (_here defined as constants in the stub file_) to a function or a standalone piece of code. While mapping generally reminds us of dictionaries, here the constants are global. This indicates that the most idiomatic approach is not using a `dict`. -Adhering to the principles of DRY is important - don't repeat yourself if you can help it, especially in the `ONES` through `SIXES` categories! +Adhering to the principles of DRY is important — don't repeat yourself if you can help it, especially in the `ONES` through `SIXES` categories! ## Approach: functions + Each bit of functionality for each category can be encoded in a function, and the constant name set to that function. -This can be done by assigning the constant name to a `lambda` or creating a one-line function using the constant as a function name. +This can be done by assigning the constant name to a `lambda` or creating a one-line function using the constant as a function name. + ```python def digits(num): return lambda dice: dice.count(num) * num @@ -29,12 +33,15 @@ CHOICE = sum def score(dice, category): return category(dice) ``` + This is a very succinct way to solve the exercise, although some one-liners get a little long. For more information on this approach, read [this document][approach-functions]. ## Approach: if structure -The constants can be set to random, null, or numeric values, and an `if` structure inside `score` determines the code to be executed. + +The constants can be set to random, null, or numeric values, and an `if` structure inside `score` determines the code to be executed. As one-liners aren't necessary here, we can spread out the code to make it look neater: + ```python ONES = 1 TWOS = 2 @@ -70,6 +77,7 @@ def score(dice, category): return sum(dice) return 0 ``` + Read more on this approach [here][approach-if-structure]. [approach-functions]: https://exercism.org/tracks/python/exercises/yacht/approaches/functions diff --git a/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md b/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md index b49bb6340bd..3d557a78470 100644 --- a/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md +++ b/exercises/practice/yacht/.approaches/structural-pattern-matching/content.md @@ -1,11 +1,12 @@ # Structural Pattern Matching -Another very interesting approach is to use [structural pattern matching][structural pattern matching]. +Another very interesting approach is to use [structural pattern matching][structural pattern matching]. Existing in Python since 3.10, this feature allows for neater code than traditional if structures. - -By and large, we reuse the code from the [if structure approach][approach-if-structure]. -We set the constants to random values and check for them in the `match` structure. -`category` is the "subject", and in every other line, we check it against a "pattern". + +By and large, we reuse the code from the [if structure approach][approach-if-structure]. +We set the constants to random values and check for them in the `match` structure. +`category` is the "subject", and in every other line, we check it against a "pattern". + ```python ONES = 1 TWOS = 2 @@ -39,17 +40,18 @@ def score(dice, category): case _: return 0 ``` -For the first pattern, we utilize "or patterns", using the `|` operator. + +For the first pattern, we utilize "or patterns", using the `|` operator. This checks whether the subject is any of the provided patterns. -In the next five patterns, we check an additional condition along with the pattern matching. -Finally, we use the wildcard operator `_` to match anything. -As the compiler checks the patterns (`case`s) in order, `return 0` will be executed if none of the other patterns match. +In the next five patterns, we check an additional condition along with the pattern matching. +Finally, we use the wildcard operator `_` to match anything. +As the compiler checks the patterns (`case`s) in order, `return 0` will be executed if none of the other patterns match. -Note that the conditions might differ, but the patterns must have hard coded values - that is, you can't say `case ONES ...` instead of `case 1 ...`. -This will capture the category and lead to unexpected behavior. +Note that the conditions might differ, but the patterns must have hard coded values — that is, you can't say `case ONES ...` instead of `case 1 ...`. +This will capture the category and lead to unexpected behavior. This code is much clenaer than the corresponding `if` structure code. [structural pattern matching]: https://peps.python.org/pep-0636/ -[approach-if-structure]: https://exercism.org/tracks/python/exercises/yacht/approaches/if-structure \ No newline at end of file +[approach-if-structure]: https://exercism.org/tracks/python/exercises/yacht/approaches/if-structure