From 9093c008859b6aae0fd744bdc46927d3afa8e4f6 Mon Sep 17 00:00:00 2001 From: Mathstrains21 Date: Thu, 6 Jan 2022 10:31:03 +0000 Subject: [PATCH 01/49] `about.md` - how to use decorators --- concepts/decorators/about.md | 52 ++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index c628150d56..cef6a5692b 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,2 +1,50 @@ -#TODO: Add about for this concept. - +# About + +Decorators are a feature of the Python language that can modify or register a function. + +## How to use them + +Decorators are placed just above a function in the code like so: + +```python +@decorator +def function(): + pass +``` + +Some decorators take arguments: + +```python +@decorator2(name="Bob") +def function2(): + pass +``` + +If a decorator takes any arguments, but you don't wish to pass any, you must still call it with parentheses for the decorator to work: + +```python +@decorator3() +def function3(): + pass +``` + +Decorators are just syntactic sugar. +An alternative way of doing the same as the above three examples is using higher-order functions: +```python +def function(): + pass + +function = decorator(function) + + +def function2(): + pass + +function2 = decorator2(name="Bob")(function2) + + +def function3(): + pass + +function3 = decorator3()(function3) +``` From bf8e6d20e28f2867c187d0b5e16d5c50744e7a2a Mon Sep 17 00:00:00 2001 From: Mathstrains21 Date: Thu, 6 Jan 2022 10:52:24 +0000 Subject: [PATCH 02/49] Add `do_nothing` decorator --- concepts/decorators/about.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index cef6a5692b..1bfd8c4e78 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -48,3 +48,34 @@ def function3(): function3 = decorator3()(function3) ``` + +## How to write them + +As said before, decorators can modify or register a function. +The simplest decorator however, does absolutely nothing. + +Decorators are functions which return functions. +They take one argument - the function which they have been added to. +They also return one thing - the function which will be run by the program. +This is usually either the function they were added to or a slightly modified version of that function, but it does not have to be - it can be any function whatsoever. + +The simplest decorator - one that does nothing - can be written as follows: +```python +def do_nothing(function): + return function +``` +```python +def function4a(): + return 4 + +@do_nothing +def function4b(): + return 4 +``` +```python +>>>function4a() +4 +>>>function4b() +4 +``` +As you can see, both functions do the same thing, and when the decorator is added nothing changes. From 8398ddcf659035a53c4b29682c5cb7348f429477 Mon Sep 17 00:00:00 2001 From: Mathstrains21 Date: Thu, 6 Jan 2022 11:19:36 +0000 Subject: [PATCH 03/49] Example that actually does something --- concepts/decorators/about.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 1bfd8c4e78..10f493b71b 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -52,7 +52,7 @@ function3 = decorator3()(function3) ## How to write them As said before, decorators can modify or register a function. -The simplest decorator however, does absolutely nothing. +The simplest decorator however, does absolutely nothing. Decorators are functions which return functions. They take one argument - the function which they have been added to. @@ -79,3 +79,29 @@ def function4b(): 4 ``` As you can see, both functions do the same thing, and when the decorator is added nothing changes. + +A decorator that registers a function could be written as follows: +```python +functions = [] + +def register_function(function): + functions.append(function) + return function +``` +```python +>>>functions +[] +``` +```python +@register_function +def function5(): + return 5 +``` +```python +>>>functions +[] +>>>function5() +5 +``` +As you can see, adding the decorator to the function adds the function into the list. +It is important to note that this happens when the function is declared, not when it is called. From 6e45226a4b6cf6b950f6a1548f7a89a37de0bd4e Mon Sep 17 00:00:00 2001 From: Mathstrains21 Date: Fri, 7 Jan 2022 14:38:22 +0000 Subject: [PATCH 04/49] First decorator modifying the original function --- concepts/decorators/about.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 10f493b71b..547710c717 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -105,3 +105,32 @@ def function5(): ``` As you can see, adding the decorator to the function adds the function into the list. It is important to note that this happens when the function is declared, not when it is called. + +Many decorators you write will change what is run when the function is called. +These will need to return a different function to the one passed. +This different function is written inside the decorator's function. + +This decorator doubles the result of the function: +```python +def double(function): + def wrapper(): + function_result = function() + doubled = function_result * 2 + return doubled + return wrapper +``` +```python +def function6a(): + return 6 + +@double +def function6b(): + return 6 +``` +```python +>>>function6a() +6 +>>>function6b() +12 +``` +As you can see the decorator modifies the result of the function. From 59b9a3cdf3a986d6cef456e74ecb9c66f82c5c78 Mon Sep 17 00:00:00 2001 From: Mathstrains21 Date: Fri, 7 Jan 2022 17:28:44 +0000 Subject: [PATCH 05/49] Explain the example --- concepts/decorators/about.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 547710c717..574a5bd609 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -134,3 +134,17 @@ def function6b(): 12 ``` As you can see the decorator modifies the result of the function. + +Now lets take a look at what is actually happening in this decorator. + +On the first line, we have the normal function definition. +But, when we go inside this function and take a look at the next line, we get another function definition. +This function is what we will return at the end of the decorator. +This means we are not returning the original function. +Because of this, Python will not actually call the original function when a call is made to what looks like that function. +Instead, Python will call the function we created, `wrapper()`. + +If we look inside our `wrapper()` function, we first see a call to the original function. +This call will do exactly the same as if we had called the original function without the decoration to the function. +Then we get a line that modifies this result. +Finally we return the modified result, which is what we get when calling the function. From a05cd9c02c3b6d8dfbf023d135b8bd79c7e89a5f Mon Sep 17 00:00:00 2001 From: Mathstrains21 Date: Fri, 7 Jan 2022 18:33:49 +0000 Subject: [PATCH 06/49] Function parameters and varying numbers of parameters --- concepts/decorators/about.md | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 574a5bd609..e5c6dea871 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -148,3 +148,61 @@ If we look inside our `wrapper()` function, we first see a call to the original This call will do exactly the same as if we had called the original function without the decoration to the function. Then we get a line that modifies this result. Finally we return the modified result, which is what we get when calling the function. + +If we apply this decorator to a function which takes a single number and triples it, then we should get a function that sextuples our number. +Lets see what happens: +```python +@double +def triple(number): + return number * 3 +``` +```python +>>>triple(5) +Traceback (most recent call last): + File "", line 1, in +TypeError: wrapper() takes 0 positional arguments but 1 was given +``` +Unfortunately, we get an error. +This happens because, as said earlier, python does not call the original function when you appear to call it. +Python actually calls the function in the decorator, `wrapper()`, which does not have any parameters. + +To rectify this, we can add a parameter to our `wrapper()` function. +An updated `@double` decorator is shown below: +```python +def double(function): + def wrapper(value): + function_result = function(value) + doubled = function_result * 2 + return doubled + return wrapper +``` +```python +>>>triple(5) +30 +``` +However, if we now call our function which took no parameters earlier, it will fail: +```python +>>>function6b() +Traceback (most recent call last): + File "", line 1, in +TypeError: wrapper() mising 1 required positional argument: 'value' +``` +It would also fail for any other number of parameters too. + +Fortunately we can write decorators that don't care about the number of parameters a function may take by using the `*args` and `**kwargs` syntax. +Here's an update `@double` decorator: +```python +def double(function): + def wrapper(*args, **kwargs): + function_result = function(*args, **kwargs) + doubled = function_result * 2 + return doubled + return wrapper +``` +Now we should be to use this decorator on functions which accept zero, one, two or even one million (though we wouldn't recommend that many!) parameters: +```python +>>>triple(5) +30 +>>>function6b() +12 +``` From 935fbc8ec9e7a2e0f1300ecc2dea8b0e897ed8ce Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 07:53:53 -0500 Subject: [PATCH 07/49] Update about.md Saving work. Refactoring this to be more in line with the learning objectives. Just getting ideas down at this point... --- concepts/decorators/about.md | 90 ++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index e5c6dea871..8b36d7ddee 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,8 +1,10 @@ # About -Decorators are a feature of the Python language that can modify or register a function. +Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the function argument. +If function `A` is a decorator, and function `B` is its argument, then function `A` _extends_ or _replaces_ function `B`'s behavior _without modifying_ it. +We say that the decorator function `A` _wraps_ function `B`. -## How to use them +## How to use a Decorator Decorators are placed just above a function in the code like so: @@ -29,7 +31,7 @@ def function3(): ``` Decorators are just syntactic sugar. -An alternative way of doing the same as the above three examples is using higher-order functions: +An alternative way of doing the same as the above three examples is using [higher-order functions][higher-order functions]: ```python def function(): pass @@ -49,62 +51,56 @@ def function3(): function3 = decorator3()(function3) ``` -## How to write them +## How to write a Decorator -As said before, decorators can modify or register a function. -The simplest decorator however, does absolutely nothing. +Decorators are intended to extend or replace the behavior of another function, but a decorator may do nothing but return the function it is wrapping. -Decorators are functions which return functions. -They take one argument - the function which they have been added to. -They also return one thing - the function which will be run by the program. -This is usually either the function they were added to or a slightly modified version of that function, but it does not have to be - it can be any function whatsoever. +Decorators are functions which take at least one argument - the function which they are wrapping. +They usually either return the wrapped function or they may return the result of an expression that uses the wrapped function. The simplest decorator - one that does nothing - can be written as follows: ```python def do_nothing(function): - return function -``` -```python -def function4a(): - return 4 - +... return function +... @do_nothing -def function4b(): - return 4 -``` -```python ->>>function4a() -4 ->>>function4b() +def function4(): +... return 4 +... +>>>function4() 4 + ``` -As you can see, both functions do the same thing, and when the decorator is added nothing changes. -A decorator that registers a function could be written as follows: -```python -functions = [] +A decorator may add side effects (such as logging) and/or validation: -def register_function(function): - functions.append(function) - return function -``` -```python ->>>functions -[] -``` ```python -@register_function -def function5(): - return 5 -``` -```python ->>>functions -[] ->>>function5() -5 +>>> def my_logger(func): +... def my_logger_wrapper(*args, **kwargs): +... print(f"Entering {func.__name__} with {args} argument") +... if any("Pluto" in text for text in args): +... print("Pluto is not a world!") +... else: +... func(*args, **kwargs) +... print(f"After {func.__name__}") +... return my_logger_wrapper +... +... +>>> @my_logger +... def my_func(planet): +... print(f"Hello, {planet}!") +... +... +>>> my_func("World") +Entering my_func with ('World',) argument +Hello, World! +After my_func +>>> my_func(Pluto") +Entering my_func with ('Pluto',) argument +Pluto is not a world! +After my_func + ``` -As you can see, adding the decorator to the function adds the function into the list. -It is important to note that this happens when the function is declared, not when it is called. Many decorators you write will change what is run when the function is called. These will need to return a different function to the one passed. @@ -206,3 +202,5 @@ Now we should be to use this decorator on functions which accept zero, one, two >>>function6b() 12 ``` + +[higher-order functions]: https://www.geeksforgeeks.org/higher-order-functions-in-python/ From 3195b1d9d5ff2a1237e38558e0b9288abc6d48ed Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 09:10:40 -0500 Subject: [PATCH 08/49] Update about.md Saving work. More to do... --- concepts/decorators/about.md | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 8b36d7ddee..89369029c3 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,10 +1,19 @@ # About Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the function argument. -If function `A` is a decorator, and function `B` is its argument, then function `A` _extends_ or _replaces_ function `B`'s behavior _without modifying_ it. +If function `A` is a decorator, and function `B` is its argument, then function `A` extends or replaces function `B`'s behavior _without modifying_ it. We say that the decorator function `A` _wraps_ function `B`. +The wrapped function is not actually changed. +Beahvior is either added around the wrapped function, or the wrapped function's behavior is substituted. -## How to use a Decorator +## A Decorator is a Higher-Order Function + +A [higher-order function][higher-order functions] is a function that accepts a function as an argument and/or returns a function. +A function, used as an argument or returned from another function, is a [first-class function][first-class functions]. +A Python function, as a [callable object][callable object], is a first-class function which can be stored in a variable or used as an argument, much like any other value. +Higher-order functions and first-class functions work together to make decorators possible. + +## What a Decorator looks like Decorators are placed just above a function in the code like so: @@ -17,21 +26,28 @@ def function(): Some decorators take arguments: ```python -@decorator2(name="Bob") +@decorator_with_arg(name="Bob") def function2(): pass ``` -If a decorator takes any arguments, but you don't wish to pass any, you must still call it with parentheses for the decorator to work: +If a decorator takes a default argument, you must still call it with parentheses for the decorator to work: ```python -@decorator3() +@decorator_with_default_arg() def function3(): pass ``` +If a decorator takes a positional argument, using empty parentheses will result in an error which will look something like + +``` +TypeError: decorator_with_default_arg() missing 1 required positional argument: 'name' +``` + Decorators are just syntactic sugar. -An alternative way of doing the same as the above three examples is using [higher-order functions][higher-order functions]: +Following are examples of alternative ways of setting a decorator: + ```python def function(): pass @@ -42,13 +58,13 @@ function = decorator(function) def function2(): pass -function2 = decorator2(name="Bob")(function2) +function2 = decorator_with_arg(name="Bob")(function2) def function3(): pass -function3 = decorator3()(function3) +function3 = decorator_with_default_arg()(function3) ``` ## How to write a Decorator @@ -203,4 +219,6 @@ Now we should be to use this decorator on functions which accept zero, one, two 12 ``` +[callable object]: https://www.pythonmorsels.com/callables/ +[first-class functions]: https://www.geeksforgeeks.org/first-class-functions-python/ [higher-order functions]: https://www.geeksforgeeks.org/higher-order-functions-in-python/ From f1b475e71996873be9e147b8c3edc1581eeca6c5 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 09:12:17 -0500 Subject: [PATCH 09/49] Update about.md --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 89369029c3..5e49392c62 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -42,7 +42,7 @@ def function3(): If a decorator takes a positional argument, using empty parentheses will result in an error which will look something like ``` -TypeError: decorator_with_default_arg() missing 1 required positional argument: 'name' +TypeError: decorator_with_no_default_arg() missing 1 required positional argument: 'name' ``` Decorators are just syntactic sugar. From fec71c789e150935d0c9c98bc9b5bcfb2cd83da4 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 12:11:50 -0500 Subject: [PATCH 10/49] Update about.md Saving work. A bit more to do... --- concepts/decorators/about.md | 200 ++++++++++++++--------------------- 1 file changed, 81 insertions(+), 119 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 5e49392c62..078a920b67 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -10,12 +10,12 @@ Beahvior is either added around the wrapped function, or the wrapped function's A [higher-order function][higher-order functions] is a function that accepts a function as an argument and/or returns a function. A function, used as an argument or returned from another function, is a [first-class function][first-class functions]. -A Python function, as a [callable object][callable object], is a first-class function which can be stored in a variable or used as an argument, much like any other value. +A Python function, as a [callable object][callable objects], is a first-class function which can be stored in a variable or used as an argument, much like any other value. Higher-order functions and first-class functions work together to make decorators possible. ## What a Decorator looks like -Decorators are placed just above a function in the code like so: +The `@` symbol is prepended to the name of the decorator function and placed just above the function to be decorated, like so: ```python @decorator @@ -39,14 +39,14 @@ def function3(): pass ``` -If a decorator takes a positional argument, using empty parentheses will result in an error which will look something like +If a decorator takes a positional argument, using empty parentheses will result in an error which will look something like: ``` -TypeError: decorator_with_no_default_arg() missing 1 required positional argument: 'name' +TypeError: decorator_with_pos_arg() missing 1 required positional argument: 'name' ``` -Decorators are just syntactic sugar. -Following are examples of alternative ways of setting a decorator: +The `@decorator` syntax is just syntactic sugar. +Following are examples of alternative ways for setting a decorator: ```python def function(): @@ -67,158 +67,120 @@ def function3(): function3 = decorator_with_default_arg()(function3) ``` -## How to write a Decorator +## How to write a simple Decorator Decorators are intended to extend or replace the behavior of another function, but a decorator may do nothing but return the function it is wrapping. Decorators are functions which take at least one argument - the function which they are wrapping. -They usually either return the wrapped function or they may return the result of an expression that uses the wrapped function. +They usually return either the wrapped function or the result of an expression that uses the wrapped function. -The simplest decorator - one that does nothing - can be written as follows: +A simple decorator - one that simply returns its wrapped function - can be written as follows: ```python -def do_nothing(function): -... return function +>>> def do_nothing(func): +... return func ... -@do_nothing -def function4(): +... @do_nothing +... def function4(): ... return 4 ... ->>>function4() +>>> print(function4()) 4 ``` -A decorator may add side effects (such as logging) and/or validation: +A decorator may only add side effects, such as for logging: ```python >>> def my_logger(func): -... def my_logger_wrapper(*args, **kwargs): -... print(f"Entering {func.__name__} with {args} argument") -... if any("Pluto" in text for text in args): +... print(f"Entering {func.__name__}") +... return func +... +... @my_logger +... def my_func(): +... print("Hello") +... +>>> my_func() +Entering my_func +Hello + +``` + +A decorator does not return itself. +It returns either its function argument, another function, or a value that replaces the return value from the function argument. +If a decorator returns another function, it will usually return an inner function. + +## Inner Functions + +A function can be defined within a function. +Such a nested function is called an [inner function][inner functions]. +A decorator may use an inner function to wrap its function argument. +The decorator returns its inner function. +The inner function may return the original function argument. + +### How to write a validating Decorator using an inner function + +Following is an example of a decorator being used for validation: + +```python +>>> def my_validator(func): +... def my_wrapper(planet): +... print(f"Entering {func.__name__} with {planet} argument") +... if "Pluto" == planet: ... print("Pluto is not a world!") ... else: -... func(*args, **kwargs) -... print(f"After {func.__name__}") -... return my_logger_wrapper -... +... return func(planet) +... return my_wrapper ... ->>> @my_logger +... @my_validator ... def my_func(planet): ... print(f"Hello, {planet}!") ... -... >>> my_func("World") Entering my_func with ('World',) argument Hello, World! -After my_func >>> my_func(Pluto") Entering my_func with ('Pluto',) argument Pluto is not a world! -After my_func ``` -Many decorators you write will change what is run when the function is called. -These will need to return a different function to the one passed. -This different function is written inside the decorator's function. +On the first line, we have the definition for the decorator with its `func` argument. +On the next line is the definition for the decorators inner function, which wraps the `func` argument. +Since the inner function wraps the decorator's `func` argument, it is passed the same argument of `planet`. +It doesn't have to have the same name of `planet`. +If `planet` was replaced with `world` throughout the decorator, the decorater would still work. -This decorator doubles the result of the function: -```python -def double(function): - def wrapper(): - function_result = function() - doubled = function_result * 2 - return doubled - return wrapper -``` -```python -def function6a(): - return 6 +The inner function returns either `func` or, if `planet` equals `Pluto` it will print that Pluto is not a world. +It could raise a `ValueError` instead. +So, the inner function wraps `func`, and returns either `func` or does something that substitutes what `func` would do. +The decorator returns the inner function. +It does not directly return the original function. +Depending on what happens in the wrapper function, `func` may or may not be called. -@double -def function6b(): - return 6 -``` -```python ->>>function6a() -6 ->>>function6b() -12 -``` -As you can see the decorator modifies the result of the function. - -Now lets take a look at what is actually happening in this decorator. - -On the first line, we have the normal function definition. -But, when we go inside this function and take a look at the next line, we get another function definition. -This function is what we will return at the end of the decorator. -This means we are not returning the original function. -Because of this, Python will not actually call the original function when a call is made to what looks like that function. -Instead, Python will call the function we created, `wrapper()`. +Decorators can be written for functions that use an arbitrary number of parameters by using the `*args` and `**kwargs` syntax. -If we look inside our `wrapper()` function, we first see a call to the original function. -This call will do exactly the same as if we had called the original function without the decoration to the function. -Then we get a line that modifies this result. -Finally we return the modified result, which is what we get when calling the function. +Following is an example of a decorator for a function that takes an arbitrary number of arguments: -If we apply this decorator to a function which takes a single number and triples it, then we should get a function that sextuples our number. -Lets see what happens: -```python -@double -def triple(number): - return number * 3 -``` ```python ->>>triple(5) -Traceback (most recent call last): - File "", line 1, in -TypeError: wrapper() takes 0 positional arguments but 1 was given -``` -Unfortunately, we get an error. -This happens because, as said earlier, python does not call the original function when you appear to call it. -Python actually calls the function in the decorator, `wrapper()`, which does not have any parameters. +>>> def double(func): +... def wrapper(*args, **kwargs): +... return func(*args, **kwargs) * 2 +... return wrapper +... +... @double +... def add(*args): +... return sum(args) +... +>>> print(add(2, 3, 4)) +18 +>>> print(add(2, 3, 4, 5, 6)) +40 -To rectify this, we can add a parameter to our `wrapper()` function. -An updated `@double` decorator is shown below: -```python -def double(function): - def wrapper(value): - function_result = function(value) - doubled = function_result * 2 - return doubled - return wrapper ``` -```python ->>>triple(5) -30 -``` -However, if we now call our function which took no parameters earlier, it will fail: -```python ->>>function6b() -Traceback (most recent call last): - File "", line 1, in -TypeError: wrapper() mising 1 required positional argument: 'value' -``` -It would also fail for any other number of parameters too. -Fortunately we can write decorators that don't care about the number of parameters a function may take by using the `*args` and `**kwargs` syntax. -Here's an update `@double` decorator: -```python -def double(function): - def wrapper(*args, **kwargs): - function_result = function(*args, **kwargs) - doubled = function_result * 2 - return doubled - return wrapper -``` -Now we should be to use this decorator on functions which accept zero, one, two or even one million (though we wouldn't recommend that many!) parameters: -```python ->>>triple(5) -30 ->>>function6b() -12 -``` +TODO: decorators with their own arguments -[callable object]: https://www.pythonmorsels.com/callables/ +[callable objects]: https://www.pythonmorsels.com/callables/ [first-class functions]: https://www.geeksforgeeks.org/first-class-functions-python/ [higher-order functions]: https://www.geeksforgeeks.org/higher-order-functions-in-python/ +[inner functions]: https://www.geeksforgeeks.org/python-inner-functions/ From 3f063ccba9603521eab426b1fb4059a8ff5d63d3 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 12:27:18 -0500 Subject: [PATCH 11/49] Update about.md --- concepts/decorators/about.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 078a920b67..c9e7723e0b 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -126,7 +126,7 @@ Following is an example of a decorator being used for validation: ... def my_wrapper(planet): ... print(f"Entering {func.__name__} with {planet} argument") ... if "Pluto" == planet: -... print("Pluto is not a world!") +... print("Pluto is not a planet!") ... else: ... return func(planet) ... return my_wrapper @@ -140,7 +140,7 @@ Entering my_func with ('World',) argument Hello, World! >>> my_func(Pluto") Entering my_func with ('Pluto',) argument -Pluto is not a world! +Pluto is not a planet! ``` From 261740540cbd4b1ca067b94f05d9c689e7d6ba8c Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 13:31:28 -0500 Subject: [PATCH 12/49] Update about.md Pretty much there now, I think. --- concepts/decorators/about.md | 87 +++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index c9e7723e0b..97e60dcf7c 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -106,8 +106,8 @@ Hello ``` A decorator does not return itself. -It returns either its function argument, another function, or a value that replaces the return value from the function argument. -If a decorator returns another function, it will usually return an inner function. +It may return its function argument, another function, or a value that replaces the return value from the function argument. +If a decorator returns another function, it will usually return an [inner function][inner functions]. ## Inner Functions @@ -125,7 +125,7 @@ Following is an example of a decorator being used for validation: >>> def my_validator(func): ... def my_wrapper(planet): ... print(f"Entering {func.__name__} with {planet} argument") -... if "Pluto" == planet: +... if ("Pluto" == planet): ... print("Pluto is not a planet!") ... else: ... return func(planet) @@ -136,10 +136,10 @@ Following is an example of a decorator being used for validation: ... print(f"Hello, {planet}!") ... >>> my_func("World") -Entering my_func with ('World',) argument +Entering my_func with World argument Hello, World! >>> my_func(Pluto") -Entering my_func with ('Pluto',) argument +Entering my_func with Pluto argument Pluto is not a planet! ``` @@ -150,14 +150,16 @@ Since the inner function wraps the decorator's `func` argument, it is passed the It doesn't have to have the same name of `planet`. If `planet` was replaced with `world` throughout the decorator, the decorater would still work. -The inner function returns either `func` or, if `planet` equals `Pluto` it will print that Pluto is not a world. -It could raise a `ValueError` instead. +The inner function returns either `func` or, if `planet` equals `Pluto`, it will print that Pluto is not a planet. +It could be coded to raise a `ValueError` instead. So, the inner function wraps `func`, and returns either `func` or does something that substitutes what `func` would do. The decorator returns the inner function. -It does not directly return the original function. -Depending on what happens in the wrapper function, `func` may or may not be called. +It does not _directly_ return the original function. +Depending on what happens in the wrapper function, `func` may or may not be returned. -Decorators can be written for functions that use an arbitrary number of parameters by using the `*args` and `**kwargs` syntax. +### How to write a Decorator for a function that takes an arbitrary number of arguments + +Decorators can be written for functions that take an arbitrary number of arguments by using the `*args` and `**kwargs` syntax. Following is an example of a decorator for a function that takes an arbitrary number of arguments: @@ -178,7 +180,70 @@ Following is an example of a decorator for a function that takes an arbitrary nu ``` -TODO: decorators with their own arguments +This works for doubling the return value from the function argument. +If we want to triple, quadruple, etc. the return value, we can add a parameter to the decorator itself. + +### How to write a Decorator which has its own parameters + +Following is an example of a decorator that can be configured to multiply the decorated function's return value by an arbitrary amount: + +```python +>>> def multi(factor=1): +... if (factor == 0): +... raise ValueError("factor must not be 0") +... +... def outer_wrapper(func): +... def inner_wrapper(*args, **kwargs): +... return func(*args, **kwargs) * factor +... return inner_wrapper +... return outer_wrapper +... +... @multi(factor=3) +... def add(*args): +... return sum(args) +... +>>> print(add(2, 3, 4)) +27 +>>> print(add(2, 3, 4, 5, 6)) +60 + +``` + +The first lines validate that `factor` is not `0`. +Then the outer wrapper is defined. +This has the same signature we expect for an unparameterized decorator. +The outer wrapper has an inner function with the same signature as the original function. +The inner wrapper does the work of multiplying the returned value from the orignal function by the argument passed to the decorator. +The outer wrapper returns the inner wrapper, and the decorator returns the outer wrapper. + +Following is an example of a parameterized decorator that controls whether it validates the argument passed to the original function: + +```python +>>> def check_for_pluto(check=True): +... def my_validator(func): +... def my_wrapper(world): +... print(f"Entering {func.__name__} with {world} argument") +... if (check and "Pluto" == world): +... print("Pluto is not a planet!") +... else: +... return func(world) +... return my_wrapper +... return my_validator +... +... @check_for_pluto(check=False) +... def my_func(planet): +... print(f"Hello, {planet}!") +... +>>> my_func("World") +Entering my_func with World argument +Hello, World! +>>> my_func("Pluto") +Entering my_func with Pluto argument +Hello, Pluto! + +``` + +This allows for easy toggling between checking for `Pluto` or not, and is done without having to modify `my_func`. [callable objects]: https://www.pythonmorsels.com/callables/ [first-class functions]: https://www.geeksforgeeks.org/first-class-functions-python/ From 20c603edaa9ae5fae4aa03011b5f3e0265371ffc Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Sun, 29 May 2022 15:45:28 -0500 Subject: [PATCH 13/49] Update about.md Fixed some typos --- concepts/decorators/about.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 97e60dcf7c..7c5a4a6e0e 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,10 +1,10 @@ # About Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the function argument. -If function `A` is a decorator, and function `B` is its argument, then function `A` extends or replaces function `B`'s behavior _without modifying_ it. +If function `A` is a decorator, and function `B` is its argument, then function `A` extends or replaces function `B`'s behavior _without modifying_ function `B`. We say that the decorator function `A` _wraps_ function `B`. The wrapped function is not actually changed. -Beahvior is either added around the wrapped function, or the wrapped function's behavior is substituted. +Behavior is either added around the wrapped function, or the wrapped function's behavior is substituted. ## A Decorator is a Higher-Order Function @@ -213,7 +213,7 @@ The first lines validate that `factor` is not `0`. Then the outer wrapper is defined. This has the same signature we expect for an unparameterized decorator. The outer wrapper has an inner function with the same signature as the original function. -The inner wrapper does the work of multiplying the returned value from the orignal function by the argument passed to the decorator. +The inner wrapper does the work of multiplying the returned value from the original function by the argument passed to the decorator. The outer wrapper returns the inner wrapper, and the decorator returns the outer wrapper. Following is an example of a parameterized decorator that controls whether it validates the argument passed to the original function: From 38bc6cc076f22026f76ed888360d1acf27985383 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:32:33 -0500 Subject: [PATCH 14/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 7c5a4a6e0e..8fed192d82 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,6 +1,6 @@ # About -Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the function argument. +Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the passed-in function. If function `A` is a decorator, and function `B` is its argument, then function `A` extends or replaces function `B`'s behavior _without modifying_ function `B`. We say that the decorator function `A` _wraps_ function `B`. The wrapped function is not actually changed. From f0ed0b8e29200b51a3180e01111742a4c1ee0fa1 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:32:51 -0500 Subject: [PATCH 15/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 8fed192d82..09dc133447 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,7 +1,7 @@ # About Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the passed-in function. -If function `A` is a decorator, and function `B` is its argument, then function `A` extends or replaces function `B`'s behavior _without modifying_ function `B`. +If function `A` is a decorator, and function `B` is its argument, then function `A` modifies, extends or replaces function `B`'s **behavior** _without modifying_ function `B`'s code. We say that the decorator function `A` _wraps_ function `B`. The wrapped function is not actually changed. Behavior is either added around the wrapped function, or the wrapped function's behavior is substituted. From 2e5a3cebcd4853b46405c0fb422745f0e5496719 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:33:08 -0500 Subject: [PATCH 16/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 09dc133447..b0935e0c8f 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -3,7 +3,7 @@ Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the passed-in function. If function `A` is a decorator, and function `B` is its argument, then function `A` modifies, extends or replaces function `B`'s **behavior** _without modifying_ function `B`'s code. We say that the decorator function `A` _wraps_ function `B`. -The wrapped function is not actually changed. +While we talk about "modifying" behavior, the wrapped function is _not actually changed_. Behavior is either added around the wrapped function, or the wrapped function's behavior is substituted. ## A Decorator is a Higher-Order Function From bb1b05af7e6b3d2d9570a111206926d548f67e59 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:33:32 -0500 Subject: [PATCH 17/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index b0935e0c8f..060e226367 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -8,7 +8,7 @@ Behavior is either added around the wrapped function, or the wrapped function's ## A Decorator is a Higher-Order Function -A [higher-order function][higher-order functions] is a function that accepts a function as an argument and/or returns a function. +A [higher-order function][higher-order functions] is a function that accepts one or more functions as arguments and/or returns one or more functions. A function, used as an argument or returned from another function, is a [first-class function][first-class functions]. A Python function, as a [callable object][callable objects], is a first-class function which can be stored in a variable or used as an argument, much like any other value. Higher-order functions and first-class functions work together to make decorators possible. From b7c51beec9aeb247db64a055cddf245fffa8bc30 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:34:25 -0500 Subject: [PATCH 18/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 060e226367..5984b30265 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -4,7 +4,7 @@ Decorators are functions that take another function as an argument for the purpo If function `A` is a decorator, and function `B` is its argument, then function `A` modifies, extends or replaces function `B`'s **behavior** _without modifying_ function `B`'s code. We say that the decorator function `A` _wraps_ function `B`. While we talk about "modifying" behavior, the wrapped function is _not actually changed_. -Behavior is either added around the wrapped function, or the wrapped function's behavior is substituted. +Behavior is either added _around_ the wrapped function (_and what it returns_), or the wrapped function's behavior is _substituted_ for some other behavior. ## A Decorator is a Higher-Order Function From dc9d705f04fb3f62aeb5ac332f2b3f016f4b7bc8 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:36:24 -0500 Subject: [PATCH 19/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 5984b30265..29e45c709a 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -10,7 +10,7 @@ Behavior is either added _around_ the wrapped function (_and what it returns_), A [higher-order function][higher-order functions] is a function that accepts one or more functions as arguments and/or returns one or more functions. A function, used as an argument or returned from another function, is a [first-class function][first-class functions]. -A Python function, as a [callable object][callable objects], is a first-class function which can be stored in a variable or used as an argument, much like any other value. +A Python function, as a [callable object][callable objects], is a first-class function which can be stored in a variable or used as an argument, much like any other value or object. Higher-order functions and first-class functions work together to make decorators possible. ## What a Decorator looks like From 066b8fdf230f50817410485fd976759973efa1fb Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:36:41 -0500 Subject: [PATCH 20/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 29e45c709a..2d281665ba 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -13,7 +13,7 @@ A function, used as an argument or returned from another function, is a [first-c A Python function, as a [callable object][callable objects], is a first-class function which can be stored in a variable or used as an argument, much like any other value or object. Higher-order functions and first-class functions work together to make decorators possible. -## What a Decorator looks like +## What Using Decorator Looks Like The `@` symbol is prepended to the name of the decorator function and placed just above the function to be decorated, like so: From 9f2736508eb41a5bcf0397f0f21a740e07fc06bd Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:37:03 -0500 Subject: [PATCH 21/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 2d281665ba..b2de76cdf2 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -19,7 +19,7 @@ The `@` symbol is prepended to the name of the decorator function and placed jus ```python @decorator -def function(): +def decorated_function(): pass ``` From 56d7a6e93cbf37afe35fcc8073d3ed8a8650e256 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:37:26 -0500 Subject: [PATCH 22/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index b2de76cdf2..be108352a8 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -23,7 +23,7 @@ def decorated_function(): pass ``` -Some decorators take arguments: +Some decorators accept arguments: ```python @decorator_with_arg(name="Bob") From 961d9176d5417e3453703b9bfbc4b47ce5acda2f Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:37:51 -0500 Subject: [PATCH 23/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index be108352a8..de53ea7a76 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -31,7 +31,7 @@ def function2(): pass ``` -If a decorator takes a default argument, you must still call it with parentheses for the decorator to work: +If a decorator has defined default arguments, you must use parenthesis in the `@decorator()` call for the decorator to work: ```python @decorator_with_default_arg() From 97e06a25ad4fa36746a27694718cb41395874dda Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:38:05 -0500 Subject: [PATCH 24/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index de53ea7a76..1709ae18d7 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -27,7 +27,7 @@ Some decorators accept arguments: ```python @decorator_with_arg(name="Bob") -def function2(): +def decorated_function2(): pass ``` From 8a2667852834c15e78aeada7002875b00c6469d7 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:38:15 -0500 Subject: [PATCH 25/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 1709ae18d7..ebc4b45b83 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -153,7 +153,7 @@ If `planet` was replaced with `world` throughout the decorator, the decorater wo The inner function returns either `func` or, if `planet` equals `Pluto`, it will print that Pluto is not a planet. It could be coded to raise a `ValueError` instead. So, the inner function wraps `func`, and returns either `func` or does something that substitutes what `func` would do. -The decorator returns the inner function. +The decorator returns its _inner function_. It does not _directly_ return the original function. Depending on what happens in the wrapper function, `func` may or may not be returned. From 155b722a18f1dfc86f4c7d20f13cb2bd4498e9aa Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:38:24 -0500 Subject: [PATCH 26/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index ebc4b45b83..d110f3b83d 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -154,7 +154,7 @@ The inner function returns either `func` or, if `planet` equals `Pluto`, it will It could be coded to raise a `ValueError` instead. So, the inner function wraps `func`, and returns either `func` or does something that substitutes what `func` would do. The decorator returns its _inner function_. -It does not _directly_ return the original function. +It does not _directly_ return the original, passed-in function. Depending on what happens in the wrapper function, `func` may or may not be returned. ### How to write a Decorator for a function that takes an arbitrary number of arguments From 23ad694ee86c871728714c90d76412c264008ed9 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:38:39 -0500 Subject: [PATCH 27/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index d110f3b83d..1a07df4704 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -157,7 +157,7 @@ The decorator returns its _inner function_. It does not _directly_ return the original, passed-in function. Depending on what happens in the wrapper function, `func` may or may not be returned. -### How to write a Decorator for a function that takes an arbitrary number of arguments +### Decorating a Function that Takes an Arbitrary Number of Arguments Decorators can be written for functions that take an arbitrary number of arguments by using the `*args` and `**kwargs` syntax. From 5897d625427ce49b1a571104004abdbf7fa5d459 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:38:49 -0500 Subject: [PATCH 28/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 1a07df4704..457ab427e1 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -183,7 +183,7 @@ Following is an example of a decorator for a function that takes an arbitrary nu This works for doubling the return value from the function argument. If we want to triple, quadruple, etc. the return value, we can add a parameter to the decorator itself. -### How to write a Decorator which has its own parameters +### Decorators Which Have Their own Parameters Following is an example of a decorator that can be configured to multiply the decorated function's return value by an arbitrary amount: From 4cf2503cf070cdd19c9e4e53a67c8cd0c6935404 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:39:08 -0500 Subject: [PATCH 29/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 457ab427e1..b23a52050b 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -35,7 +35,7 @@ If a decorator has defined default arguments, you must use parenthesis in the `@ ```python @decorator_with_default_arg() -def function3(): +def decorated_function3(): pass ``` From bea08e91b72e991cbdbb4b86eefaf005a108d9a2 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:39:33 -0500 Subject: [PATCH 30/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index b23a52050b..975a8f5c55 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -39,7 +39,7 @@ def decorated_function3(): pass ``` -If a decorator takes a positional argument, using empty parentheses will result in an error which will look something like: +If a decorator takes a _positional_ arguments, not supplying the arguments will result in an error which will look something like: ``` TypeError: decorator_with_pos_arg() missing 1 required positional argument: 'name' From 936193d9425e556b98f7a47892388ab25d72c946 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:39:59 -0500 Subject: [PATCH 31/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 975a8f5c55..5681722212 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -45,7 +45,7 @@ If a decorator takes a _positional_ arguments, not supplying the arguments will TypeError: decorator_with_pos_arg() missing 1 required positional argument: 'name' ``` -The `@decorator` syntax is just syntactic sugar. +The `@decorator` syntax is syntactic sugar or a shorthand for calling the _decorating function_ and passing the _decorated function_ to it as an argument. Following are examples of alternative ways for setting a decorator: ```python From bc3d624d5a19d4a27f6d6696441133fa7b52f79b Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:40:19 -0500 Subject: [PATCH 32/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 5681722212..ebf2c76aac 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -46,7 +46,7 @@ TypeError: decorator_with_pos_arg() missing 1 required positional argument: 'nam ``` The `@decorator` syntax is syntactic sugar or a shorthand for calling the _decorating function_ and passing the _decorated function_ to it as an argument. -Following are examples of alternative ways for setting a decorator: +Following are examples of alternative ways for calling a decorator: ```python def function(): From 99c86626c70a95eaa41814863fc31331bc5d8392 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:40:50 -0500 Subject: [PATCH 33/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index ebf2c76aac..02f5d8299b 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -67,7 +67,7 @@ def function3(): function3 = decorator_with_default_arg()(function3) ``` -## How to write a simple Decorator +## Writing a Simple Decorator Decorators are intended to extend or replace the behavior of another function, but a decorator may do nothing but return the function it is wrapping. From 6721bd48a41691d097890010f41a1a43e23d30db Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:42:07 -0500 Subject: [PATCH 34/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 02f5d8299b..0996b0a16d 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -69,7 +69,7 @@ function3 = decorator_with_default_arg()(function3) ## Writing a Simple Decorator -Decorators are intended to extend or replace the behavior of another function, but a decorator may do nothing but return the function it is wrapping. +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. They usually return either the wrapped function or the result of an expression that uses the wrapped function. From 89e5971da92f79044ae6c0655d6d811d6e5248a9 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:43:00 -0500 Subject: [PATCH 35/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 0996b0a16d..502315aad9 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -106,7 +106,7 @@ Hello ``` A decorator does not return itself. -It may return its function argument, another function, or a value that replaces the return value from the function argument. +It may return its function arguments, another function, or one or more values that replace the return from the passed-in or decorated function. If a decorator returns another function, it will usually return an [inner function][inner functions]. ## Inner Functions From f7d7bd40fe2642c67f16b3d5eeae7c5e11741948 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:43:22 -0500 Subject: [PATCH 36/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 502315aad9..c90f27da11 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -114,7 +114,7 @@ If a decorator returns another function, it will usually return an [inner functi A function can be defined within a function. Such a nested function is called an [inner function][inner functions]. A decorator may use an inner function to wrap its function argument. -The decorator returns its inner function. +The decorator then returns its inner function. The inner function may return the original function argument. ### How to write a validating Decorator using an inner function From 844d117aecd359683140ac3353542853014d9ec4 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:43:37 -0500 Subject: [PATCH 37/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index c90f27da11..c2c7bb8a55 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -115,7 +115,7 @@ A function can be defined within a function. Such a nested function is called an [inner function][inner functions]. A decorator may use an inner function to wrap its function argument. The decorator then returns its inner function. -The inner function may return the original function argument. +The inner function may then return the original function argument. ### How to write a validating Decorator using an inner function From 7f7cc5b6be8b034f2cc580ce7a5a4ebd4b0c65c4 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:43:54 -0500 Subject: [PATCH 38/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index c2c7bb8a55..38dd8df1bc 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -88,7 +88,7 @@ A simple decorator - one that simply returns its wrapped function - can be writt ``` -A decorator may only add side effects, such as for logging: +A decorator may only add side effects, such as additional information used for logging: ```python >>> def my_logger(func): From 324c224f3cfa376969b9f9ebebe98d7d49215bd1 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:44:25 -0500 Subject: [PATCH 39/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 1 + 1 file changed, 1 insertion(+) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 38dd8df1bc..8447519718 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -138,6 +138,7 @@ Following is an example of a decorator being used for validation: >>> my_func("World") Entering my_func with World argument Hello, World! +... >>> my_func(Pluto") Entering my_func with Pluto argument Pluto is not a planet! From 0634ecc719249c43fb7841161cbbbef40973b04c Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:44:58 -0500 Subject: [PATCH 40/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 8447519718..a31e4b32ac 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -146,7 +146,7 @@ Pluto is not a planet! ``` On the first line, we have the definition for the decorator with its `func` argument. -On the next line is the definition for the decorators inner function, which wraps the `func` argument. +On the next line is the definition for the decorators _inner function_, which wraps the `func` argument. Since the inner function wraps the decorator's `func` argument, it is passed the same argument of `planet`. It doesn't have to have the same name of `planet`. If `planet` was replaced with `world` throughout the decorator, the decorater would still work. From cc93f0aa5f71388480b6ac59aed43b731e608cf0 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:45:21 -0500 Subject: [PATCH 41/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index a31e4b32ac..e3e5017506 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -147,7 +147,7 @@ Pluto is not a planet! On the first line, we have the definition for the decorator with its `func` argument. On the next line is the definition for the decorators _inner function_, which wraps the `func` argument. -Since the inner function wraps the decorator's `func` argument, it is passed the same argument of `planet`. +Since the _inner function_ wraps the decorator's `func` argument, it is passed the same argument of `planet`. It doesn't have to have the same name of `planet`. If `planet` was replaced with `world` throughout the decorator, the decorater would still work. From 467d18cfad79ea482eb827af6258eda834e44965 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 08:16:07 -0500 Subject: [PATCH 42/49] Update about.md --- concepts/decorators/about.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index e3e5017506..7bb5b23e72 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -123,12 +123,12 @@ Following is an example of a decorator being used for validation: ```python >>> def my_validator(func): -... def my_wrapper(planet): -... print(f"Entering {func.__name__} with {planet} argument") -... if ("Pluto" == planet): +... def my_wrapper(world): +... print(f"Entering {func.__name__} with {world} argument") +... if ("Pluto" == world): ... print("Pluto is not a planet!") ... else: -... return func(planet) +... return func(world) ... return my_wrapper ... ... @my_validator @@ -139,7 +139,7 @@ Following is an example of a decorator being used for validation: Entering my_func with World argument Hello, World! ... ->>> my_func(Pluto") +>>> my_func("Pluto") Entering my_func with Pluto argument Pluto is not a planet! @@ -147,9 +147,9 @@ Pluto is not a planet! On the first line, we have the definition for the decorator with its `func` argument. On the next line is the definition for the decorators _inner function_, which wraps the `func` argument. -Since the _inner function_ wraps the decorator's `func` argument, it is passed the same argument of `planet`. -It doesn't have to have the same name of `planet`. -If `planet` was replaced with `world` throughout the decorator, the decorater would still work. +Since the _inner function_ wraps the decorator's `func` argument, it is passed the same argument that is passed to `func`. +Note that the wrapper doesn't have to use the same name for the argument that was defined in `func`. +The original function uses `planet` and the decorator uses `world`, and the decorater still works. The inner function returns either `func` or, if `planet` equals `Pluto`, it will print that Pluto is not a planet. It could be coded to raise a `ValueError` instead. From 19c4cc602a10db4db3b95ddef930753d6253a849 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 13 Jun 2022 08:19:19 -0500 Subject: [PATCH 43/49] Update concepts/decorators/about.md Co-authored-by: BethanyG --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 7bb5b23e72..913cee9411 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -117,7 +117,7 @@ A decorator may use an inner function to wrap its function argument. The decorator then returns its inner function. The inner function may then return the original function argument. -### How to write a validating Decorator using an inner function +### A Validating Decorator Using an Inner Function Following is an example of a decorator being used for validation: From 3a59dddbba84a48a889d96a979d4c8deb3519d23 Mon Sep 17 00:00:00 2001 From: KOTP Date: Wed, 15 Jun 2022 16:35:49 -0400 Subject: [PATCH 44/49] White space "corrections" --- concepts/decorators/about.md | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 913cee9411..927e065c54 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -3,7 +3,7 @@ Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the passed-in function. If function `A` is a decorator, and function `B` is its argument, then function `A` modifies, extends or replaces function `B`'s **behavior** _without modifying_ function `B`'s code. We say that the decorator function `A` _wraps_ function `B`. -While we talk about "modifying" behavior, the wrapped function is _not actually changed_. +While we talk about "modifying" behavior, the wrapped function is _not actually changed_. Behavior is either added _around_ the wrapped function (_and what it returns_), or the wrapped function's behavior is _substituted_ for some other behavior. ## A Decorator is a Higher-Order Function @@ -31,7 +31,7 @@ def decorated_function2(): pass ``` -If a decorator has defined default arguments, you must use parenthesis in the `@decorator()` call for the decorator to work: +If a decorator has defined default arguments, you must use parenthesis in the `@decorator()` call for the decorator to work: ```python @decorator_with_default_arg() @@ -78,14 +78,13 @@ A simple decorator - one that simply returns its wrapped function - can be writt ```python >>> def do_nothing(func): ... return func -... +... ... @do_nothing ... def function4(): ... return 4 -... +... >>> print(function4()) 4 - ``` A decorator may only add side effects, such as additional information used for logging: @@ -94,15 +93,14 @@ A decorator may only add side effects, such as additional information used for l >>> def my_logger(func): ... print(f"Entering {func.__name__}") ... return func -... +... ... @my_logger ... def my_func(): ... print("Hello") -... +... >>> my_func() Entering my_func Hello - ``` A decorator does not return itself. @@ -130,11 +128,11 @@ Following is an example of a decorator being used for validation: ... else: ... return func(world) ... return my_wrapper -... +... ... @my_validator ... def my_func(planet): ... print(f"Hello, {planet}!") -... +... >>> my_func("World") Entering my_func with World argument Hello, World! @@ -142,7 +140,6 @@ Hello, World! >>> my_func("Pluto") Entering my_func with Pluto argument Pluto is not a planet! - ``` On the first line, we have the definition for the decorator with its `func` argument. @@ -169,16 +166,15 @@ Following is an example of a decorator for a function that takes an arbitrary nu ... def wrapper(*args, **kwargs): ... return func(*args, **kwargs) * 2 ... return wrapper -... +... ... @double ... def add(*args): ... return sum(args) -... +... >>> print(add(2, 3, 4)) 18 >>> print(add(2, 3, 4, 5, 6)) 40 - ``` This works for doubling the return value from the function argument. @@ -192,22 +188,21 @@ Following is an example of a decorator that can be configured to multiply the de >>> def multi(factor=1): ... if (factor == 0): ... raise ValueError("factor must not be 0") -... +... ... def outer_wrapper(func): ... def inner_wrapper(*args, **kwargs): ... return func(*args, **kwargs) * factor ... return inner_wrapper ... return outer_wrapper -... +... ... @multi(factor=3) ... def add(*args): ... return sum(args) -... +... >>> print(add(2, 3, 4)) 27 >>> print(add(2, 3, 4, 5, 6)) 60 - ``` The first lines validate that `factor` is not `0`. @@ -230,18 +225,17 @@ Following is an example of a parameterized decorator that controls whether it va ... return func(world) ... return my_wrapper ... return my_validator -... +... ... @check_for_pluto(check=False) ... def my_func(planet): ... print(f"Hello, {planet}!") -... +... >>> my_func("World") Entering my_func with World argument Hello, World! >>> my_func("Pluto") Entering my_func with Pluto argument Hello, Pluto! - ``` This allows for easy toggling between checking for `Pluto` or not, and is done without having to modify `my_func`. From 26a5434d19799cd3ac0e5cde5aac0672d4e6c7a8 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Thu, 16 Jun 2022 06:20:26 -0500 Subject: [PATCH 45/49] Update concepts/decorators/about.md Co-authored-by: Victor Goff --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 927e065c54..8b3e61fbc5 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -1,7 +1,7 @@ # About Decorators are functions that take another function as an argument for the purpose of extending or replacing the behavior of the passed-in function. -If function `A` is a decorator, and function `B` is its argument, then function `A` modifies, extends or replaces function `B`'s **behavior** _without modifying_ function `B`'s code. +If function `A` is a decorator, and function `B` is its argument, then function `A` modifies, extends, or replaces function `B`'s **behavior** _without modifying_ function `B`'s code. We say that the decorator function `A` _wraps_ function `B`. While we talk about "modifying" behavior, the wrapped function is _not actually changed_. Behavior is either added _around_ the wrapped function (_and what it returns_), or the wrapped function's behavior is _substituted_ for some other behavior. From 970ddd55b747516753b1ec1daaa7848d610d6fa0 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Thu, 16 Jun 2022 06:20:52 -0500 Subject: [PATCH 46/49] Update concepts/decorators/about.md Co-authored-by: Victor Goff --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 8b3e61fbc5..5b9b8941a5 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -13,7 +13,7 @@ A function, used as an argument or returned from another function, is a [first-c A Python function, as a [callable object][callable objects], is a first-class function which can be stored in a variable or used as an argument, much like any other value or object. Higher-order functions and first-class functions work together to make decorators possible. -## What Using Decorator Looks Like +## What Using a Decorator Looks Like The `@` symbol is prepended to the name of the decorator function and placed just above the function to be decorated, like so: From 1dffa4da7ada06d13bd7efdcefe7dee7a09f6f83 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Thu, 16 Jun 2022 06:21:03 -0500 Subject: [PATCH 47/49] Update concepts/decorators/about.md Co-authored-by: Victor Goff --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 5b9b8941a5..695a036024 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -146,7 +146,7 @@ On the first line, we have the definition for the decorator with its `func` argu On the next line is the definition for the decorators _inner function_, which wraps the `func` argument. Since the _inner function_ wraps the decorator's `func` argument, it is passed the same argument that is passed to `func`. Note that the wrapper doesn't have to use the same name for the argument that was defined in `func`. -The original function uses `planet` and the decorator uses `world`, and the decorater still works. +The original function uses `planet` and the decorator uses `world`, and the decorator still works. The inner function returns either `func` or, if `planet` equals `Pluto`, it will print that Pluto is not a planet. It could be coded to raise a `ValueError` instead. From a1066e008a19e8997b47277c97c1da198bb4e793 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Thu, 16 Jun 2022 06:21:40 -0500 Subject: [PATCH 48/49] Update concepts/decorators/about.md Co-authored-by: Victor Goff --- concepts/decorators/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index 695a036024..b54a7dec43 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -178,7 +178,7 @@ Following is an example of a decorator for a function that takes an arbitrary nu ``` This works for doubling the return value from the function argument. -If we want to triple, quadruple, etc. the return value, we can add a parameter to the decorator itself. +If we want to triple, quadruple, etc. the return value, we can add a parameter to the decorator itself., as we show in the next section. ### Decorators Which Have Their own Parameters From fa7101ffb3e0a710514b203c8e62b53f53d8d644 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Thu, 16 Jun 2022 06:36:10 -0500 Subject: [PATCH 49/49] Update about.md --- concepts/decorators/about.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/concepts/decorators/about.md b/concepts/decorators/about.md index b54a7dec43..3b29864dbb 100644 --- a/concepts/decorators/about.md +++ b/concepts/decorators/about.md @@ -31,7 +31,7 @@ def decorated_function2(): pass ``` -If a decorator has defined default arguments, you must use parenthesis in the `@decorator()` call for the decorator to work: +If a decorator has defined default arguments, you must use parenthesis in the `@decorator()` call for the decorator to work, as you would in calling any function: ```python @decorator_with_default_arg() @@ -152,8 +152,8 @@ The inner function returns either `func` or, if `planet` equals `Pluto`, it will It could be coded to raise a `ValueError` instead. So, the inner function wraps `func`, and returns either `func` or does something that substitutes what `func` would do. The decorator returns its _inner function_. -It does not _directly_ return the original, passed-in function. -Depending on what happens in the wrapper function, `func` may or may not be returned. +The _inner_function_ may or may not return the original, passed-in function. +Depending on what code conditionally executes in the wrapper function or _inner_function_, `func` may be returned, an error could be raised, or a value of `func`'s return type could be returned. ### Decorating a Function that Takes an Arbitrary Number of Arguments @@ -178,7 +178,7 @@ Following is an example of a decorator for a function that takes an arbitrary nu ``` This works for doubling the return value from the function argument. -If we want to triple, quadruple, etc. the return value, we can add a parameter to the decorator itself., as we show in the next section. +If we want to triple, quadruple, etc. the return value, we can add a parameter to the decorator itself, as we show in the next section. ### Decorators Which Have Their own Parameters