<jupyter_start><jupyter_text>Table of Contents 1&nbsp;&nbsp;arbitrary number of arguments2&nbsp;&nbsp;arbitrary keyward arguments3&nbsp;&nbsp;functions that return multiple values4&nbsp;&nbsp;python function argument expansion<jupyter_code>def function_name(arg0, arg1):
    """Function Documentation, aka docstring"""
    function_stuff = arg0 + arg1
    # return is optional
    # if no, return it will return None
    # python functions always return something
    return(function_stuff)
function_name?
# no type declaration
# because python is a dynamically typed language
def my_add(x, y):
    """add values"""
    return(x + y)
my_add(1, 4)
my_add('hello', 'world')
my_add([1, 2, 3], [4, 5, 6])
my_add('123', 123)
my_add(1)
# we just delt with positional arguments
my_add(x='hello', y='world')
my_add(y='world', x='hello')
def my_func_default(x, y, z='foo'):
    return(x + y + z)
my_func_default('hello', 'world')
my_func_default('hello', 'world', 'again')
my_func_default('hello', 'world', z='again')
my_func_default('hello', 'world', a='again')<jupyter_output><empty_output><jupyter_text>arbitrary number of arguments<jupyter_code>def my_add_args(x, *args):
    total = x
    for arg in args:
        total += arg
    return(total)
my_add_args(5)
my_add_args(1, 2, 3, 4, 5)<jupyter_output><empty_output><jupyter_text>arbitrary keyward arguments<jupyter_code>my_dict = {'name':'daniel'}
my_dict
my_dict.items()
for thing1, thing2 in my_dict.items():
    print(thing1, thing2)
def my_add_kwargs(x, **kwargs):
    total = x
    for arg, value in kwargs.items():
        print(arg, value)
        total += value
    return(total)
my_add_kwargs(1, b=2, c=3)<jupyter_output>b 2
c 3<jupyter_text>functions that return multiple values<jupyter_code># return a tuple
# and use multiple assignment to catch the return values
def func_mult_returns(x, y):
    """returns the square of x and the square of y"""
    square_x = x**2
    square_y = y **2
    return square_x, square_y
func_mult_returns(2, 3)
type(func_mult_returns(2, 3))
x, y = func_mult_returns(2, 3)
print(x, y)
a, b, c = [1, 2, 3]
print(a, b, c)<jupyter_output>1 2 3<jupyter_text>python function argument expansion<jupyter_code>def my_add(x, y):
    return x + y
tup = (1, 2)
tup
my_add(*z)
my_dict = {'x':1, 'y':2}
my_dict
my_add(**my_dict)<jupyter_output><empty_output>