You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: exercises/practice/wordy/.approaches/dunder-getattribute/content.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,13 +37,17 @@ def answer(question):
37
37
This approach begins by defining a [dictionary][dictionaries] of the word keys with their related [`dunder-methods`][dunder] methods.
38
38
Since only whole numbers are involved, the available `dunder-methods` are those for the [`int`][int] class/namespace.
39
39
The supported methods for the `int()` namespace can be found by using `print(dir(int))` or `print(int.__dict__)` in a Python terminal.
40
-
See [SO: Difference between dir() and __dict__][dir-vs-__dict__] for differences between the two.
40
+
See [`SO: Difference between dir() and __dict__`][dir-vs-__dict__] for more details.
41
+
42
+
<br>
41
43
42
44
~~~~exercism/note
43
45
The built-in [`dir`](https://docs.python.org/3/library/functions.html?#dir) function returns a list of all valid attributes for an object.
44
46
The `dunder-method` [`<object>.__dict__`](https://docs.python.org/3/reference/datamodel.html#object.__dict__) is a mapping of an objects writable attributes.
45
47
~~~~
46
48
49
+
<br>
50
+
47
51
The `OPS` dictionary is defined with all uppercase letters, which is the naming convention for a Python [constant][const].
48
52
It indicates that the value should not be changed.
Copy file name to clipboardExpand all lines: exercises/practice/wordy/.approaches/introduction.md
+12-2Lines changed: 12 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,10 +22,12 @@ A whole class of error can be eliminated up front by checking if a question star
22
22
Any other question formulation becomes a `ValueError("unknown operation")`.
23
23
This could lead to future maintenance issues if the definition of a question ever changes or operations are added, but for the purposes of passing the current Wordy tests, it works well.
24
24
25
+
<br>
25
26
26
27
~~~~exercism/note
27
28
There are many Pythonic ways to go about the cleaning, parsing, and calculation steps of Wordy.
28
-
However, the solutions all follow these general steps:
29
+
However, solutions all follow the same general steps:
30
+
29
31
30
32
1. Remove the parts of the question string that do not apply to calculating the answer.
31
33
2. Iterate over the question, determining which words are numbers, and which are meant to be mathematical operations.
@@ -38,6 +40,7 @@ However, the solutions all follow these general steps:
38
40
6. Once the question is calculated down to a single number, that is the answer. Anything else that happens in the loop/iteration or within the accumulated result is a `ValueError("syntax error")`.
39
41
~~~~
40
42
43
+
<br>
41
44
42
45
For question cleaning, [`str.removeprefix`][removeprefix] and
43
46
[`str.removesuffix`][removesuffix] introduced in `Python 3.9` can be very useful:
@@ -95,6 +98,7 @@ Some solutions use either [lambda][lambdas] expressions, [dunder/"special" metho
95
98
However, the exercise can be solved without using `operator`, `lambdas`, `dunder-methods` or `eval`.
96
99
It is recommended that you first start by solving it _without_ "advanced" strategies, and then refine your solution into something more compact or complex as you learn and practice.
97
100
101
+
<br>
98
102
99
103
~~~~exercism/caution
100
104
Using [`eval`][eval] for the operations might seem convenient, but it is a [dangerous][eval-danger] and possibly [destructive][eval-destructive] approach.
@@ -158,6 +162,7 @@ Alternatives could use a [dictionary][dict] to store word --> operator mappings
158
162
159
163
For more details and variations, read the [String, List and Dictionary Methods][approach-string-list-and-dict-methods] approach.
160
164
165
+
<br>
161
166
162
167
## Approach: Import Callables from the Operator Module
163
168
@@ -199,6 +204,7 @@ Like the first approach, it uses a [try-except][handling-exceptions] block for h
199
204
200
205
For more details and options, take a look at the [Import Callables from the Operator Module][approach-import-callables-from-operator] approach.
201
206
207
+
<br>
202
208
203
209
## Approach: Regex and the Operator Module
204
210
@@ -257,6 +263,7 @@ It is longer than some solutions, but clearer and potentially easier to maintain
257
263
258
264
For more details, take a look at the [regex-with-operator-module][approach-regex-with-operator-module] approach.
259
265
266
+
<br>
260
267
261
268
## Approach: Lambdas in a Dictionary to return Functions
262
269
@@ -306,6 +313,7 @@ These "hand-crafted" `lambdas` could also introduce a mathematical error, althou
306
313
307
314
For more details, take a look at the [Lambdas in a Dictionary][approach-lambdas-in-a-dictionary] approach.
308
315
316
+
<br>
309
317
310
318
## Approach: Recursion
311
319
@@ -351,6 +359,7 @@ The dictionary in this example could use functions from `operator`, `lambdas`, `
351
359
352
360
For more details, take a look at the [recursion][approach-recursion] approach.
353
361
362
+
<br>
354
363
355
364
## Approach: functools.reduce()
356
365
@@ -393,6 +402,7 @@ This solution may be a little less clear to follow or reason about due to the sl
393
402
394
403
For more details and variations, take a look at the [functools.reduce for Calculation][approach-functools-reduce] approach.
395
404
405
+
<br>
396
406
397
407
## Approach: Dunder methods with `__getattribute__`
398
408
@@ -444,7 +454,7 @@ For more detail on this solution, take a look at the [dunder method with `__geta
Copy file name to clipboardExpand all lines: exercises/practice/wordy/.approaches/recursion/content.md
+20-7Lines changed: 20 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,14 +5,21 @@
5
5
A recursive strategy [may not always be obvious][looping-vs-recursion] or easy — but it is always possible.
6
6
So the `while-loop`s used in other approaches to Wordy can be re-written to use recursive calls.
7
7
8
+
<br>
9
+
8
10
That being said, Python famously does not perform [tail-call optimization][tail-call-optimization], and limits recursive calls on the stack to a depth of 1000 frames, so it is important to only use recursion where you are confident that it can complete within the limit (_or something close to it_).
9
11
[Memoization][memoization] and other strategies in [dynamic programming][dynamic-programming] can help to make recursion more efficient and "shorter" in Python, but it's always good to give it careful consideration.
10
12
13
+
<br>
14
+
11
15
Recursion works best with problem spaces that resemble trees, include [backtracking][backtracking], or become progressively smaller.
12
-
Some examples include financial processes like calculating [amortization][amortization] and [depreciation][depreciation], tracking [radiation reduction through nuclei decay][nuclei-decay], and algorithms like [biscetion search][bisection-search], [depth-firs search][dfs], and [merge sort][merge-sort].
16
+
Some examples include financial processes like calculating [amortization][amortization] and [depreciation][depreciation], tracking [radiation reduction through nuclei decay][nuclei-decay], and algorithms like [biscetion search][bisection-search], [depth-first search][dfs], and [merge sort][merge-sort].
17
+
18
+
<br>
13
19
14
-
Other algorithms such as [breadth-first search][bfs], [Dijkstra's algorithm][dijkstra], and the [Bellman-Ford Algorithm][bellman-ford] lend themselves better to iteration.
20
+
Other algorithms such as [breadth-first search][bfs], [Dijkstra's algorithm][dijkstra], and the [Bellman-Ford Algorithm][bellman-ford] lend themselves better to loops.
15
21
22
+
<br>
16
23
17
24
```python
18
25
from operator import add, mul, sub
@@ -68,13 +75,16 @@ This approach separates the solution into three functions:
68
75
2.`clean()`, which takes a question string and returns a `list` of parsed words and numbers to calculate from.
69
76
3.`calculate()`, which performs the calculations on the `list` recursively, until a single number (_the base case check_) is returned as the answer — or an error is thrown.
70
77
78
+
<br>
79
+
71
80
The cleaning logic is separate from the processing logic so that the cleaning steps aren't repeated over and over with each recursive `calculate()` call.
72
-
This separation also makes it easier to make changes in processing or calculating without creating conflict or confusion.
81
+
This separation also makes it easier to make changes without creating conflict or confusion.
73
82
74
-
Note that `calculate()` performs the same steps as the `while-loop` from [Import Callables from the Operator Module][approach-import-callables-from-operator] and others.
83
+
`calculate()` performs the same steps as the `while-loop` from [Import Callables from the Operator Module][approach-import-callables-from-operator] and others.
75
84
The difference being that the `while-loop` test for `len()` 1 now occurs as an `if` condition in the function (_the base case_), and the "looping" is now a call to `calculate()` in the `else` condition.
76
85
`calculate()` can also use many of the strategies detailed in other approaches, as long as they work with the recursion.
77
86
87
+
<br>
78
88
79
89
`clean()` can also use any of the strategies detailed in other approaches, two of which are below:
80
90
@@ -91,6 +101,7 @@ The difference being that the `while-loop` test for `len()` 1 now occurs as an `
91
101
question.strip("?").split())) #<-- The () in list() also invokes implicit concatenation.
92
102
```
93
103
104
+
<br>
94
105
95
106
## Variation 1: Use Regex for matching, cleaning, and calculating
96
107
@@ -184,6 +195,7 @@ Because each new iteration of the question needs to be validated, there is an `i
184
195
185
196
Note that the `for-loop` and VALIDATE use [`re.match`][re-match], but DIGITS validation uses [`re.fullmatch`][re-fullmatch].
186
197
198
+
<br>
187
199
188
200
## Variation 2: Use Regex, Recurse within the For-loop
189
201
@@ -229,13 +241,14 @@ This saves some space, but requires that the nested `tuples` be unpacked as the
229
241
Recursion is used a bit differently here from the previous variations — the calls are placed [within the `for-loop`][recursion-within-loops].
230
242
Because the regex are more generic, they will match a `digit-operation-digit` trio in a longer question, so the line `return operation(calculate(match['x']), calculate(match['y']))` is effectively splitting a question into parts that can then be worked on in their own stack frames.
231
243
244
+
232
245
For example:
233
246
234
247
1. "1 plus -10 multiplied by 13 divided by 2" would match on "1 plus -10" (_group x_) **multiplied by** "13 divided by 2" (_group y_).
235
-
2. This would then be re-arranged to `mul(calculate("1 plus -10"), calculate("13 divided by 2"))`
248
+
2. This is re-arranged to `mul(calculate("1 plus -10"), calculate("13 divided by 2"))`
236
249
3. At this point the loop would pause as the two recursive calls to `calculate()` spawn
237
-
4. The loops would run again — and so would the calls to `calculate()`, until there wasn't any match that caused a split of the question or an error.
238
-
5. One at a time, the numbers would then be returned, until the main `mul(calculate("1 plus -10"), calculate("13 divided by 2"))` could be solved, at which point the answer would be returned.
250
+
4. The loops then run again — and so would the calls to `calculate()`, until there wasn't any match that caused a split of the question or an error.
251
+
5. One at a time, the numbers would then be returned, until the main `mul(calculate("1 plus -10"), calculate("13 divided by 2"))` could be solved, at which point the answer is returned.
239
252
240
253
For a more visual picture, you can step through the code on [pythontutor.com][recursion-in-loop-pythontutor].
0 commit comments