From 8a4defb5618c9fa15dd3afd299e841e0feba77c3 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 26 May 2026 14:26:15 -0700 Subject: [PATCH 1/5] Typos and fixes for function arguments concept. --- concepts/function-arguments/about.md | 134 +++++++++----------- concepts/function-arguments/introduction.md | 70 ++++++---- 2 files changed, 105 insertions(+), 99 deletions(-) diff --git a/concepts/function-arguments/about.md b/concepts/function-arguments/about.md index 0f2ab5dddda..851263204c6 100644 --- a/concepts/function-arguments/about.md +++ b/concepts/function-arguments/about.md @@ -12,22 +12,20 @@ Parameter names should not contain spaces or punctuation. Positional arguments are values passed to a function in the same order as the parameters which bind to them. Positional arguments can optionally be passed by using their parameter name. -Following is an example of positional arguments being passed by position and by their parameter name: +Positional arguments being passed by position and by their parameter name: ```python >>> def concat(greeting, name): -... return f"{greeting}{name}" -... +... return f"{greeting}{name}" + # Passing data to the function by position. >>> print(concat("Hello, ", "Bob")) - Hello, Bob -... + # Passing data to the function using the parameter name. >>> print(concat(name="Bob", greeting="Hello, ")) Hello, Bob - ``` The first call to `concat` passes the arguments by position. @@ -38,7 +36,7 @@ Note that positional arguments cannot follow keyword arguments. This ```python ->>> print(concat(greeting="Hello, ", "Bob")) +>>> print(concat(greeting="Hello, ", "Gregor")) ``` results in this error: @@ -50,24 +48,21 @@ SyntaxError: positional argument follows keyword argument Requiring positional-only arguments for function calls can be done through the use of the `/` operator in the parameter list. -Following is an example of positional-only arguments: +Positional-only arguments: ```python # Parameters showing a position-only operator. >>> def concat(greeting, name, /): -... return f"{greeting}{name}" +... return f"{greeting}{name}" -... >>> print(concat("Hello, ", "Bob")) Hello, Bob -... + # Call to the function using keyword arguments. >>> print(concat(name="Bob", greeting="Hello, ")) Traceback (most recent call last): print(concat(name="Bob", greeting="Hello, ")) TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting, name' - - ``` ## Keyword Arguments @@ -75,43 +70,40 @@ TypeError: concat() got some positional-only arguments passed as keyword argumen Keyword arguments use the parameter name when calling a function. Keyword arguments can optionally be referred to by position. -Following is an example of keyword arguments being referred to by their parameter name and by position: +Keyword arguments being referred to by their parameter name and by position: ```python >>> def concat(greeting, name): -... return f"{greeting}{name}" -... +... return f"{greeting}{name}" + # Function call using parameter names as argument keywords. >>> print(concat(name="Bob", greeting="Hello, ")) Hello, Bob -... + # Function call with positional data as arguments. >>> print(concat("Hello, ", "Bob")) Hello, Bob - ``` Requiring keyword-only arguments for function calls can be done through the use of the `*` operator in the parameter list. -Following is an example of keyword-only arguments: +Keyword-only arguments: ```python # Function definition requiring keyword-only arguments. >>> def concat(*, greeting, name): -... return f"{greeting}{name}" -... +... return f"{greeting}{name}" + # Keyword arguments can be in an arbitrary order. >>> print(concat(name="Bob", greeting="Hello, ")) Hello, Bob -... + # Calling the function with positional data raises an error. >>> print(concat("Hello, ", "Bob")) Traceback (most recent call last): print(concat("Hello, ", "Bob")) TypeError: concat() takes 0 positional arguments but 2 were given - - ``` ## Default Argument Values @@ -123,8 +115,8 @@ Default values can be overridden by calling the function with a new argument val ```python # Function with default argument values. >>> def concat(greeting, name="you", punctuation="!"): -... return f"{greeting}, {name}{punctuation}" -... +... return f"{greeting}, {name}{punctuation}" + >>> print(concat("Hello")) Hello, you! @@ -138,23 +130,23 @@ Hello, Bob. Arguments can be positional or keyword if neither the `/` nor `*` operators are used in the parameter definitions. Alternately, the positional-or-keyword arguments can be placed between the positional-only parameters on the left and the keyword-only parameters on the right. -Following is an example of positional-only, positional-or-keyword, and keyword-only arguments: +Positional-only, positional-or-keyword, and keyword-only arguments: ```python # Position-only argument followed by position-or-keyword, followed by keyword-only. ->>> def concat(greeting, /, name, *, ending): -... return f"{greeting}{name}{ending}" -... +>>> def concat(greeting, /, name, *, ending): +... return f"{greeting}{name}{ending}" + >>> print(concat("Hello, ", "Bob", ending="!")) Hello, Bob! + >>> print(concat("Hello, ", name="Bob", ending="!")) Hello, Bob! -... + >>> print(concat(greeting="Hello, ", name="Bob", ending="!")) Traceback (most recent call last): print(concat(greeting="Hello, ", name="Bob", ending="!")) TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting' - ``` ## `*args` @@ -164,7 +156,6 @@ Code examples will often use a function definition something like the following: ```python def my_function(*args, **kwargs): # code snipped - ``` `*args` is a two-part name that represents a `tuple` with an indefinite number of separate positional arguments, also known as a [`variadic argument`][variadic argument]. @@ -175,77 +166,77 @@ The `*` is the operator which transforms the group of separate arguments into a If you have ever [unpacked a tuple][unpack a tuple] you may find the `*` in `*args` to be confusing. The `*` in a _parameter_ definition, instead of unpacking a tuple, converts one or more positional arguments _into_ a tuple. -We say that the `*` operator is [overloaded], as it has different behavior in different contexts. +We say that the `*` operator is [_overloaded_][overloading], as it has different behavior in different contexts. For instance, `*` is used for multiplication, it is used for unpacking, and it is used to define an arbitrary number of positional parameters. + +[overloading]: https://therenegadecoder.com/code/abusing-pythons-operator-overloading-feature/ +[unpacking]: https://www.geeksforgeeks.org/unpacking-a-tuple-in-python/ ~~~~ -Since a tuple can be iterated, `args` can be passed to any other function which takes an iterable. +Since a tuple can be iterated over, `args` can be passed to any other function which takes an iterable. Although `*args` is commonly juxtaposed with `**kwargs`, it doesn't have to be. -Following is an example of an arbitrary number of values being passed to a function: +An arbitrary number of values being passed to a function: ```python - >>> def add(*args): -# args is passed to the sum function, which takes an iterable -... return sum(args) -... + # args is passed to the sum function, which iterates over it. +... return sum(args) + >>> print(add(1, 2, 3)) 6 ``` If `*args` follows one or more positional arguments, then `*args` will be what is left over after the positional arguments. -Following is an example of an arbitrary number of values being passed to a function after a positional argument: +An arbitrary number of values being passed to a function after a positional argument: ```python - >>> def add(first, *args): # first will be 1, leaving the values 2 and 3 in *args ... return first + sum(args) -... + >>> print(add(1, 2, 3)) 6 ``` -If one or more default arguments are defined after `*args` they are separate from the `*args` values. +If one or more [default arguments][default arguments] are defined after `*args`, they are separate from the `*args` values. -To put it all together is an example of an arbitrary number of values being passed to a function that also has a positional argument and a default argument: +To put it all together: ```python >>> def add(first, *args, last=0): -... return first + sum(args) + last -... +... return first + sum(args) + last + >>> print(add(1, 2, 3)) 6 >>> print(add(1, 2, 3, last=4)) 10 + # This uses the unpacking operator * to separate the list elements into positional arguments. -# It does not have the same behavior as the * in *args. +# It does not have the same behavior as the * (packing) in *args. >>> print(add(*[1, 2, 3])) 6 - ``` -Note that when an argument is already in an iterable, such as a tuple or list, it needs to be unpacked before being passed to a function that takes an arbitrary number of separate arguments. +Note that when an argument is already inside an `iterable`, such as a `tuple` or `list`, it needs to be [_unpacked_][unpacking-and-multiple-assignment] before being passed to a function that takes an arbitrary number of separate arguments. This is accomplished by using `*`, which is the [unpacking operator][unpacking operator]. `*` in this context _unpacks_ the container into its separate elements which are then transformed by `*args` into a tuple. -Where there are only positional arguments, the unpacking action must result in the same number of arguments as there are formal parameters. +Where there are only positional arguments, the unpacking action must result in the same number of arguments as there are formal parameters defined. Without unpacking the list passed into `add`, the program would error. ```python ->>>> def add(first, *args, last=0): -... return first + sum(args) + last -... ->>>> print(add([1, 2, 3])) +>>> def add(first, *args, last=0): +... return first + sum(args) + last + +>>> print(add([1, 2, 3])) Traceback (most recent call last): print(add([1, 2, 3])) return first + sum(args) + last TypeError: can only concatenate list (not "int") to list - ``` ## `**kwargs` @@ -254,42 +245,37 @@ TypeError: can only concatenate list (not "int") to list `kwargs` is the name of the group of arguments and could be any other name, such as `my_args`, `arguments`, etc. The `**` transforms the group of named arguments into a [`dictionary`][dictionary] of `{argument name: argument value}` pairs. -Since a dictionary can be iterated, `kwargs` can be passed to any other function which takes an iterable. +Since a dictionary can be iterated over, `kwargs` can be passed to any other function which takes an iterable. Although `**kwargs` is commonly juxtaposed with `*args`, it doesn't have to be. -Following is an example of an arbitrary number of key-value pairs being passed to a function: +An arbitrary number of key-value pairs being passed to a function: ```python >>> def add(**kwargs): -... return sum(kwargs.values()) -... +... return sum(kwargs.values()) + >>> print(add(one=1, two=2, three=3)) 6 ``` Note that the `dict.values()` method is called to iterate through the `kwargs` dictionary values. - -When iterating a dictionary the default is to iterate the keys. - -Following is an example of an arbitrary number of key-value pairs being passed to a function that then iterates over `kwargs.keys()`: +When iterating over a dictionary the default is to iterate through the _keys_, so `dict.values()` needs to be specified explicitly. +Following is an example of an arbitrary number of key-value pairs being passed to a function that then iterates over `kwargs.items()`: ```python >>> def concat(**kwargs): - # Join concatenates the key names from `kwargs.keys()` -... return " ".join(kwargs) -... ->>> print(concat(one=1, two=2, three=3)) -one two three +... # Join concatenates the tuples from `kwargs.items()` +... return " ".join((str(item) for item in kwargs.items())) +>>> print(concat(one=1, two=2, three=3)) +('one', 1) ('two', 2) ('three', 3) ``` - [default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ -[dictionary]: https://www.w3schools.com/python/python_dictionaries.asp -[function concept]: ../functions/about.md +[dictionary]: https://exercism.org/tracks/python/concepts/dicts +[function concept]: https://github.com/exercism/python/blob/main/concepts/functions/about.md [key-value]: https://www.pythontutorial.net/python-basics/python-dictionary/ -[overloaded]: https://www.geeksforgeeks.org/operator-overloading-in-python/ [tuple]: https://www.w3schools.com/python/python_tuples.asp -[unpack a tuple]: https://www.geeksforgeeks.org/unpacking-a-tuple-in-python/ [unpacking operator]: https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists +[unpacking-and-multiple-assignment]: https://exercism.org/tracks/python/concepts/unpacking-and-multiple-assignment [variadic argument]: https://en.wikipedia.org/wiki/Variadic_function diff --git a/concepts/function-arguments/introduction.md b/concepts/function-arguments/introduction.md index 07b885f332e..a5ecc400272 100644 --- a/concepts/function-arguments/introduction.md +++ b/concepts/function-arguments/introduction.md @@ -4,7 +4,7 @@ For the basics on function arguments, please see the [function concept][function ## Parameter Names -Parameter names, like variable names, must start with a letter or underscore and may contain letters, underscores, or numbers. +[Parameter names][parameters], like variable names, must start with a letter or underscore and may contain letters, underscores, or numbers. Parameter names should not contain spaces or punctuation. ## Positional Arguments @@ -16,58 +16,78 @@ Following is an example of positional arguments being passed by position and by ```python >>> def concat(greeting, name): -... return f"{greeting}{name}" +... return f"{greeting}{name}" ... # Passing data to the function by position. ->>> print(concat("Hello, ", "Bob")) -Hello, Bob -... -# Passing data to the function using the parameter name. ->>> print(concat(name="Bob", greeting="Hello, ")) -Hello, Bob +>>> print(concat("Hello, ", "Judy")) +Hello, Judy +# Passing data to the function using the parameter name. +>>> print(concat(name="Sally", greeting="Hello, ")) +Hello, Sally ``` The first call to concat passes the arguments by position. -The second call to concat passes the arguments by name, allowing their positions to be changed. +The second call to concat passes the arguments by _name_, allowing their positions to be changed. -Note that positional arguments cannot follow keyword arguments. +Note that positional arguments cannot follow arguments passed by name (_also called [keyword arguments][keyword-arguments]. **Not** to be confused with var-positional parameters or [kwargs][kwargs]_). -This +This set of arguments ```python ->>> print(concat(greeting="Hello, ", "Bob")) +>>> print(concat(greeting="Hello, ", "Zed")) ``` -results in this error: +will result in this error: ``` SyntaxError: positional argument follows keyword argument ``` +## Default Argument Values + +[Default values][default arguments] for one or more arguments can be supplied in the parameter list. +This allows the function to be called with _fewer_ arguments if needed. +Default values can be overridden by calling the function with new arguments in place of the defaults: + + +```python +# Note the default arguments for both greeting and name. +>>> def concat(greeting="Hello, ", name="you"): +... return f"{greeting}{name}" + +# Function call overriding the defaults +>>> print(concat(name="Jerry", greeting="Hello, ")) +Hello, Jerry + +# Function call without arguments resulting in the defaults being used. +>>> print(concat()) +Hello, you +``` + ## Keyword Arguments -Keyword arguments use the parameter name when calling a function. +Keyword arguments use the parameter name when passing arguments to a function. Keyword arguments can optionally be referred to by position. Following is an example of keyword arguments being referred to by their parameter name and by position: ```python +# Note the default arguments for both greeting and name. >>> def concat(greeting="Hello, ", name="you"): -... return f"{greeting}{name}" +... return f"{greeting}{name}" ... # Function call using parameter names as argument keywords. ->>> print(concat(name="Bob", greeting="Hello, ")) -Hello, Bob -... -# Function call with positional data as arguments. ->>> print(concat("Hello, ", name="Bob")) -Hello, Bob ->>> print(concat()) -Hello, you +>>> print(concat(name="Jerry", greeting="Hello, ")) +Hello, Jerry +# Function call with positional data as arguments. +>>> print(concat("Hello, ", "Isaac")) +Hello, Isaac ``` [default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ -[function concept]: ../functions/about.md -[parameters]: https://www.codecademy.com/learn/flask-introduction-to-python/modules/learn-python3-functions/cheatsheet +[function concept]: https://github.com/exercism/python/blob/main/concepts/functions/about.md +[keyword-arguments]: https://docs.python.org/3/glossary.html#term-argument +[kwargs]: https://docs.python.org/3/glossary.html#term-parameter +[parameters]: https://www.codecademy.com/learn/flask-introduction-to-python/modules/learn-python3-functions/cheatsheet \ No newline at end of file From 4acaa307f24ccdb6dbfd700b8082976a900afa88 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 26 May 2026 16:17:18 -0700 Subject: [PATCH 2/5] Applied changes from code review. --- concepts/function-arguments/about.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/concepts/function-arguments/about.md b/concepts/function-arguments/about.md index 851263204c6..61f0f094d0e 100644 --- a/concepts/function-arguments/about.md +++ b/concepts/function-arguments/about.md @@ -33,23 +33,21 @@ The second call to `concat` passes the arguments by name, allowing their positio Note that positional arguments cannot follow keyword arguments. -This +This set of arguments: ```python >>> print(concat(greeting="Hello, ", "Gregor")) ``` -results in this error: +Results in this error: ``` SyntaxError: positional argument follows keyword argument ``` -Requiring positional-only arguments for function calls can be done through the use of the `/` operator in the parameter list. +Requiring positional-only arguments for function calls can be done through the use of the `/` operator in the parameter list: -Positional-only arguments: - ```python # Parameters showing a position-only operator. >>> def concat(greeting, name, /): @@ -163,20 +161,19 @@ def my_function(*args, **kwargs): The `*` is the operator which transforms the group of separate arguments into a [`tuple`][tuple]. ~~~~exercism/note -If you have ever [unpacked a tuple][unpack a tuple] you may find the `*` in `*args` to be confusing. +If you have ever [unpacked a tuple][unpack-a-tuple] you may find the `*` in `*args` to be confusing. The `*` in a _parameter_ definition, instead of unpacking a tuple, converts one or more positional arguments _into_ a tuple. We say that the `*` operator is [_overloaded_][overloading], as it has different behavior in different contexts. For instance, `*` is used for multiplication, it is used for unpacking, and it is used to define an arbitrary number of positional parameters. [overloading]: https://therenegadecoder.com/code/abusing-pythons-operator-overloading-feature/ -[unpacking]: https://www.geeksforgeeks.org/unpacking-a-tuple-in-python/ +[unpack-a-tuple]: https://www.geeksforgeeks.org/unpacking-a-tuple-in-python/ ~~~~ Since a tuple can be iterated over, `args` can be passed to any other function which takes an iterable. -Although `*args` is commonly juxtaposed with `**kwargs`, it doesn't have to be. +Although `*args` is commonly juxtaposed with `**kwargs`, it doesn't have to be: -An arbitrary number of values being passed to a function: ```python >>> def add(*args): @@ -187,9 +184,8 @@ An arbitrary number of values being passed to a function: 6 ``` -If `*args` follows one or more positional arguments, then `*args` will be what is left over after the positional arguments. +If `*args` follows one or more positional arguments, then `*args` will be what is left over after the positional arguments: -An arbitrary number of values being passed to a function after a positional argument: ```python >>> def add(first, *args): @@ -226,7 +222,7 @@ This is accomplished by using `*`, which is the [unpacking operator][unpacking o `*` in this context _unpacks_ the container into its separate elements which are then transformed by `*args` into a tuple. Where there are only positional arguments, the unpacking action must result in the same number of arguments as there are formal parameters defined. -Without unpacking the list passed into `add`, the program would error. +Without unpacking the list passed into `add`, the program would error: ```python >>> def add(first, *args, last=0): @@ -246,9 +242,8 @@ TypeError: can only concatenate list (not "int") to list The `**` transforms the group of named arguments into a [`dictionary`][dictionary] of `{argument name: argument value}` pairs. Since a dictionary can be iterated over, `kwargs` can be passed to any other function which takes an iterable. -Although `**kwargs` is commonly juxtaposed with `*args`, it doesn't have to be. +Although `**kwargs` is commonly juxtaposed with `*args`, it doesn't have to be: -An arbitrary number of key-value pairs being passed to a function: ```python >>> def add(**kwargs): @@ -259,7 +254,7 @@ An arbitrary number of key-value pairs being passed to a function: ``` Note that the `dict.values()` method is called to iterate through the `kwargs` dictionary values. -When iterating over a dictionary the default is to iterate through the _keys_, so `dict.values()` needs to be specified explicitly. +When iterating over a dictionary, the default is to iterate through the _keys_, so `dict.values()` needs to be specified explicitly. Following is an example of an arbitrary number of key-value pairs being passed to a function that then iterates over `kwargs.items()`: ```python @@ -273,7 +268,7 @@ Following is an example of an arbitrary number of key-value pairs being passed t [default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ [dictionary]: https://exercism.org/tracks/python/concepts/dicts -[function concept]: https://github.com/exercism/python/blob/main/concepts/functions/about.md +[function concept]: https://exercism.org/tracks/python/concepts/functions [key-value]: https://www.pythontutorial.net/python-basics/python-dictionary/ [tuple]: https://www.w3schools.com/python/python_tuples.asp [unpacking operator]: https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists From 0317aea88305d9a53843244a06770a753d625bfc Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 26 May 2026 17:55:09 -0700 Subject: [PATCH 3/5] Applied edits from code review and re-wrote some more of the prose. --- concepts/function-arguments/about.md | 178 ++++++++++---------- concepts/function-arguments/introduction.md | 53 +++--- 2 files changed, 113 insertions(+), 118 deletions(-) diff --git a/concepts/function-arguments/about.md b/concepts/function-arguments/about.md index 61f0f094d0e..f4f2802c95a 100644 --- a/concepts/function-arguments/about.md +++ b/concepts/function-arguments/about.md @@ -10,33 +10,32 @@ Parameter names should not contain spaces or punctuation. ## Positional Arguments Positional arguments are values passed to a function in the same order as the parameters which bind to them. -Positional arguments can optionally be passed by using their parameter name. +Positional arguments can optionally be passed by using their parameter name: -Positional arguments being passed by position and by their parameter name: ```python ->>> def concat(greeting, name): -... return f"{greeting}{name}" +def concat(greeting, name): + return f"{greeting}{name}" # Passing data to the function by position. ->>> print(concat("Hello, ", "Bob")) -Hello, Bob +print(concat("Hello, ", "Lilly")) +#-> Hello, Lilly # Passing data to the function using the parameter name. ->>> print(concat(name="Bob", greeting="Hello, ")) +print(concat(name="Glenn", greeting="Hello, ")) -Hello, Bob +#-> Hello, Glenn ``` The first call to `concat` passes the arguments by position. The second call to `concat` passes the arguments by name, allowing their positions to be changed. -Note that positional arguments cannot follow keyword arguments. +Note that positional arguments cannot follow arguments passed by name (_also called [keyword arguments][keyword-arguments]. **Not** to be confused with var-positional parameters or [**kwargs][kwargs]_). This set of arguments: ```python ->>> print(concat(greeting="Hello, ", "Gregor")) +print(concat(greeting="Hello, ", "Gregor")) ``` Results in this error: @@ -47,60 +46,54 @@ SyntaxError: positional argument follows keyword argument Requiring positional-only arguments for function calls can be done through the use of the `/` operator in the parameter list: - ```python # Parameters showing a position-only operator. ->>> def concat(greeting, name, /): -... return f"{greeting}{name}" +def concat(greeting, name, /): + return f"{greeting}{name}" ->>> print(concat("Hello, ", "Bob")) -Hello, Bob +print(concat("Hello, ", "Ginnie")) +#-> Hello, Ginnie # Call to the function using keyword arguments. ->>> print(concat(name="Bob", greeting="Hello, ")) +print(concat(name="Franklin", greeting="Hello, ")) Traceback (most recent call last): - print(concat(name="Bob", greeting="Hello, ")) + print(concat(name="Franklin", greeting="Hello, ")) TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting, name' ``` ## Keyword Arguments Keyword arguments use the parameter name when calling a function. -Keyword arguments can optionally be referred to by position. - -Keyword arguments being referred to by their parameter name and by position: +They can optionally be referred to by position: ```python ->>> def concat(greeting, name): -... return f"{greeting}{name}" +def concat(greeting, name): + return f"{greeting}{name}" # Function call using parameter names as argument keywords. ->>> print(concat(name="Bob", greeting="Hello, ")) -Hello, Bob +print(concat(name="Eliza", greeting="Hello, ")) +#--> Hello, Eliza # Function call with positional data as arguments. ->>> print(concat("Hello, ", "Bob")) -Hello, Bob +print(concat("Hello, ", "Tim")) +#-> Hello, Tim ``` -Requiring keyword-only arguments for function calls can be done through the use of the `*` operator in the parameter list. - - -Keyword-only arguments: +Requiring keyword-only arguments for function calls can be done through the use of the `*` operator in the parameter list: ```python # Function definition requiring keyword-only arguments. ->>> def concat(*, greeting, name): -... return f"{greeting}{name}" +def concat(*, greeting, name): + return f"{greeting}{name}" # Keyword arguments can be in an arbitrary order. ->>> print(concat(name="Bob", greeting="Hello, ")) -Hello, Bob +print(concat(name="Kimmie", greeting="Hello, ")) +#-> Hello, Kimmie # Calling the function with positional data raises an error. ->>> print(concat("Hello, ", "Bob")) +print(concat("Hello, ", "Coleen")) Traceback (most recent call last): - print(concat("Hello, ", "Bob")) + print(concat("Hello, ", "Coleen")) TypeError: concat() takes 0 positional arguments but 2 were given ``` @@ -112,41 +105,41 @@ Default values can be overridden by calling the function with a new argument val ```python # Function with default argument values. ->>> def concat(greeting, name="you", punctuation="!"): -... return f"{greeting}, {name}{punctuation}" +def concat(greeting, name="you", punctuation="!"): + return f"{greeting}, {name}{punctuation}" ->>> print(concat("Hello")) +print(concat("Hello")) Hello, you! # Overriding the default values ->>> print(concat("Hello", name="Bob", punctuation=".")) -Hello, Bob. +print(concat("Hello", name="Polly", punctuation=".")) +Hello, Polly. ``` + ## Positional or Keyword Arguments Arguments can be positional or keyword if neither the `/` nor `*` operators are used in the parameter definitions. -Alternately, the positional-or-keyword arguments can be placed between the positional-only parameters on the left and the keyword-only parameters on the right. - -Positional-only, positional-or-keyword, and keyword-only arguments: +Alternately, the positional-or-keyword arguments can be placed between the positional-only parameters on the left and the keyword-only parameters on the right: ```python # Position-only argument followed by position-or-keyword, followed by keyword-only. ->>> def concat(greeting, /, name, *, ending): -... return f"{greeting}{name}{ending}" +def concat(greeting, /, name, *, ending): + return f"{greeting}{name}{ending}" ->>> print(concat("Hello, ", "Bob", ending="!")) -Hello, Bob! +print(concat("Hello, ", "Mark", ending="!")) +Hello, Mark! ->>> print(concat("Hello, ", name="Bob", ending="!")) -Hello, Bob! +print(concat("Hello, ", name="Rachel", ending="!")) +Hello, Rachel! ->>> print(concat(greeting="Hello, ", name="Bob", ending="!")) +>>> print(concat(greeting="Hello, ", name="JoJo", ending="!")) Traceback (most recent call last): - print(concat(greeting="Hello, ", name="Bob", ending="!")) + print(concat(greeting="Hello, ", name="JoJo", ending="!")) TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting' ``` + ## `*args` Code examples will often use a function definition something like the following: @@ -157,7 +150,7 @@ def my_function(*args, **kwargs): ``` `*args` is a two-part name that represents a `tuple` with an indefinite number of separate positional arguments, also known as a [`variadic argument`][variadic argument]. -`args` is the name given to the `tuple` of arguments, but it could be any other valid Python name, such as `my_args`, `arguments`, etc. +`args` is the name given to the `tuple` of arguments, but it could be any other valid Python name, such as `my_args`, `arguments`, etc. The `*` is the operator which transforms the group of separate arguments into a [`tuple`][tuple]. ~~~~exercism/note @@ -171,70 +164,71 @@ For instance, `*` is used for multiplication, it is used for unpacking, and it i [unpack-a-tuple]: https://www.geeksforgeeks.org/unpacking-a-tuple-in-python/ ~~~~ -Since a tuple can be iterated over, `args` can be passed to any other function which takes an iterable. +Since a `tuple` can be iterated over, `args` can be passed to any other function which takes an iterable. Although `*args` is commonly juxtaposed with `**kwargs`, it doesn't have to be: ```python ->>> def add(*args): - # args is passed to the sum function, which iterates over it. -... return sum(args) +def add(*args): + # args is passed to the sum function, which iterates over it. + return sum(args) ->>> print(add(1, 2, 3)) -6 +print(add(1, 2, 3)) +#-> 6 ``` If `*args` follows one or more positional arguments, then `*args` will be what is left over after the positional arguments: ```python ->>> def add(first, *args): -# first will be 1, leaving the values 2 and 3 in *args -... return first + sum(args) +def add(first, *args): + # first will be 1, leaving the values 2 and 3 in *args + return first + sum(args) ->>> print(add(1, 2, 3)) -6 +print(add(1, 2, 3)) +#-> 6 ``` -If one or more [default arguments][default arguments] are defined after `*args`, they are separate from the `*args` values. +If one or more [default arguments][default arguments] are defined after `*args`, they are separate from the `*args` values: -To put it all together: ```python ->>> def add(first, *args, last=0): -... return first + sum(args) + last +def add(first, *args, last=0): + return first + sum(args) + last ->>> print(add(1, 2, 3)) -6 ->>> print(add(1, 2, 3, last=4)) -10 +print(add(1, 2, 3)) +#-> 6 + +print(add(1, 2, 3, last=4)) +#-> 10 # This uses the unpacking operator * to separate the list elements into positional arguments. # It does not have the same behavior as the * (packing) in *args. ->>> print(add(*[1, 2, 3])) -6 +print(add(*[1, 2, 3])) +#-> 6 ``` -Note that when an argument is already inside an `iterable`, such as a `tuple` or `list`, it needs to be [_unpacked_][unpacking-and-multiple-assignment] before being passed to a function that takes an arbitrary number of separate arguments. +Note that when an argument is already inside an `iterable` such as a `tuple` or `list`, it needs to be [_unpacked_][unpacking-and-multiple-assignment] before being passed to a function that takes an arbitrary number of separate arguments. This is accomplished by using `*`, which is the [unpacking operator][unpacking operator]. -`*` in this context _unpacks_ the container into its separate elements which are then transformed by `*args` into a tuple. +`*` in this context _unpacks_ the container into its separate elements which are then transformed by `*args` into a `tuple`. Where there are only positional arguments, the unpacking action must result in the same number of arguments as there are formal parameters defined. Without unpacking the list passed into `add`, the program would error: ```python ->>> def add(first, *args, last=0): -... return first + sum(args) + last +def add(first, *args, last=0): + return first + sum(args) + last ->>> print(add([1, 2, 3])) +print(add([1, 2, 3])) Traceback (most recent call last): print(add([1, 2, 3])) return first + sum(args) + last TypeError: can only concatenate list (not "int") to list ``` + ## `**kwargs` `**kwargs` is a two-part name that represents an indefinite number of separate [key-value pair][key-value] arguments. @@ -246,24 +240,23 @@ Although `**kwargs` is commonly juxtaposed with `*args`, it doesn't have to be: ```python ->>> def add(**kwargs): -... return sum(kwargs.values()) +def add(**kwargs): + return sum(kwargs.values()) ->>> print(add(one=1, two=2, three=3)) -6 +print(add(one=1, two=2, three=3)) +#-> 6 ``` -Note that the `dict.values()` method is called to iterate through the `kwargs` dictionary values. -When iterating over a dictionary, the default is to iterate through the _keys_, so `dict.values()` needs to be specified explicitly. -Following is an example of an arbitrary number of key-value pairs being passed to a function that then iterates over `kwargs.items()`: +Note that the `dict.values()` method is called to iterate through the `kwargs` dictionary `values`. +When iterating over a dictionary, the default is to iterate through the _`keys`_, so `dict.values()` needs to be specified explicitly: ```python ->>> def concat(**kwargs): -... # Join concatenates the tuples from `kwargs.items()` -... return " ".join((str(item) for item in kwargs.items())) +def concat(**kwargs): + # Join concatenates the tuples from `kwargs.items()` + return " ".join((str(item) for item in kwargs.items())) ->>> print(concat(one=1, two=2, three=3)) -('one', 1) ('two', 2) ('three', 3) +print(concat(one=1, two=2, three=3)) +#-> ('one', 1) ('two', 2) ('three', 3) ``` [default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ @@ -274,3 +267,6 @@ Following is an example of an arbitrary number of key-value pairs being passed t [unpacking operator]: https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists [unpacking-and-multiple-assignment]: https://exercism.org/tracks/python/concepts/unpacking-and-multiple-assignment [variadic argument]: https://en.wikipedia.org/wiki/Variadic_function +[keyword-arguments]: https://docs.python.org/3/glossary.html#term-argument +[kwargs]: https://docs.python.org/3/glossary.html#term-parameter + diff --git a/concepts/function-arguments/introduction.md b/concepts/function-arguments/introduction.md index a5ecc400272..3f12c68ec55 100644 --- a/concepts/function-arguments/introduction.md +++ b/concepts/function-arguments/introduction.md @@ -7,32 +7,32 @@ For the basics on function arguments, please see the [function concept][function [Parameter names][parameters], like variable names, must start with a letter or underscore and may contain letters, underscores, or numbers. Parameter names should not contain spaces or punctuation. + ## Positional Arguments Positional arguments are values passed to a function in the same order as the parameters which bind to them. -Positional arguments can optionally be passed by using their parameter name. +They can optionally be passed by using their parameter name: -Following is an example of positional arguments being passed by position and by their parameter name: ```python ->>> def concat(greeting, name): -... return f"{greeting}{name}" -... +def concat(greeting, name): + return f"{greeting}{name}" + # Passing data to the function by position. ->>> print(concat("Hello, ", "Judy")) -Hello, Judy +print(concat("Hello, ", "Judy")) +#-> Hello, Judy # Passing data to the function using the parameter name. ->>> print(concat(name="Sally", greeting="Hello, ")) -Hello, Sally +print(concat(name="Sally", greeting="Hello, ")) +#-> Hello, Sally ``` The first call to concat passes the arguments by position. The second call to concat passes the arguments by _name_, allowing their positions to be changed. -Note that positional arguments cannot follow arguments passed by name (_also called [keyword arguments][keyword-arguments]. **Not** to be confused with var-positional parameters or [kwargs][kwargs]_). +Note that positional arguments cannot follow arguments passed by name (_also called [keyword arguments][keyword-arguments]. **Not** to be confused with var-positional parameters or [**kwargs][kwargs]_). -This set of arguments +This set of arguments: ```python >>> print(concat(greeting="Hello, ", "Zed")) @@ -53,41 +53,40 @@ Default values can be overridden by calling the function with new arguments in p ```python # Note the default arguments for both greeting and name. ->>> def concat(greeting="Hello, ", name="you"): -... return f"{greeting}{name}" +def concat(greeting="Hello, ", name="you"): + return f"{greeting}{name}" # Function call overriding the defaults ->>> print(concat(name="Jerry", greeting="Hello, ")) -Hello, Jerry +print(concat(name="Jerry", greeting="Hello, ")) +#-> Hello, Jerry # Function call without arguments resulting in the defaults being used. ->>> print(concat()) -Hello, you +print(concat()) +#--> Hello, you ``` ## Keyword Arguments Keyword arguments use the parameter name when passing arguments to a function. -Keyword arguments can optionally be referred to by position. +They can optionally be referred to by position: -Following is an example of keyword arguments being referred to by their parameter name and by position: ```python # Note the default arguments for both greeting and name. ->>> def concat(greeting="Hello, ", name="you"): -... return f"{greeting}{name}" -... +def concat(greeting="Hello, ", name="you"): + return f"{greeting}{name}" + # Function call using parameter names as argument keywords. ->>> print(concat(name="Jerry", greeting="Hello, ")) -Hello, Jerry +print(concat(name="Jerry", greeting="Hello, ")) +#-> Hello, Jerry # Function call with positional data as arguments. ->>> print(concat("Hello, ", "Isaac")) -Hello, Isaac +print(concat("Hello, ", "Isaac")) +#-> Hello, Isaac ``` [default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ [function concept]: https://github.com/exercism/python/blob/main/concepts/functions/about.md [keyword-arguments]: https://docs.python.org/3/glossary.html#term-argument [kwargs]: https://docs.python.org/3/glossary.html#term-parameter -[parameters]: https://www.codecademy.com/learn/flask-introduction-to-python/modules/learn-python3-functions/cheatsheet \ No newline at end of file +[parameters]: https://www.codecademy.com/learn/flask-introduction-to-python/modules/learn-python3-functions/cheatsheet From 51098f935a180ffb736087ada7375a202f4937e1 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 26 May 2026 18:25:51 -0700 Subject: [PATCH 4/5] Applied feedback from code review. --- concepts/function-arguments/about.md | 15 +++++++-------- concepts/function-arguments/introduction.md | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/concepts/function-arguments/about.md b/concepts/function-arguments/about.md index f4f2802c95a..02d8bd58893 100644 --- a/concepts/function-arguments/about.md +++ b/concepts/function-arguments/about.md @@ -23,7 +23,6 @@ print(concat("Hello, ", "Lilly")) # Passing data to the function using the parameter name. print(concat(name="Glenn", greeting="Hello, ")) - #-> Hello, Glenn ``` @@ -72,7 +71,7 @@ def concat(greeting, name): # Function call using parameter names as argument keywords. print(concat(name="Eliza", greeting="Hello, ")) -#--> Hello, Eliza +#-> Hello, Eliza # Function call with positional data as arguments. print(concat("Hello, ", "Tim")) @@ -109,11 +108,11 @@ def concat(greeting, name="you", punctuation="!"): return f"{greeting}, {name}{punctuation}" print(concat("Hello")) -Hello, you! +#-> Hello, you! # Overriding the default values print(concat("Hello", name="Polly", punctuation=".")) -Hello, Polly. +#-> Hello, Polly. ``` @@ -128,12 +127,12 @@ def concat(greeting, /, name, *, ending): return f"{greeting}{name}{ending}" print(concat("Hello, ", "Mark", ending="!")) -Hello, Mark! +#-> Hello, Mark! print(concat("Hello, ", name="Rachel", ending="!")) -Hello, Rachel! +#-> Hello, Rachel! ->>> print(concat(greeting="Hello, ", name="JoJo", ending="!")) +print(concat(greeting="Hello, ", name="JoJo", ending="!")) Traceback (most recent call last): print(concat(greeting="Hello, ", name="JoJo", ending="!")) TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting' @@ -209,7 +208,7 @@ print(add(*[1, 2, 3])) #-> 6 ``` -Note that when an argument is already inside an `iterable` such as a `tuple` or `list`, it needs to be [_unpacked_][unpacking-and-multiple-assignment] before being passed to a function that takes an arbitrary number of separate arguments. +Note that when an argument is already inside an `iterable` (_such as a `tuple` or `list`_), it needs to be [_unpacked_][unpacking-and-multiple-assignment] before being passed to a function that takes an arbitrary number of separate arguments. This is accomplished by using `*`, which is the [unpacking operator][unpacking operator]. `*` in this context _unpacks_ the container into its separate elements which are then transformed by `*args` into a `tuple`. diff --git a/concepts/function-arguments/introduction.md b/concepts/function-arguments/introduction.md index 3f12c68ec55..24ad980a3b4 100644 --- a/concepts/function-arguments/introduction.md +++ b/concepts/function-arguments/introduction.md @@ -62,7 +62,7 @@ print(concat(name="Jerry", greeting="Hello, ")) # Function call without arguments resulting in the defaults being used. print(concat()) -#--> Hello, you +#-> Hello, you ``` ## Keyword Arguments From ae392ea44fbae3d9782f4f150b6e7db01f596dce Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 26 May 2026 19:12:35 -0700 Subject: [PATCH 5/5] Corrected link to functions concept. --- concepts/function-arguments/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concepts/function-arguments/introduction.md b/concepts/function-arguments/introduction.md index 24ad980a3b4..e9d3da4d14d 100644 --- a/concepts/function-arguments/introduction.md +++ b/concepts/function-arguments/introduction.md @@ -86,7 +86,7 @@ print(concat("Hello, ", "Isaac")) ``` [default arguments]: https://www.geeksforgeeks.org/default-arguments-in-python/ -[function concept]: https://github.com/exercism/python/blob/main/concepts/functions/about.md +[function concept]: https://exercism.org/tracks/python/concepts/functions [keyword-arguments]: https://docs.python.org/3/glossary.html#term-argument [kwargs]: https://docs.python.org/3/glossary.html#term-parameter [parameters]: https://www.codecademy.com/learn/flask-introduction-to-python/modules/learn-python3-functions/cheatsheet