` can consist of general Python code, and is demarcated by being indented relative to the `def` statement.\n",
"- `return` if reached by the encapsulated code, triggers the function to return the specified object and end its own execution immediately.\n",
" \n",
"The `return` statement is also reserved by Python. It denotes the end of a function; if reached, a `return` statement immediately concludes the execution of the function and returns the specified object. \n",
"\n",
"Note that, like an if-statement and a for-loop, the `def` statment must end in a colon and the body of the function is [delimited by whitespace](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Introduction.html#Python-Uses-Whitespace-to-Delimit-Scope):"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"# wrong indentation\n",
"def bad_func1():\n",
"x = 1\n",
" return x + 2\n",
"```\n",
"***\n",
"```python\n",
"# wrong indentation\n",
"def bad_func2():\n",
" x = 1\n",
"return x + 2\n",
"```\n",
"***\n",
"```python\n",
"# missing colon\n",
"def bad_func3()\n",
" x = 1\n",
" return x + 2\n",
"```\n",
"***\n",
"```python\n",
"# missing parenthesis\n",
"def bad_func4:\n",
" x = 1\n",
" return x + 2\n",
"```\n",
"\n",
"***\n",
"```python\n",
"# this is ok\n",
"def ok_func():\n",
" x = 1\n",
" return x + 2\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**Reading Comprehension: Writing a Basic Function**\n",
"\n",
"Write a function named `count_even`. It should accept one input argument, named `numbers`, which will be an iterable containing integers. Have the function return the number of even-valued integers contained in the list. Include a reasonable docstring.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The `return` Statement\n",
"In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the* `None` *object*.\n",
"\n",
"```python\n",
"# this function returns `None`\n",
"# an \"empty\" return statement\n",
"def f():\n",
" x = 1\n",
" return\n",
"```\n",
"\n",
"```python\n",
"# this function returns `None`\n",
"# return statement is omitted\n",
"def f():\n",
" x = 1\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All Python functions return *something*. Even the built-in `print` function returns `None` after it prints to standard-output! \n",
"\n",
"```python\n",
"# the `print` function returns `None`\n",
">>> x = print(\"hi\")\n",
"hi\n",
"\n",
">>> x is None\n",
"True\n",
"```\n",
"\n",
"\n",
"**Warning!** \n",
"\n",
"Take care to not *mistakenly* omit a return statement or leave it blank. You will still be able to call your function, but it will return `None` no matter what!\n",
"
\n",
"\n",
"A function also need not have any additional code beyond its return statement. For example, we can make use of `sum` and a generator comprehension (see the previous section of this module) to shorten our `count_vowels` function:\n",
"\n",
"```python\n",
"# the returned object of a function can be specified straight-away\n",
"def count_vowels(in_string): \n",
" \"\"\" Returns the number of vowels contained in `in_string`\"\"\"\n",
" return sum(1 for char in in_string if char in \"aeiouAEIOU\")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Multiple `return` Statements\n",
"You can specify more than one `return` statement within a function. This can be useful for handling edge-cases or optimizations in your code. Suppose you want your function to compute $e^{x}$, using a [Taylor series](https://en.wikipedia.org/wiki/Taylor_series#Exponential_function) approximation. The function should immediately return `1.0` in the case that $x = 0$:\n",
"\n",
"```python\n",
"def compute_exp(x):\n",
" \"\"\" Use a Taylor Series to compute e^x \"\"\"\n",
" if x == 0:\n",
" return 1.0\n",
"\n",
" from math import factorial\n",
" return sum(x**n / factorial(n) for n in range(100))\n",
"```\n",
"\n",
"If `x==0` is `True`, then the first `return` statement is reached. `1.0` will be returned and the function will be \"exited\" immediately, without ever reaching the code following it."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As stated above, a `return` statement will trigger a function to end its execution immediately when reached, even when subsequent code follows it. *It is impossible for multiple `return` statements to be visited within a single function call*. Thus if you want to return multiple items, then your function must return a single container of those items, like a list or a tuple."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"# Returning multiple items from a function\n",
"def bad_f(x):\n",
" \"\"\" return x**2 and x**3\"\"\"\n",
" return x**2 \n",
" # this code can never be reached!\n",
" return x**3\n",
"\n",
"def good_f(x):\n",
" \"\"\" return x**2 and x**3\"\"\"\n",
" return (x**2, x**3)\n",
"```\n",
"```python\n",
">>> bad_f(2)\n",
"4\n",
"\n",
">>> good_f(2)\n",
"(4, 8)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Inline Functions\n",
"Functions can be defined in-line, as a single return statement:\n",
"\n",
"```python\n",
"def add_2(x):\n",
" return x + 2\n",
"```\n",
"\n",
"can be rewritten as:\n",
"\n",
"```python\n",
"def add_2(x): return x + 2\n",
"```\n",
"\n",
"This should be used sparingly, for exceedingly simple functions that can be easily understood without docstrings."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Arguments\n",
"A sequence of comma-separated variable names can be specified in the function signature to indicated *positional* arguments for the function. For example, the following specifies `x`, `lower`, and `upper` as input arguments to a function, `is_bounded`:\n",
"\n",
"```python\n",
"def is_bounded(x, lower, upper):\n",
" return lower <= x <= upper\n",
"```\n",
"\n",
"This function can then be passed its arguments in several way:\n",
"\n",
"### Specifying Arguments by Position\n",
"The objects passed to `is_bounded` will be assigned to its input variables based on their positions. That is, `is_bounded(3, 2, 4)` will assign `x=3`, `lower=2`, and `upper=4`, in accordance with the positional ordering of the function's input arguments:\n",
"\n",
"```python\n",
"# evaluate: 2 <= 3 <= 4\n",
"# specifying inputs based on position\n",
">>> is_bounded(3, 2, 4)\n",
"True\n",
"```\n",
"\n",
"Feeding a function too few or too many arguments will raise a `TypeError`\n",
"```python\n",
"# too few inputs: raises error\n",
"is_bounded(3)\n",
"\n",
"# too many inputs: raises error\n",
"is_bounded(1, 2, 3, 4)\n",
"```\n",
"\n",
"### Specifying Arguments by Name\n",
"You can provide explicit names when specifying the inputs to a function, in which case ordering does not matter. This is very nice for writing clear and flexible code:\n",
"```python\n",
"# evaluate: 2 <= 3 <= 4\n",
"# specify inputs using explicit input names\n",
">>> is_bounded(lower=2, x=3, upper=4)\n",
"True\n",
"```\n",
"\n",
"You can mix-and-match positional and named input by using position-based inputs first:\n",
"\n",
"```python\n",
"# evaluate: 2 <= 3 <= 4\n",
"# `x` is specified based on position\n",
"# `lower` and `upper` are specified by name\n",
">>> is_bounded(3, upper=4, lower=2)\n",
"True\n",
"```\n",
"\n",
"Note that if you provide a named input, all the inputs following it must also be named:\n",
"\n",
"```python\n",
"# positional arguments cannot follow named arguments\n",
">>> is_bounded(3, lower=2, 4)\n",
"SyntaxError: positional argument follows keyword argument\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Default-Valued Arguments\n",
"You can specify default values for input arguments to a function. Their default values are utilized if a user does not specify these inputs when calling the function. Recall our `count_vowels` function. Suppose we want the ability to include \"y\" as a vowel. We know, however, that people will typically want to exclude \"y\" from their vowels, so we can exclude \"y\" by default:\n",
"\n",
"```python\n",
"def count_vowels(in_string, include_y=False): \n",
" \"\"\" Returns the number of vowels contained in `in_string`\"\"\"\n",
" vowels = \"aeiouAEIOU\"\n",
" if include_y:\n",
" vowels += \"yY\" # add \"y\" to vowels \n",
" return sum(1 for char in in_string if char in vowels)\n",
"```\n",
"\n",
"Now, if only `in_string` is specified when calling `count_vowels`, `include_y` will be passed the value `False` by default:\n",
"\n",
"```python\n",
"# using the default value: exclude y from vowels\n",
">>> count_vowels(\"Happy\")\n",
"1\n",
"```\n",
"\n",
"This default value can be overridden:\n",
"```python\n",
"# overriding the default value: include y as a vowel\n",
">>> count_vowels(\"Happy\", True)\n",
"2\n",
"\n",
"# you can still specify inputs by name\n",
">>> count_vowels(include_y=True, in_string=\"Happy\")\n",
"2\n",
"```\n",
"\n",
"Default-valued input arguments must come after all positional input arguments in the function signature:\n",
"```python\n",
"# this is ok\n",
"def f(x, y, z, count=1, upper=2):\n",
" return None\n",
"```\n",
"\n",
"```python\n",
"# this will raise a syntax error\n",
"def f(x, y, count=1, upper=2, z):\n",
" return None\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**Reading Comprehension: Functions and Arguments**\n",
"\n",
"Write a function, `max_or_min`, which accepts two positional arguments, `x` and `y` (which will hold numerical values), and a `mode` variable that has the default value `\"max\"`. \n",
"\n",
"The function should return `min(x, y)` or `max(x, y)` according to the `mode`. Have the function return `None` if `mode` is neither `\"max\"` nor `\"min\"`. \n",
"\n",
"Include a descriptive doc-string.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Accommodating an Arbitrary Number of Positional Arguments\n",
"Python provides us with a syntax for defining a function, which can be called with an arbitrary number of positional arguments. This is signaled by the syntax `def f(*)`.\n",
"\n",
"```python\n",
"# The * symbol indicates that an arbitrary number of\n",
"# arguments can be passed to `args`, when calling `f`.\n",
"def f(*args):\n",
" # All arguments passed to `f` will be \"packed\" into a \n",
" # tuple that is assigned to the variable `args`.\n",
" # `f()` will assign `args = tuple()`\n",
" # `f(x, y, ...)` will assign `args = (x, y, ...)`\n",
" return args\n",
"```\n",
"\n",
"Because Python cannot foresee how many arguments will be passed to `f`, all of the objects that are passed to it will be *packed into a tuple*, which is then assigned to the variable `args`:\n",
"\n",
"```python\n",
"# pass zero arguments to `f`\n",
">>> f() \n",
"()\n",
"\n",
"# pass one argument to `f`\n",
">>> f(1) \n",
"(1,)\n",
"\n",
"# pass three arguments to `f`\n",
">>> f((0, 1), True, \"cow\") \n",
"((0, 1), True, \"cow\")\n",
"```\n",
"\n",
"This syntax can be combined with positional arguments and default arguments. Any variables specified after a packed variable *must be called by name*:\n",
"```python\n",
"def f(x, *seq, y):\n",
" print(\"x is: \", x)\n",
" print(\"seq is: \", seq)\n",
" print(\"y is: \", y)\n",
" return None\n",
"```\n",
"```python\n",
">>> f(1, 2, 3, 4, y=5) # `y` must be specified by name\n",
"```\n",
"```\n",
"x is: 1\n",
"seq is: (2, 3, 4)\n",
"y is: 5\n",
"```\n",
"```python\n",
">>> f(\"cat\", y=\"dog\") # no additional positional arguments are passed\n",
"```\n",
"```\n",
"x is: \"cat\"\n",
"seq is: ()\n",
"y is: \"dog\"\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"**Reading Comprehension: Arbitrary Arguments**\n",
"\n",
"Write a function named `mean`, which accepts and arbitrary number of numerical arguments, and computes the mean of all of the values passed to the function. Thus `mean(1, 2, 3)` should return $\\frac{1 + 2 + 3}{3} = 2.0$ \n",
"\n",
"This function should return `0.` if no arguments are passed to it. Be sure to test your function, and include a docstring.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that `*` indicates the *packing of an arbitrary number of arguments into a tuple*, when used in the signature of a function definition. Simultaneously, `*` signals the *unpacking of an iterable* to pass each of its members as a positional argument to a function, when used in the context of calling a function:\n",
"\n",
"```python\n",
"# Using `*` when calling a function, to unpack an \n",
"# iterable. Passing its members as distinct arguments \n",
"# to the function\n",
"\n",
"def f(x, y, z):\n",
" return x + y + z\n",
"\n",
">>> f(1, 2, 3)\n",
"6\n",
"\n",
"# `*` means: unpack the contents of [1, 2, 3]\n",
"# passing each item as x, y, and z,\n",
"# respectively\n",
">>> f(*[1, 2, 3]) # equivalent to: f(1, 2, 3)\n",
"6\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the following example, we use `*` to: \n",
"\n",
" 1. Define a function to accept an arbitrary\n",
" number of arguments, which get packed into a tuple.\n",
" 2. Call the function, passing it an arbitrary \n",
" number of arguments, by unpacking an iterable."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"def number_of_args(*args):\n",
" return len(args)\n",
"```\n",
"```python\n",
">>> number_of_args(None, None, None, None)\n",
"4\n",
"\n",
">>> some_list = [1, 2, 3, 4, 5]\n",
"\n",
"# passing the list itself as the sole argument\n",
">>> number_of_args(some_list)\n",
"1\n",
"\n",
"# unpacking the 5 members of the list, \n",
"# passing each one as an argument to the function\n",
">>> number_of_args(*some_list)\n",
"5\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Accommodating an Arbitrary Number of Keyword Arguments\n",
"We can also define a function that is able to accept an arbitrary number of *keyword* arguments, using the syntax: `def f(**)` \n",
"\n",
"Note that a single asterisk, `*`, was used to denote an arbitrary number of *positional* arguments, whereas `**` signals the acceptance of an arbitrary number of *keyword* arguments. \n",
"\n",
"```python\n",
"# The ** symbol indicates that an arbitrary number of\n",
"# keyword arguments can be passed to `args`, when calling `f`.\n",
"def f(**args):\n",
" # All keyword arguments passed to `f` will be \"packed\" into a \n",
" # dictionary that is assigned to the variable `args`.\n",
" # `f()` will assign `args = {}` (an empty dictionary)\n",
" # `f(x=1, y=2, ...)` will assign `args = {\"x\":1, \"y\":2, ...}`\n",
" return args\n",
"```\n",
"\n",
"Because Python cannot foresee how many arguments will be passed to `f`, all of the keyword arguments that are passed to it will be packed into a *dictionary*, where a given keyword is set as a key (cast as a string) that maps to the corresponding value. This dictionary is then assigned to the variable `args`. Dictionaries will be discussed in detail in a [later section](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html).\n",
"\n",
"```python\n",
">>> f() # pass zero arguments to `f`\n",
"{}\n",
"\n",
">>> f(x=1) # pass one argument to `f`\n",
"{'x': 1}\n",
"\n",
">>> f(x=(0, 1), val=True, moo=\"cow\") # pass three arguments to `f`\n",
"{'moo': 'cow', 'val': True, 'x': (0, 1)}\n",
"```\n",
"\n",
"This syntax can be combined with positional arguments and default arguments. No additional arguments may come after a `**` entry in a function-definition signature:\n",
"```python\n",
"def f(x, y=2, **kwargs):\n",
" print(\"x is: \", x)\n",
" print(\"y is: \", y)\n",
" print(\"kwargs is: \", kwargs)\n",
" return None\n",
"```\n",
"```python\n",
"# passing arbitrary keyword arguments to `f`\n",
">>> f(1, y=9, z=3, k=\"hi\")\n",
"```\n",
"```\n",
"x is: 1\n",
"y is: 9\n",
"kwargs is: {'z': 3, 'k': 'hi'}\n",
"```\n",
"```python\n",
"# no additional keyword arguments are passed\n",
">>> f(\"cat\", y=\"dog\") \n",
"```\n",
"```\n",
"x is: cat\n",
"y is: dog\n",
"kwargs is: {}\n",
"```\n",
"\n",
"The following function accepts an arbitrary number of positional arguments *and* an arbitrary number of keyword arguments:\n",
"\n",
"```python\n",
"# accepting arbitrary positional and keyword arguments\n",
"def f(*x, **y):\n",
" # all positional arguments get packed into the tuple `x`\n",
" # all keyword arguments get packed into the dictionary `y` \n",
" print(x) \n",
" print(y)\n",
" return None\n",
"\n",
">>> f(1, 2, 3, hi=-1, bye=-2, sigh=-3)\n",
"```\n",
"```\n",
"(1, 2, 3)\n",
"{'hi': -1, 'bye': -2, 'sigh': -3}\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that `**` indicates the *packing of an arbitrary number of keyword arguments into a dictionary*, when used in the signature of a function definition. Simultaneously, `**` signals the *unpacking of a dictionary* to pass each of its key-value pairs as a keyword argument to a function, when used in the context of calling a function:\n",
"\n",
"```python\n",
"# Using `**` when calling a function, to unpack a \n",
"# dictionary, passing its members as keyword arguments \n",
"# to the function\n",
"def f(x, y, z):\n",
" return 0*x + 1*y + 2*z\n",
"\n",
">>> f(z=10, x=9, y=1)\n",
"21\n",
"\n",
">>> args = {\"x\": 9, \"y\": 1, \"z\": 10}\n",
">>> f(**args) # equivalent to: f(x=9, y=1, z=10)\n",
"21\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the following example, we use `**` to: \n",
"\n",
" 1. Define a function to accept an arbitrary\n",
" number of keyword arguments, which get packed into a dictionary.\n",
" 2. Call the function, passing it an arbitrary \n",
" number of keyword arguments, by unpacking a dictionary."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"def print_kwargs(**args):\n",
" print(args)\n",
"```\n",
"```python\n",
">>> print_kwargs(a=1, b=2, c=3, d=4)\n",
"{'a': 1, 'b': 2, 'c': 3, 'd': 4}\n",
"\n",
">>> some_dict = {\"hi\":1, \"bye\":2}\n",
"\n",
"# unpacking the key-value pairs of the dictionary\n",
"# as keyword arguments and values, to the function\n",
">>> print_kwargs(a=2, umbrella=True, **some_dict)\n",
"{'a': 2, 'umbrella': True, 'hi': 1, 'bye': 2}\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Functions are Objects\n",
"Once defined, a function behaves like any other Python object, like a list or string or integer. You can assign a variable to a function-object:\n",
"```python\n",
">>> var = count_vowels # `var` now references the function `count_vowels`\n",
">>> var(\"Hello\") # you can now \"call\" `var`\n",
"2\n",
"```\n",
"\n",
"You can store functions in a list:\n",
"```python\n",
"my_list = [count_vowels, print]\n",
"\n",
"for func in my_list:\n",
" func(\"hello\")\n",
" \n",
"# iteration 0: calls `count_vowels(\"hello\")` \n",
"# iteration 1: calls `print(\"hello\")`\n",
"```\n",
"\n",
"You can also call functions anywhere, and their return-value will be returned in-place:\n",
"```python\n",
"if count_vowels(\"pillow\") > 1:\n",
" print(\"that's a lot of vowels!\")\n",
"```\n",
"\n",
"And, of course, this works within comprehension expressions as well:\n",
"```python\n",
">>> sum(count_vowels(word, include_y=True) for word in [\"hi\", \"bye\", \"guy\", \"sigh\"])\n",
"6\n",
"```\n",
"\n",
"\"Printing\" a function isn't very revealing. It simply tells you the memory address where the function-object is stored:\n",
"```python\n",
">>> print(count_vowels)\n",
"\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Links to Official Documentation\n",
"\n",
"- [Definition of 'function'](https://docs.python.org/3/library/stdtypes.html#functions)\n",
"- [Defining functions](https://docs.python.org/3/tutorial/controlflow.html#defining-functions)\n",
"- [Default argument values](https://docs.python.org/3/tutorial/controlflow.html#default-argument-values)\n",
"- [Keyword arguments](https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments)\n",
"- [Specifying arbitrary arguments](https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists)\n",
"- [Unpacking arguments](https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists)\n",
"- [Documentation strings](https://docs.python.org/3/tutorial/controlflow.html#documentation-strings)\n",
"- [Function annotations](https://docs.python.org/3/tutorial/controlflow.html#function-annotations)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reading Comprehension Exercise Solutions:\n",
"\n",
"**Writing a Basic Function: Solution**\n",
"\n",
"```python\n",
"def count_even(numbers):\n",
" \"\"\" Counts the number of even integers in an iterable\"\"\"\n",
" total = 0\n",
" for num in numbers:\n",
" if num % 2 == 0:\n",
" total += 1\n",
" return total\n",
"```\n",
"or, using a generator comprehension:\n",
"\n",
"```python\n",
"def count_even(numbers):\n",
" \"\"\" Counts the number of even integers in an iterable\"\"\"\n",
" return sum(1 for num in numbers if num % 2 == 0)\n",
"```\n",
"\n",
"**Functions and Arguments: Solution**\n",
"\n",
"```python\n",
"def max_or_min(x, y, mode=\"max\"):\n",
" \"\"\" Return either `max(x,y)` or `min(x,y)`,\n",
" according to the `mode` argument.\n",
" \n",
" Parameters\n",
" ----------\n",
" x : Number\n",
" \n",
" y : Number\n",
" \n",
" mode : str\n",
" Either 'max' or 'min'\n",
" \n",
" Returns\n",
" -------\n",
" The max or min of the two values. `None` is\n",
" returned if an invalid mode was specified.\"\"\"\n",
" if mode == \"max\":\n",
" return max(x, y)\n",
" elif mode == \"min\":\n",
" return min(x, y)\n",
" else:\n",
" return None\n",
"```\n",
"\n",
"Note that you can actually have your function raise an \"exception\" (an error) in the case that `mode` wasn't passed a proper value. In fact, that is likely the more appropriate behavior for this function. \n",
"\n",
"Such a solution would look like:\n",
"```python\n",
"def max_or_min(x, y, mode=\"max\"):\n",
" if mode == \"max\":\n",
" return max(x, y)\n",
" elif mode == \"min\":\n",
" return min(x, y)\n",
" else:\n",
" raise Exception(\"`mode` was passed an invalid value: {}\".format(mode))\n",
"```\n",
"\n",
"**Arbitrary Arguments: Solution**\n",
"\n",
"```python\n",
"def mean(*seq):\n",
" \"\"\" Returns the mean of the function's arguments \"\"\"\n",
" if len(seq) == 0:\n",
" return 0\n",
" \n",
" total = 0 \n",
" for num in seq:\n",
" total += num\n",
" return total / len(seq)\n",
"```\n",
"\n",
"or, being a bit more fancy :\n",
"\n",
"- using the fact that `bool(seq)` is `False` if `seq` is empty\n",
"- using the inline if-else syntax\n",
"\n",
"```python\n",
"def mean(*seq):\n",
" \"\"\" Returns the mean of the function's arguments \"\"\"\n",
" return sum(seq) / len(seq) if seq else 0\n",
"```"
]
}
],
"metadata": {
"jupytext": {
"text_representation": {
"extension": ".md",
"format_name": "markdown",
"format_version": "1.3",
"jupytext_version": "1.13.6"
}
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}