diff --git a/concepts/basics/about.md b/concepts/basics/about.md index 30ea083022..6a6fca716b 100644 --- a/concepts/basics/about.md +++ b/concepts/basics/about.md @@ -6,7 +6,8 @@ Imperative, declarative (e.g., functional), and object-oriented programming _sty Python puts a strong emphasis on code readability and (_similar to Haskell_) uses [significant indentation][significant indentation] to denote function, method, and class definitions. -Python was created by Guido van Rossum and first released in 1991. The [Python Software Foundation][psf] manages and directs resources for Python and CPython development and receives proposals for changes to the language from [members][psf membership] of the community via [Python Enhancement Proposals or PEPs][peps]. +Python was created by Guido van Rossum and first released in 1991. +The [Python Software Foundation][psf] manages and directs resources for Python and CPython development and receives proposals for changes to the language from [members][psf membership] of the community via [Python Enhancement Proposals or PEPs][peps]. Complete documentation for the current release can be found at [docs.python.org][python docs]. @@ -18,8 +19,14 @@ Complete documentation for the current release can be found at [docs.python.org] - [Python FAQs][python faqs] - [Python Glossary of Terms][python glossary of terms] +
+ +This first concept introduces 4 major Python language features: +1. Name Assignment (_variables and constants_), +2. Functions (_the `def` keyword and the `return` keyword_), +3. Comments, and +4. Docstrings. -This concept introduces 4 major Python language features: Name Assignment (_variables and constants_), Functions (_and the return keyword_), Comments, and Docstrings. ~~~~exercism/note @@ -32,9 +39,9 @@ On the Python track, [variables][variables] are always written in [`snake_case`] [snake case]: https://en.wikipedia.org/wiki/Snake_case +[the zen of python]: https://www.python.org/dev/peps/pep-0020/ [variables]: https://realpython.com/python-variables/ [what is pythonic]: https://blog.startifact.com/posts/older/what-is-pythonic.html -[the zen of python]: https://www.python.org/dev/peps/pep-0020/ ~~~~ @@ -127,8 +134,8 @@ def add_two_numbers(number_one, number_two): IndentationError: unindent does not match any outer indentation level ``` -Functions explicitly return a value or object via the [`return`][return] keyword. -Functions that do not have an explicit `return` expression will _implicitly_ return [`None`][none]. +Functions _explicitly_ return a value or object via the [`return`][return] keyword. +Functions that do not have an _explicit_ `return` expression will _implicitly_ return [`None`][none]. ```python # Function definition on first line. diff --git a/concepts/basics/links.json b/concepts/basics/links.json index 3e5561228e..1d1d640c9e 100644 --- a/concepts/basics/links.json +++ b/concepts/basics/links.json @@ -1,5 +1,6 @@ [ - {"url": "https://lerner.co.il/2019/06/18/understanding-python-assignment/", + { + "url": "https://lerner.co.il/2019/06/18/understanding-python-assignment/", "description": "Reuven Lerner: Understanding Python Assignment" }, { @@ -14,6 +15,10 @@ "url": "https://www.pythonmorsels.com/everything-is-an-object/", "description": "Python Morsels: Everything is an Object" }, + { + "url": "https://eli.thegreenplace.net/2012/03/23/python-internals-how-callables-work/", + "description": "Eli Bendersky: Python internals: how callables work" + }, { "url": "https://stackoverflow.com/questions/11328920/is-python-strongly-typed", "description": "dynamic typing and strong typing" diff --git a/exercises/concept/guidos-gorgeous-lasagna/.docs/hints.md b/exercises/concept/guidos-gorgeous-lasagna/.docs/hints.md index bdab2e7eb3..9006524852 100644 --- a/exercises/concept/guidos-gorgeous-lasagna/.docs/hints.md +++ b/exercises/concept/guidos-gorgeous-lasagna/.docs/hints.md @@ -3,12 +3,14 @@ ## General - [The Python Tutorial][the python tutorial] can be a great introduction. -- [Numbers][numbers] in Python can be integers, floats, or complex. - [PEP 8][pep8] is the Python code style guide. +- [PEP 257][PEP257] details Python docstring conventions. +- [Numbers][numbers] in Python can be integers, floats, or complex. + ## 1. Define expected bake time in minutes -- You need to [name][naming] a constant, and [assign][assignment] it an integer value. +- You need to [name][naming] a constant, and [assign][assignment] it an [integer][numbers] value. ## 2. Calculate remaining bake time in minutes @@ -25,7 +27,7 @@ ## 4. Calculate total elapsed cooking time (prep + bake) in minutes -- You need to define a [function][defining-functions] with two parameters. +- You need to define a [function][defining functions] with two parameters. - Remember: you can always _call_ a function you've defined previously. - You can use the [mathematical operator for addition][python as a calculator] to sum values. - This function should [return a value][return]. diff --git a/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md b/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md index f9be66c3fe..6c8de4e69f 100644 --- a/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md +++ b/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md @@ -8,14 +8,18 @@ This includes numbers, strings, lists, and even functions. We'll dig more into what all of that means as we continue through the track. -This first exercise introduces 4 major Python language features: Name Assignment (_variables and constants_), Functions (_and the return keyword_), Comments, and Docstrings. +This first exercise introduces 4 major Python language features: +1. Name Assignment (_variables and constants_), +2. Functions (_the `def` keyword and the `return` keyword_), +3. Comments, and +4. Docstrings. ~~~~exercism/note In general, content, tests, and analyzer tooling for the Python track follow the style conventions outlined in [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/) for Python code style, with the additional (strong) suggestion that there be no single letter variable names. -On the Python track, [variables][variables] are always written in [`snake_case`][snake case], and constants in `SCREAMING_SNAKE_CASE` +On the Python track, [variables][variables] are always written in [`snake_case`][snake case], and constants in `SCREAMING_SNAKE_CASE`. [variables]: https://realpython.com/python-variables/ [snake case]: https://en.wikipedia.org/wiki/Snake_case @@ -84,7 +88,7 @@ IndentationError: unindent does not match any outer indentation level ``` Functions explicitly return a value or object via the [`return`][return] keyword. -Functions that do not have an explicit `return` expression will _implicitly_ return [`None`][none]. +Functions that do not have an _explicit_ `return` expression will _implicitly_ return [`None`][none]. ```python # Function definition on first line. @@ -201,7 +205,6 @@ Raise a number to an arbitrary power. Takes number_one and raises it to the power of number_two, returning the result. ``` -[pep257]: https://www.python.org/dev/peps/pep-0257/ [calls]: https://docs.python.org/3/reference/expressions.html#calls [comments]: https://realpython.com/python-comments-guide/#python-commenting-basics [docstring]: https://docs.python.org/3/tutorial/controlflow.html#tut-docstrings @@ -215,5 +218,6 @@ Raise a number to an arbitrary power. [module]: https://docs.python.org/3/tutorial/modules.html [none]: https://docs.python.org/3/library/constants.html [parameters]: https://docs.python.org/3/glossary.html#term-parameter +[pep257]: https://www.python.org/dev/peps/pep-0257/ [return]: https://docs.python.org/3/reference/simple_stmts.html#return [type hints]: https://docs.python.org/3/library/typing.html diff --git a/exercises/concept/guidos-gorgeous-lasagna/lasagna_test.py b/exercises/concept/guidos-gorgeous-lasagna/lasagna_test.py index 7d0a7d9f1b..4066aa8a39 100644 --- a/exercises/concept/guidos-gorgeous-lasagna/lasagna_test.py +++ b/exercises/concept/guidos-gorgeous-lasagna/lasagna_test.py @@ -37,33 +37,45 @@ def test_EXPECTED_BAKE_TIME(self): @pytest.mark.task(taskno=2) def test_bake_time_remaining(self): input_data = [1, 2, 5, 10, 15, 23, 33, 39] - result_data = [40 - item for item in input_data] + result_data = [39, 38, 35, 30, 25, 17, 7, 1] - for variant, (time, result) in enumerate(zip(input_data, result_data), start=1): - with self.subTest(f'variation #{variant}', time=time, result=result): - failure_msg = f'Expected: {result} but the bake time remaining was calculated incorrectly.' - self.assertEqual(bake_time_remaining(time), result, msg=failure_msg) + for variant, (time, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', time=time, expected=expected): + actual_result = bake_time_remaining(time) + failure_msg = (f'Called bake_time_remaining({time}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the remaining bake time.') + + self.assertEqual(actual_result, expected, msg=failure_msg) @pytest.mark.task(taskno=3) def test_preparation_time_in_minutes(self): input_data = [1, 2, 5, 8, 11, 15] - result_data = [item * 2 for item in input_data] + result_data = [2, 4, 10, 16, 22, 30] + + for variant, (layers, expected) in enumerate(zip(input_data, result_data), start=1): + with self.subTest(f'variation #{variant}', layers=layers, expected=expected): + actual_result = preparation_time_in_minutes(layers) + failure_msg = (f'Called preparation_time_in_minutes({layers}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the preparation time.') - for variant, (layers, time) in enumerate(zip(input_data, result_data), start=1): - with self.subTest(f'variation #{variant}', layers=layers, time=time): - failure_msg = f'Expected: {time} minutes, but preparation time was calculated incorrectly.' - self.assertEqual(preparation_time_in_minutes(layers), time, msg=failure_msg) + self.assertEqual(actual_result, expected, msg=failure_msg) @pytest.mark.task(taskno=4) def test_elapsed_time_in_minutes(self): layer_data = (1, 2, 5, 8, 11, 15) time_data = (3, 7, 8, 4, 15, 20) - result_data = [prep * 2 + elapsed for prep, elapsed in zip(layer_data, time_data)] + result_data = [5, 11, 18, 20, 37, 50] - for variant, (layers, time, total_time) in enumerate(zip(layer_data, time_data, result_data), start=1): - with self.subTest(f'variation #{variant}', layers=layers, time=time, total_time=total_time): - failure_msg = f'Expected {time} minutes elapsed, but the timing was calculated incorrectly.' - self.assertEqual(elapsed_time_in_minutes(layers, time), total_time, msg=failure_msg) + for variant, (layers, time, expected) in enumerate(zip(layer_data, time_data, result_data), start=1): + with self.subTest(f'variation #{variant}', layers=layers, time=time, expected=expected): + actual_result = elapsed_time_in_minutes(layers, time) + failure_msg = (f'Called elapsed_time_in_minutes({layers}, {time}). ' + f'The function returned {actual_result}, but the tests ' + f'expected {expected} as the elapsed time.') + + self.assertEqual(actual_result, expected, msg=failure_msg) @pytest.mark.task(taskno=5) def test_docstrings_were_written(self): @@ -77,6 +89,9 @@ def test_docstrings_were_written(self): for variant, function in enumerate(functions, start=1): with self.subTest(f'variation #{variant}', function=function): - failure_msg = f'Expected a docstring for `{function.__name__}`, but received `None` instead.' + actual_result = function.__doc__ + failure_msg = (f'Called {function.__name__}.__doc__. {actual_result} was returned, ' + f'but the tests expected a docstring for the {function.__name__} function.') + # Check that the __doc__ key is populated for the function. - self.assertIsNotNone(function.__doc__, msg=failure_msg) + self.assertIsNotNone(actual_result, msg=failure_msg)