<jupyter_start><jupyter_text>PYTHON 3 Функции, генераторы, декораторыMIPT 2020 Еще немного о __collections__<jupyter_code>from collections import OrderedDict

d = OrderedDict([(1, 3), (3, 1), (2, 2)])
dict(d)
d.popitem(last=False)
d.popitem()
d.popitem()
d.popitem()

d = dict([(1, 3), (3, 1), (2, 2)])

for k, v in d.items():
    k, v<jupyter_output><empty_output><jupyter_text>Из документации:Performing list(d) on a dictionary returns a list of all the keys used in the dictionary, in insertion order  Функции  Аргументы<jupyter_code>def hello():
    print("hello world")

hello()

def i_return_two_plus_x(x: int) -> int:  # just for static linters
    return 2 + x

i_return_two_plus_x(4)

def some_args(a, b, c, d=2, e=4):
    return a + b + c + d + e

some_args(1, 2, 3)
some_args(1, 2, 3, 4, 5)
some_args(1, 2, c=3, d=4, e=5)
some_args(1, 2, 3, 5, d=7)

def more_args(a, b=3, *, d, c=3):
    return a + b + c + d

more_args(1, b=2, c=3, d=4)
more_args(1, c=2, d=1)
more_args(1, 2, 3, 4)

# python3.8
def args(a, /, b, *, c):
    ...

def f(x):
    return x

def f(x, y):
    return x, y

f(1, 2)
f(1)

def anything(f, *args, **kwargs):
    print(args)
    print(kwargs, kwargs['a'], sep='\n')

anything(1, 2, 3, a=4, b=5)

def test_mutability(x):
    x.append(2)
    print(id(x))
    x = 173
    print(id(x))

x = [1]
id(x)
test_mutability(x)
id(x)
x<jupyter_output><empty_output><jupyter_text>Звездочка __только__ распаковывает iterable в аргументы функции<jupyter_code>def so_many_args(a, b, c, d, e, f, g, h, i, *args, j=0, k=0):
    return a + b + c + d + e + f + g + h + i + j + k

so_many_args(*[1, 2, 3, 4, 5, 6, 7, 8, 9], **{'j': 10, 'k': 11})<jupyter_output><empty_output><jupyter_text>Рекурсия<jupyter_code>import sys

sys.setrecursionlimit(3000)

def fact(n):
    if n <= 1:
        return 1
    return n * fact(n - 1)

fact(10)
fact(100)
fact(2950)

sys.getrecursionlimit()
sys.setrecursionlimit(100)

fact(200)

def f(n):
    if n < 2:
        return n
    return g(n - 1) + 1

def g(n):
    if n < 2:
        return n
    return f(n - 1) + 2

f(5)<jupyter_output><empty_output><jupyter_text>Генераторы<jupyter_code>def squared(a):
    for x in a:
        yield x ** 2

a = list(range(10))
for elem in squared(a):
    print(elem, end=' ')

func = squared
func
generator = func(a)
generator
next(generator, None)

while True:
    print(next(generator), end=' ')

generator = func(a)
while True:
    try:
        elem = next(generator)
        # loop body
        print(elem, end=' ')
    except StopIteration:
        break

def yielder3():
    for i in range(10):
        yield i

def yielder2():
    for elem in yielder3():
        yield elem

def yielder1():
    yield from yielder2()  # Передает управление второму генератору, 
                           # пока он не исчерпается

for x in yielder1():
    print(x, end=' ')

def cumsum():
    csum = 0.0
    while True:
        csum += yield csum  # Вообще говоря это уже корутина

arr = [1.0 + x / 2 for x in range(10)]
arr
gen = cumsum()
gen
gen.send(None) # equal to next(gen)
for elem in arr:
    print(gen.send(elem), end=' ')

for elem in gen:
    print("Can reach?")<jupyter_output><empty_output><jupyter_text>Области видимости<jupyter_code>x = 2  # global

def func(a):
    x = 4  # local
    return a + x

func(1)
x

hw = 'hello world'
def hello():
    global hw  # можно явно указать и менять отсюда
    hw = 'broken, fix pls'
    print(hw)

hello()
hw

def hello2():
    global hw
    hw = 'fixed, dont worry'

hello2()
hw

def hello2():
    nonlocal hw
    hw = 'fixed, dont worry'<jupyter_output>broken, fix pls<jupyter_text>Замыкания<jupyter_code>def outer(x):
    z = x
    def inner(y):
        nonlocal z
        return z * y
    return inner

multiply_by_3 = outer(3)
multiply_by_3(4)
outer(3)(4)<jupyter_output><empty_output><jupyter_text>Функция тоже объект!<jupyter_code>multiply_by = [outer(x) for x in range(10)]
multiply_by[3](5)
multiply_by[6](10)<jupyter_output><empty_output><jupyter_text>Декораторы<jupyter_code>def salad(f):
    def internal(*args):
        print("salad")
        f(*args)
    return internal

def bread(f):
    def internal():
        print("bread")
        f()
        print("bread")
    return internal

def tomato(f):
    def internal():
        print("tomato")
        f()
    return internal

def f():
    print("beef")

sandwich = bread(salad(tomato(f)))
sandwich()<jupyter_output>bread
salad
tomato
beef
bread<jupyter_text>Так люди придумали декораторы<jupyter_code>@bread
@salad
@tomato
def g():
    print("chicken")

g()  
# то же самое что g = bread(salad(tomato(g)))

g.__name__, g.__repr__()<jupyter_output><empty_output><jupyter_text>Лучше не затирать эти поля<jupyter_code>from functools import wraps

def bread(h):
    @wraps(h)
    def internal():
        print("bread")
        h()
        print("bread")
    return internal

@bread
def h():
    print("fish")
    
h()
h.__name__, h.__repr__()<jupyter_output>bread
fish
bread<jupyter_text>Лямбда-функции<jupyter_code>applier1 = lambda f, x: f(x)

def apply(f, x):
    return f(x)

applier2 = apply

applier1(sum, [1, 2, 3])
applier2(sum, [1, 2, 3])

a = [(1, 5), (3, 1), (7, 20), (9, 11)]
sorted(a, key=sum)<jupyter_output><empty_output><jupyter_text>Summary<jupyter_code># function
def f():
    return 'f'
f.__call__()
f.__call__ = lambda: 'f new'
f.__call__()

# generator
def g():  # function
    yield 'g'
it = g.__call__()  # get generator
it.__next__()  # iterate

# coroutine
def h():
    s = yield 'h'
    yield s
it = h.__call__() # get coroutine
it.__next__() # first iteration
it.send('hey')

dir(f)

f.__code__<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15073594608973223, 'fraction_numerical': 0.02979251640361766, 'mean_word_length': 3.427001569858713, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '151204', 'license': 'MIT', 'n_tokens_mistral': 2495, 'n_tokens_neox': 2422, 'n_words': 601, 'path': 'seminars/04_func_gen_iter/.ipynb_checkpoints/Seminar_04-checkpoint.ipynb', 'repo_name': 'Vemmy124/PythonSeminarsMIPT2020', 'size': '5639'}