Functions


Functions

  • simple example:
def square(x):
    return x * x

square(5)
  • None is returned when using return without parameter and implicit return value at end of function
def even_or_odd(n):
    if n % 2 == 0:
        print("even")
        return
    print("odd")

w = even_or_odd(31)
#=> odd
w is None
#=> True
  • longer example
def nth_root(radicand, n):
    return radicand ** (1/n)

def ordinal_suffix(value):
    s = str(value)
    if s.endswith('11'):
        return 'th'
    elif s.endswith('12'):
        return 'th'
    elif s.endswith('13'):
        return 'th'
    elif s.endswith('1'):
        return 'st'
    elif s.endswith('2'):
        return 'nd'
    elif s.endswith('3'):
        return 'rd'
    return 'th'

def ordinal(value):
    return str(value) + ordinal_suffix(value)

def display_nth_root(radicand, n):
    root = nth_root(radicand, n)
    message = "The " + ordinal(n) + " root of " \
        + str(radicand) + " is " + str(root)
    print(message)
  • special functions follow naming procedure: __<function_name>__
    • referred to as dunder (portmanteau of "double underscore")
    • given function __init__, it would be referred to as "dunder init"

__name__

Python idiom of __name__

  • specially named variable that allows us to determine if module is run as script or imported into another module
  • module code is only executed once on initial import
from urllib.request import urlopen

def fetch_words():
    story = urlopen('http://sixty-north.com/c/t.txt')
    story_words = []

    for line in story:
        line_words = line.decode('utf8').split()
        for word in line_words:
            story_words.append(word)
    story.close()

    for word in story_words:
        print(word)

print(__name__)
# prints `words` in Python REPL env
# prints `__main__` in shell env

if __name__ == '__main__':
    fetch_words()

Detecting callable objects:

def is_even(x):
    return x % 2 == 0

callable(is_even)
#=> True

Making instances of classes callable(?)

class CallMe:
    def __call__(self):
        print("Called!")

call_me = CallMe()
callable(call_me)
#=> True

Extended formal argument syntax

def extended(*args, **kwargs):
  1. 'star args' must come before 'k w args'
  2. any arguments preceding 'star args' will be considered positional arguments
  3. any arguments after 'star args' will be mandatory keyword arguments
  4. if 'k w args' is present, it must be last in arguments list

'star args'

  • handles positional arguments
def hypervolume(*lengths):
    print(f"lengths: {lengths}")
    print(f"type: {type(lengths)}")

    i = iter(lengths)
    v = next(i)
    for length in i:
        v *= length
    return v

### or better yet, making sure a meaningful
# exception gets thrown if called without arguments
def hypervolume(length, *lengths):
    print(f"lengths: {lengths}")
    print(f"type: {type(lengths)}")

    v = length
    for item in lengths:
        v *= item
    return v

'k w args' (KWARGS)

  • handles keyword arguments
  • keyword args passed to kwargs as dictionary
def example(name, **kwargs):
    print(f"name: {name}")
    print("kwargs: ")
    print(kwargs)
    print(f"type of kwargs: {type(kwargs)}")


def tag(name, **attributes):
    result = '<' + name
    for key, value in attributes.items():
        result += ' {k}="{v}"'.format(k=key, v=str(value))
    result += '/>'
    return result

Extended actual argument syntax

'star args'

def print_args(arg1, arg2, *args):
    print(arg1)
    print(arg2)
    print(arg3)

t = (11, 12, 13, 14)
print(*t)
#=> 11
#=> 12
#=> (13, 14)

'k w args'

def color(red, green, blue, **kwargs):
    print("r = ", red)
    print("g = ", green)
    print("b = ", blue)
    print(kwargs)

k = {'red': 21, 'green': 68, 'blue': 120, 'alpha': 52}
color(**k)
#=> r = 21
#=> g = 68
#=> b = 120
#=> {'alpha': 52}

Forwarding Arguments using *args and **kwargs

def trace(f, *args, **kwargs):
    print("args = ", args)
    print("kwargs = ", kwargs)
    result = f(*args, **kwargs)
    print("result = ", result)
    return result

Example using zip()

sunday = [2, 3, 4, 5, 6]
monday =[11, 12, 13, 14, 15]
tuesday = [5, 4, 3, 2, 1]
daily = [sunday, monday, tuesday]

### all do the same thing
for item in zip(sunday, monday, tuesday):
    print(item)

for item in zip(daily[0], daily[1], daily[2]):
    print(item)

for item in zip(*daily):
    print(item)

### result from `print` in `for` loop as single data structure
transposed = list(zip(*daily)) #=> list of tuples

Local Functions

  • generally refers to functions defined inside of other functions
def func():
    def local_func():
        a = 'hello'
        b = 'world'
        return a + b

    x = 1
    y = 2
    return x + y

Returning Function from Function

def outer():
    def inner():
        print('inner')
    return inner

example = outer()
example()
#=> inner

First-class Functions

  • functions can be treated like any other object
Made with Gatsby G Logo