12. Programowanie funkcyjne

12.1. Rekurencja

  • warunek zakończenia
  • maksymalna ilość zagłębień
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

12.2. Lambda - funkcje anonimowe

lista = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


def parzystosc(x):
    if x % 2 == 0:
        return True
    else:
        return False


parzyste1 = filter(lambda x: x % 2 == 0, lista)
parzyste2 = filter(parzystosc, lista)

print(list(parzyste1))
print(list(parzyste2))
class Osoba:
    pass

o = Osoba()
o.say_hello = lambda: print('hello')

o.say_hello()

12.3. Closure

def f(x):
    def g(y):
        return x + y
    return g

12.4. Monady

12.5. złożenia funkcji

12.5.1. map()

lista = [1, 2, 3]

def inkrementuj(y):
    return 1 + y

map(inkrementuj, lista)
map(lambda y: 1 + y, l)
def kwadrat(x):
    return pow(x, 2)

potegi1 = map(kwadrat, dane)
potegi2 = map(lambda x: pow(x, 2), dane)

print(list(potegi1))
import datetime

def opoznienie(przesuniecie):
    delay = pow(przesuniecie, 2)
    return datetime.datetime.now() + datetime.timedelta(seconds=delay)

czasy = map(opoznienie, dane)

print(list(czasy))

12.5.2. zip()

>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> list(zipped)
[(1, 4), (2, 5), (3, 6)]
>>> # unzip
>>> x2, y2 = zip(*zip(x, y))
>>> x == list(x2) and y == list(y2)
True

12.5.3. filter()

OSOBY = [
    {'imie': 'José', 'wiek': 10},
    {'imie': 'Max', 'wiek': 18},
    {'imie': 'Ivan', 'wiek': 21},
]

def osoba_pelnoletnia(osoba):
    if osoba['wiek'] >= 18:
        return True
    else:
        return False


dorosli = filter(osoba_pelnoletnia, OSOBY)
print(list(dorosli))
def parzysta(liczba):
    if liczba % 2 == 0:
        return True
    else:
        return False


dane = range(0, 30)

parzyste1 = filter(parzysta, dane)
parzyste2 = filter(lambda x: x % 2 == 0, dane)
parzyste3 = filter(lambda x: not x % 2, dane)

print(list(parzyste3))

12.5.4. all(iterable)

Return True if all elements of the iterable are true (or if the iterable is empty). Equivalent to:

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True

12.5.5. any(iterable)

Return True if any element of the iterable is true. If the iterable is empty, return False. Equivalent to:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False

12.5.6. enumerate(iterable, start=0)

Return an enumerate object. iterable must be a sequence, an iterator, or some other object which supports iteration. The __next__() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over iterable.

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

Equivalent to:

def enumerate(sequence, start=0):
    n = start
    for elem in sequence:
        yield n, elem
        n += 1

12.6. functools

12.6.1. memoize

import functools

@functools.lru_cache(maxsize=None)
def fib(num):
    if num < 2:
        return num
    else:
        return fib(num-1) + fib(num-2)
def factorial(n):
    if not hasattr(factorial, 'mem'):
        factorial.mem = {1: 1}
    if not n in factorial.mem:
        factorial.mem[n] = n * factorial(n - 1)
    return factorial.mem[n]
def memoize(function):
    from functools import wraps

    memo = {}

    @wraps(function)
    def wrapper(*args):
        if args in memo:
            return memo[args]
        else:
            rv = function(*args)
            memo[args] = rv
            return rv
    return wrapper


@memoize
def fibonacci(n):
    if n < 2: return n
    return fibonacci(n - 1) + fibonacci(n - 2)

fibonacci(25)

12.7. Zadania kontrolne

12.7.1. map(), filter() i lambda

Używając generatora zbuduj listę zawierającą wszystkie liczby podzielne przez 3 z zakresu od 1 do 33:

  • Używając funkcji filter() usuń z niej wszystkie liczby parzyste
  • Używając wyrażenia lambda i funkcji map() podnieś wszystkie elementy tak otrzymanej listy do sześcianu
  • Odpowiednio używając funkcji sum() i len() oblicz średnią arytmetyczną z elementów tak otrzymanej listy.

12.7.2. Zbalansowanie nawiasów

Napisz kod, który za pomocą rekurencji sprawdzi zbalansowanie nawiasów, tzn. czy ilość otwieranych nawiasów jest równa ilości nawiasów zamykanych. Zwórć uwagę, że mogą być cztery typy nawiasów:

  • okrągłe: ( i )
  • kwadratowe: [ i ]
  • klamrowe { i }
  • trójkątne < i >
>>> zbalansowanie_nawiasow("() [] () ([]()[])")
True

>>> zbalansowanie_nawiasow("( (] ([)]")
False