diff --git a/exercises/practice/acronym/.approaches/config.json b/exercises/practice/acronym/.approaches/config.json
index b5bbca7a232..7959ea68868 100644
--- a/exercises/practice/acronym/.approaches/config.json
+++ b/exercises/practice/acronym/.approaches/config.json
@@ -1,6 +1,7 @@
{
"introduction": {
- "authors": ["bethanyg"]
+ "authors": ["bethanyg"],
+ "contributors": ["yrahcaz7"]
},
"approaches": [
{
@@ -51,6 +52,13 @@
"title": "Regex Sub",
"blurb": "Use re.sub() to clean the input string and create the acronym in one step.",
"authors": ["bethanyg"]
+ },
+ {
+ "uuid": "0ce3eaf7-da79-403d-a481-5dd8f476d286",
+ "slug": "double-generator-expression",
+ "title": "Double Generator Expression",
+ "blurb": "Use generator expressions for both cleaning and joining the input.",
+ "authors": ["yrahcaz7"]
}
]
}
diff --git a/exercises/practice/acronym/.approaches/double-generator-expression/content.md b/exercises/practice/acronym/.approaches/double-generator-expression/content.md
new file mode 100644
index 00000000000..168d1354714
--- /dev/null
+++ b/exercises/practice/acronym/.approaches/double-generator-expression/content.md
@@ -0,0 +1,38 @@
+# Using a `generator-expression` for both cleaning and joining
+
+```python
+from string import ascii_letters
+
+
+VALID_CHARS = {' ', '-'} | set(ascii_letters)
+
+
+def abbreviate(to_abbreviate):
+ to_abbreviate = ''.join(' ' if char == '-' else char
+ for char in to_abbreviate
+ if char in VALID_CHARS)
+
+ return ''.join(word[0] for word in to_abbreviate.split()).upper()
+```
+
+One way someone might try to increase performce is to use a single [generator expression][generator-expression] to clean the input, rather than using multiple calls to [`str.replace()`][str-replace].
+However, this approach is actually amongst the slower ones.
+(See the [performance article][article-performance] for more detail.)
+
+In this approach, the `VALID_CHARS` constant is first defined using `string.ascii_letters`, a space, and a hyphen.
+In `abbreviate()`, the first generator expression iterates over `to_abbreviate`, excluding any code points that are not a member of the `VALID_CHARS` set.
+For each code point that is not excluded, the expression passes it into [`str.join()`][str-join] (unless it is a hyphen, in which case it replaces the hyphen with a space).
+`to_abbreviate` is then set to the result of the `str.join()`, preparing it for the next step.
+
+Next, [`to_abbreviate.split()`][str-split] is used to split `to_abbreviate` into words separated by whitespace — we can ignore the case of hyphens as we already replaced all of them with spaces.
+Now the second generator expression iterates over the list returned by `to_abbreviate.split()`, yeilding the first code point in each word.
+These code points are passed to another `str.join()`, which is then [chained][chaining] to [`str.upper()`][str-upper].
+Now that both steps are complete, we return the result of `str.upper()` directly on the same line.
+
+[article-performance]: https://exercism.org/tracks/python/exercises/acronym/articles/performance
+[chaining]: https://pyneng.readthedocs.io/en/latest/book/04_data_structures/method_chaining.html
+[generator-expression]: https://dbader.org/blog/python-generator-expressions
+[str-join]: https://docs.python.org/3/library/stdtypes.html#str.join
+[str-replace]: https://docs.python.org/3/library/stdtypes.html#str.replace
+[str-split]: https://docs.python.org/3/library/stdtypes.html#str.split
+[str-upper]: https://docs.python.org/3/library/stdtypes.html#str.upper
diff --git a/exercises/practice/acronym/.approaches/double-generator-expression/snippet.txt b/exercises/practice/acronym/.approaches/double-generator-expression/snippet.txt
new file mode 100644
index 00000000000..5a56cfb20b3
--- /dev/null
+++ b/exercises/practice/acronym/.approaches/double-generator-expression/snippet.txt
@@ -0,0 +1,8 @@
+VALID_CHARS = {' ', '-'} | set(ascii_letters)
+
+def abbreviate(to_abbreviate):
+ to_abbreviate = ''.join(' ' if char == '-' else char
+ for char in to_abbreviate
+ if char in VALID_CHARS)
+
+ return ''.join(word[0] for word in to_abbreviate.split()).upper()
\ No newline at end of file
diff --git a/exercises/practice/acronym/.approaches/introduction.md b/exercises/practice/acronym/.approaches/introduction.md
index 9aaac23d6fa..52a72ff6cbf 100644
--- a/exercises/practice/acronym/.approaches/introduction.md
+++ b/exercises/practice/acronym/.approaches/introduction.md
@@ -6,13 +6,12 @@ Among them are:
- Using `str.replace()` to scrub the input, and:
- joining with a `for loop` with string concatenation via the `+` operator.
- joining via `str.join()`, passing a `list-comprehension` or `generator-expression`.
- - joining via `str.join()`, passing `map()`.
+ - joining via `str.join()`, passing `map()`.
- joining via `functools.reduce()`.
- Using `re.findall()`/`re.finditer()` to scrub the input, and:
- joining via `str.join()`, passing a `generator-expression`.
-
- - Using `re.sub()` for both cleaning and joining (_using "only" regex for almost everything_)`
+ - Using `re.sub()` for both cleaning and joining (_using "only" regex for almost everything_)`
## General Guidance
@@ -51,7 +50,7 @@ def abbreviate(to_abbreviate):
For more information, take a look at the [loop approach][approach-loop].
-## Approach: scrub with `replace()` and join via `list comprehension` or `Generator expression`
+## Approach: scrub with `replace()` and join via `list comprehension` or `generator expression`
```python
@@ -59,17 +58,17 @@ def abbreviate(to_abbreviate):
phrase = to_abbreviate.replace('-', ' ').replace('_', ' ').upper().split()
return ''.join([word[0] for word in phrase])
-
-###OR###
-
+
+###OR###
+
def abbreviate(to_abbreviate):
phrase = to_abbreviate.replace('-', ' ').replace('_', ' ').upper().split()
- # note the parenthesis instead of square brackets.
+ # Note the parenthesis instead of square brackets.
return ''.join((word[0] for word in phrase))
```
-For more information, check out the [list-comprehension][approach-list-comprehension] approach or the [generator-expression][approach-generator-expression] approach.
+For more information, check out the [list-comprehension][approach-list-comprehension] approach or the [generator-expression][approach-generator-expression] approach.
## Approach: scrub with `replace()` and join via `map()`
@@ -96,7 +95,7 @@ def abbreviate(to_abbreviate):
return reduce(lambda start, word: start + word[0], phrase, "")
```
-For more information, take a look at the [functools.reduce()][approach-functools-reduce] approach.
+For more information, take a look at the [`functools.reduce()`][approach-functools-reduce] approach.
## Approach: filter with `re.findall()` and join via `str.join()`
@@ -105,8 +104,8 @@ For more information, take a look at the [functools.reduce()][approach-functools
import re
-def abbreviate(phrase):
- removed = re.findall(r"[a-zA-Z']+", phrase)
+def abbreviate(to_abbreviate):
+ removed = re.findall(r"[a-zA-Z']+", to_abbreviate)
return ''.join(word[0] for word in removed).upper()
```
@@ -120,36 +119,57 @@ For more information, take a look at the [regex-join][approach-regex-join] appro
import re
-def abbreviate_regex_sub(to_abbreviate):
+def abbreviate(to_abbreviate):
pattern = re.compile(r"(?>>** | **13** | **14** | **19** | **20** | **25** | **30** | **35** | **39** | **42** | **45** | **60** | **63** | **74** | **150** | **210** | **360** | **400** | **2940** |
-|------------------------------ |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:-----------: |:------------: |:------------: |:------------: |:------------: |:-------------: |
-| **loop** | 5.79e-07 | 4.96e-07 | 6.98e-07 | 7.41e-07 | 6.18e-07 | 7.25e-07 | 1.03e-06 | 7.33e-07 | 1.16e-06 | 8.71e-07 | 1.51e-06 | 1.65e-06 | 1.83e-06 | 2.43e-06 | 4.63e-06 | 7.76e-06 | 4.85e-06 | 5.94e-05 |
-| **list comprehension** | 7.28e-07 | 6.57e-07 | 8.26e-07 | 8.62e-07 | 7.67e-07 | 8.30e-07 | 1.08e-06 | 8.68e-07 | 1.24e-06 | 4.00e-07 | 1.49e-06 | 1.55e-06 | 1.76e-06 | 2.19e-06 | 4.08e-06 | 7.21e-06 | 4.40e-06 | 5.42e-05 |
-| **functools.reduce()** | 7.93e-07 | 6.65e-07 | 9.50e-07 | 2.43e-06 | 8.19e-07 | 9.56e-07 | 1.36e-06 | 4.12e-07 | 1.64e-06 | 1.21e-06 | 2.03e-06 | 2.14e-06 | 2.45e-06 | 3.15e-06 | 6.03e-06 | 1.03e-05 | 6.19e-06 | 8.10e-05 |
-| **map()** | 8.05e-07 | 7.21e-07 | 9.34e-07 | 9.46e-07 | 8.32e-07 | 9.16e-07 | 1.23e-06 | 9.52e-07 | 1.44e-06 | 1.14e-06 | 1.71e-06 | 1.80e-06 | 2.00e-06 | 2.58e-06 | 4.81e-06 | 8.02e-06 | 4.95e-06 | 5.64e-05 |
-| **generator expression** | 8.85e-07 | 7.90e-07 | 1.01e-06 | 1.01e-06 | 9.26e-07 | 2.49e-06 | 1.30e-06 | 1.06e-06 | 1.49e-06 | 1.19e-06 | 1.81e-06 | 1.86e-06 | 2.10e-06 | 2.67e-06 | 5.12e-06 | 8.61e-06 | 5.12e-06 | 5.81e-05 |
-| **re.finditer()** | 1.05e-06 | 1.74e-06 | 2.44e-06 | 2.40e-06 | 2.09e-06 | 2.45e-06 | 3.28e-06 | 2.42e-06 | 8.15e-06 | 3.12e-06 | 5.15e-06 | 5.18e-06 | 5.94e-06 | 7.89e-06 | 1.46e-05 | 2.35e-05 | 1.48e-05 | 1.68e-04 |
-| **regex with str.join()** | 1.62e-06 | 1.42e-06 | 1.85e-06 | 1.91e-06 | 1.66e-06 | 1.88e-06 | 2.61e-06 | 4.41e-06 | 3.14e-06 | 2.47e-06 | 3.92e-06 | 4.11e-06 | 4.61e-06 | 6.24e-06 | 1.13e-05 | 1.86e-05 | 1.19e-05 | 1.36e-04 |
-| **re.findall() 1st letters** | 1.63e-06 | 1.57e-06 | 2.04e-06 | 2.12e-06 | 2.16e-06 | 2.50e-06 | 3.18e-06 | 2.90e-06 | 3.73e-06 | 3.41e-06 | 4.84e-06 | 5.22e-06 | 5.94e-06 | 1.00e-05 | 1.54e-05 | 2.48e-05 | 2.28e-05 | 1.95e-04 |
-| **re.sub()** | 2.35e-06 | 1.10e-06 | 3.06e-06 | 2.94e-06 | 2.51e-06 | 2.92e-06 | 4.10e-06 | 2.91e-06 | 4.95e-06 | 3.80e-06 | 6.48e-06 | 6.39e-06 | 6.90e-06 | 9.29e-06 | 1.90e-05 | 2.98e-05 | 1.83e-05 | 2.03e-04 |
+| **String Length >>>** | Length: 13 | Length: 14 | Length: 19 | Length: 20 | Length: 25 | Length: 30 | Length: 35 | Length: 39 | Length: 42 | Length: 45 | Length: 60 | Length: 63 | Length: 74 | Length: 78 | Length: 93 | Length: 108 | Length: 120 | Length: 140 | Length: 150 | Length: 200 | Length: 210 | Length: 225 | Length: 260 | Length: 310 | Length: 360 | Length: 400 | Length: 2940 |
+|:-----------------------------------------|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|-------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|---------------:|
+| loop with str.replace | 2.78e-07 | 2.46e-07 | 3.23e-07 | 3.42e-07 | 2.88e-07 | 3.32e-07 | 4.69e-07 | 3.58e-07 | 5.53e-07 | 4.29e-07 | 7.27e-07 | 7.70e-07 | 8.26e-07 | 5.97e-07 | 7.18e-07 | 1.10e-06 | 7.72e-07 | 1.57e-06 | 1.08e-06 | 2.07e-06 | 2.18e-06 | 2.20e-06 | 1.60e-06 | 2.11e-06 | 3.56e-06 | 2.20e-06 | 2.51e-05 |
+| list comprehension with str.join() | 2.92e-07 | 2.67e-07 | 3.24e-07 | 3.47e-07 | 2.99e-07 | 3.29e-07 | 4.59e-07 | 3.57e-07 | 5.28e-07 | 4.31e-07 | 6.35e-07 | 6.65e-07 | 7.50e-07 | 5.58e-07 | 6.62e-07 | 9.84e-07 | 7.28e-07 | 1.34e-06 | 1.06e-06 | 1.76e-06 | 1.85e-06 | 1.96e-06 | 1.44e-06 | 1.85e-06 | 2.97e-06 | 1.99e-06 | 1.95e-05 |
+| map() with str.replace() | 4.18e-07 | 3.75e-07 | 4.74e-07 | 4.90e-07 | 4.30e-07 | 4.88e-07 | 6.54e-07 | 5.03e-07 | 7.57e-07 | 5.89e-07 | 9.02e-07 | 9.45e-07 | 1.08e-06 | 7.59e-07 | 9.44e-07 | 1.46e-06 | 1.00e-06 | 1.97e-06 | 1.45e-06 | 2.60e-06 | 2.65e-06 | 2.87e-06 | 2.10e-06 | 2.66e-06 | 4.52e-06 | 2.83e-06 | 2.95e-05 |
+| functools.reduce() with str.replace() | 4.35e-07 | 3.63e-07 | 5.07e-07 | 5.28e-07 | 4.41e-07 | 5.17e-07 | 7.63e-07 | 5.42e-07 | 9.34e-07 | 6.90e-07 | 1.14e-06 | 1.18e-06 | 1.40e-06 | 9.33e-07 | 1.18e-06 | 1.95e-06 | 1.23e-06 | 2.66e-06 | 1.85e-06 | 3.49e-06 | 3.56e-06 | 3.95e-06 | 2.72e-06 | 3.58e-06 | 6.15e-06 | 3.74e-06 | 4.30e-05 |
+| generator expression with str.join() | 4.20e-07 | 3.76e-07 | 4.64e-07 | 4.94e-07 | 4.28e-07 | 4.80e-07 | 6.30e-07 | 5.01e-07 | 7.15e-07 | 5.78e-07 | 8.68e-07 | 9.00e-07 | 4.03e-07 | 7.28e-07 | 8.80e-07 | 1.34e-06 | 9.30e-07 | 1.77e-06 | 1.28e-06 | 2.31e-06 | 2.40e-06 | 2.55e-06 | 1.86e-06 | 2.39e-06 | 3.94e-06 | 2.53e-06 | 2.58e-05 |
+| regex to clean with str.join() | 9.28e-07 | 8.42e-07 | 1.06e-06 | 1.08e-06 | 9.72e-07 | 1.09e-06 | 1.42e-06 | 1.09e-06 | 1.68e-06 | 1.37e-06 | 2.07e-06 | 2.10e-06 | 2.29e-06 | 1.72e-06 | 2.11e-06 | 3.12e-06 | 2.13e-06 | 4.06e-06 | 3.05e-06 | 5.24e-06 | 5.37e-06 | 5.76e-06 | 4.19e-06 | 5.50e-06 | 8.69e-06 | 5.64e-06 | 5.67e-05 |
+| re.finditer() with str.join() | 1.12e-06 | 9.80e-07 | 1.28e-06 | 1.30e-06 | 1.14e-06 | 1.29e-06 | 1.72e-06 | 1.29e-06 | 2.09e-06 | 1.67e-06 | 2.53e-06 | 2.64e-06 | 2.92e-06 | 2.12e-06 | 2.59e-06 | 3.89e-06 | 2.61e-06 | 5.08e-06 | 3.69e-06 | 6.80e-06 | 6.93e-06 | 7.34e-06 | 5.19e-06 | 6.76e-06 | 1.09e-05 | 6.81e-06 | 7.67e-05 |
+| re.sub() to clean and join | 1.04e-06 | 8.86e-07 | 1.32e-06 | 1.30e-06 | 1.09e-06 | 1.29e-06 | 1.87e-06 | 1.36e-06 | 2.28e-06 | 1.78e-06 | 3.04e-06 | 3.01e-06 | 3.31e-06 | 2.41e-06 | 3.00e-06 | 4.73e-06 | 3.12e-06 | 6.22e-06 | 4.56e-06 | 9.04e-06 | 9.03e-06 | 9.30e-06 | 6.70e-06 | 8.86e-06 | 1.45e-05 | 9.24e-06 | 9.89e-05 |
+| re.findall() 1st letters with str.join() | 1.09e-06 | 1.09e-06 | 1.33e-06 | 1.40e-06 | 1.43e-06 | 1.61e-06 | 1.93e-06 | 1.88e-06 | 2.22e-06 | 2.22e-06 | 2.90e-06 | 3.12e-06 | 3.42e-06 | 3.30e-06 | 3.87e-06 | 4.75e-06 | 4.67e-06 | 6.00e-06 | 6.02e-06 | 8.31e-06 | 9.05e-06 | 9.29e-06 | 9.61e-06 | 1.15e-05 | 1.45e-05 | 1.42e-05 | 1.11e-04 |
+| two generator expressions | 1.14e-06 | 1.12e-06 | 1.47e-06 | 1.49e-06 | 1.79e-06 | 2.09e-06 | 2.48e-06 | 2.54e-06 | 2.90e-06 | 2.85e-06 | 3.87e-06 | 3.92e-06 | 4.79e-06 | 4.88e-06 | 5.81e-06 | 6.92e-06 | 7.14e-06 | 8.99e-06 | 8.80e-06 | 1.24e-05 | 1.26e-05 | 1.41e-05 | 1.53e-05 | 1.83e-05 | 2.21e-05 | 2.25e-05 | 1.65e-04 |
-Keep in mind that all these approaches are very fast, and that benchmarking at this granularity can be unstable.
+Keep in mind that all these approaches are very fast, and that [benchmarking at this granularity can be unstable, especially on modern CPUs][timeit-issue]. Note that there can also be [bias in benchmarking][biased-benchmarks].
-Measurements were taken on a 3.1 GHz Quad-Core Intel Core i7 Mac running MacOS Ventura.
+Measurements were taken on an M3 Mac running MacOS Sonoma.
Tests used `timeit.Timer.autorange()`, repeated 3 times.
Time is reported in seconds taken per string after calculating the 'best of' time.
The [timeit module][timeit] docs have more details, and [note.nkmk.me][note_nkmk_me] has a nice summary of methods.
[approaches]: https://exercism.org/tracks/python/exercises/acronym/dig_deeper
+[approach-double-generator-expression]: https://exercism.org/tracks/python/exercises/acronym/approaches/double-generator-expression
[approach-functools-reduce]: https://exercism.org/tracks/python/exercises/acronym/approaches/functools-reduce
[approach-generator-expression]: https://exercism.org/tracks/python/exercises/acronym/approaches/generator-expression
[approach-list-comprehension]: https://exercism.org/tracks/python/exercises/acronym/approaches/list-comprehension
@@ -68,7 +69,9 @@ The [timeit module][timeit] docs have more details, and [note.nkmk.me][note_nkmk
[approach-regex-join]: https://exercism.org/tracks/python/exercises/acronym/approaches/regex-join
[approach-regex-sub]: https://exercism.org/tracks/python/exercises/acronym/approaches/regex-sub
[benchmark-application]: https://github.com/exercism/python/tree/main/exercises/practice/acronym/.articles/performance/code/Benchmark.py
+[biased-benchmarks]: https://matthewrocklin.com/blog/work/2017/03/09/biased-benchmarks
[note_nkmk_me]: https://note.nkmk.me/en/python-timeit-measure/
[numpy]: https://numpy.org/
[pandas]: https://pandas.pydata.org/docs/index.html
[timeit]: https://docs.python.org/3.11/library/timeit.html
+[timeit-issue]: https://github.com/python/cpython/issues/89424
diff --git a/exercises/practice/wordy/.approaches/config.json b/exercises/practice/wordy/.approaches/config.json
index 670284d4715..e9ed3c471e9 100644
--- a/exercises/practice/wordy/.approaches/config.json
+++ b/exercises/practice/wordy/.approaches/config.json
@@ -1,57 +1,71 @@
{
"introduction": {
"authors": ["BethanyG"],
- "contributors": ["bobahop"]
+ "contributors": ["bobahop", "yrahcaz7"]
},
"approaches": [
{
"uuid": "4eeb0638-671a-4289-a83c-583b616dc698",
"slug": "string-list-and-dict-methods",
"title": "String, List, and Dictionary Methods",
- "blurb": "Use Core Python Features to Solve Word Problems.",
- "authors": ["BethanyG"]
+ "blurb": "Use core Python features to solve word problems.",
+ "authors": ["BethanyG"],
+ "contributors": ["yrahcaz7"]
},
- {
- "uuid": "d3ff485a-defe-42d9-b9c6-c38019221ffa",
+ {
+ "uuid": "d3ff485a-defe-42d9-b9c6-c38019221ffa",
"slug": "import-callables-from-operator",
- "title": "Import Callables from the Operator Module",
- "blurb": "Use Operator Module Methods to Solve Word Problems.",
- "authors": ["BethanyG"]
- },
- {
- "uuid": "61f44943-8a12-471b-ab15-d0d10fa4f72f",
+ "title": "Import callables from the operator module",
+ "blurb": "Use operator module methods to solve word problems.",
+ "authors": ["BethanyG"],
+ "contributors": ["yrahcaz7"]
+ },
+ {
+ "uuid": "61f44943-8a12-471b-ab15-d0d10fa4f72f",
"slug": "regex-with-operator-module",
"title": "Regex with the Operator Module",
- "blurb": "Use Regex with the Callables from Operator to solve word problems.",
- "authors": ["BethanyG"]
- },
- {
- "uuid": "46bd15dd-cae4-4eb3-ac63-a8b631a508d1",
+ "blurb": "Use regex with the callables from the operator module to solve word problems.",
+ "authors": ["BethanyG"],
+ "contributors": ["yrahcaz7"]
+ },
+ {
+ "uuid": "46bd15dd-cae4-4eb3-ac63-a8b631a508d1",
"slug": "lambdas-in-a-dictionary",
"title": "Lambdas in a Dictionary to Return Functions",
"blurb": "Use lambdas in a dictionary to return functions for solving word problems.",
- "authors": ["BethanyG"]
- },
- {
- "uuid": "2e643b88-9b76-45a1-98f4-b211919af061",
+ "authors": ["BethanyG"],
+ "contributors": ["yrahcaz7"]
+ },
+ {
+ "uuid": "2e643b88-9b76-45a1-98f4-b211919af061",
"slug": "recursion",
- "title": "Recursion for Iteration.",
+ "title": "Recursion for Iteration",
"blurb": "Use recursion with other strategies to solve word problems.",
- "authors": ["BethanyG"]
- },
- {
- "uuid": "1e136304-959c-4ad1-bc4a-450d13e5f668",
+ "authors": ["BethanyG"],
+ "contributors": ["yrahcaz7"]
+ },
+ {
+ "uuid": "1e136304-959c-4ad1-bc4a-450d13e5f668",
"slug": "functools-reduce",
- "title": "Functools.reduce for Calculation",
+ "title": "functools.reduce for Calculation",
"blurb": "Use functools.reduce with other strategies to calculate solutions.",
- "authors": ["BethanyG"]
- },
- {
+ "authors": ["BethanyG"],
+ "contributors": ["yrahcaz7"]
+ },
+ {
"uuid": "d643e2b4-daee-422d-b8d3-2cad2f439db5",
"slug": "dunder-getattribute",
- "title": "dunder with __getattribute__",
- "blurb": "Use dunder methods with __getattribute__.",
- "authors": ["bobahop"]
+ "title": "Dunder with __getattribute__",
+ "blurb": "Use dunder methods with __getattribute__ to calculate solutions.",
+ "authors": ["bobahop"],
+ "contributors": ["yrahcaz7"]
+ },
+ {
+ "uuid": "924aa814-0b03-40c1-9ee4-90b7fcdc1ff8",
+ "slug": "tuple-and-index",
+ "title": "Tuples with sequence.index",
+ "blurb": "Use tuples with the sequence.index method to calculate solutions.",
+ "authors": ["yrahcaz7"]
}
]
}
diff --git a/exercises/practice/wordy/.approaches/dunder-getattribute/content.md b/exercises/practice/wordy/.approaches/dunder-getattribute/content.md
index 167460f2d3c..26652cc693f 100644
--- a/exercises/practice/wordy/.approaches/dunder-getattribute/content.md
+++ b/exercises/practice/wordy/.approaches/dunder-getattribute/content.md
@@ -1,6 +1,5 @@
# Dunder methods with `__getattribute__`
-
```python
OPS = {
"plus": "__add__",
@@ -12,11 +11,12 @@ OPS = {
def answer(question):
question = question.removeprefix("What is").removesuffix("?").strip()
- if not question: raise ValueError("syntax error")
+ if not question:
+ raise ValueError("syntax error")
if question.startswith("-") and question[1:].isdigit():
return -int(question[1:])
- elif question.isdigit():
+ if question.isdigit():
return int(question)
found_op = False
@@ -24,30 +24,31 @@ def answer(question):
if name in question:
question = question.replace(name, op)
found_op = True
- if not found_op: raise ValueError("unknown operation")
+ if not found_op:
+ raise ValueError("unknown operation")
ret = question.split()
while len(ret) > 1:
try:
x, op, y, *tail = ret
- if op not in OPS.values(): raise ValueError("syntax error")
+ if op not in OPS.values():
+ raise ValueError("syntax error")
ret = [int(x).__getattribute__(op)(int(y)), *tail]
except:
raise ValueError("syntax error")
return ret[0]
-
```
-This approach begins by defining a [dictionary][dictionaries] of the word keys with their related [`dunder-methods`][dunder] methods.
-Since only whole numbers are involved, the available `dunder-methods` are those for the [`int`][int] class/namespace.
+This approach begins by defining a [dictionary][dictionaries] of the word keys with their related [dunder method][dunder] values.
+Since only whole numbers are involved, the available dunder methods are those for the [`int`][int] class/namespace.
The supported methods for the `int()` namespace can be found by using `print(dir(int))` or `print(int.__dict__)` in a Python terminal.
-See [`SO: Difference between dir() and __dict__`][dir-vs-__dict__] for more details.
+See [this StackOverflow post][dir-vs-__dict__] for more details.
~~~~exercism/note
The built-in [`dir`](https://docs.python.org/3/library/functions.html?#dir) function returns a list of all valid attributes for an object.
-The `dunder-method` [`