Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Декораторы в Python (2)

Cogwheelhead
November 17, 2018
91

Декораторы в Python (2)

Обновлённая версия презентации
https://speakerdeck.com/cogwheelhead/python-decorators

Cogwheelhead

November 17, 2018
Tweet

Transcript

  1. def func(*args, **kwargs): print(type(args), args) print(type(kwargs), kwargs) func(1, 2, 3,

    a=1, b=2, c=3) >>> <class 'tuple'> (1, 2, 3) <class 'dict'> {'a': 1, 'b': 2, 'c': 3}
  2. first, second, *other = [1, 2, 3, 4, 5] print(first,

    second, other) >>> 1 2 [3, 4, 5] first, second, *other = (1, 2, 3, 4, 5) print(first, second, other) >>> 1 2 [3, 4, 5]
  3. def sum_of_three(a, b, c): return a + b + c

    three = [1, 2, 3] print(sum_of_three(*three)) >>> 6
  4. def identity(x): '''Identity function''' return x f = identity for

    attribute in (f.__name__, f.__doc__, f.__module__, f.__class__): print(attribute) >>> identity Identity function __main__ <class 'function'>
  5. def add_f(x, y): return x + y add_l = lambda

    x, y: x + y print(add_f(17, 25), add_l(29, 13), (lambda x, y: x + y)(11, 31)) >>> 42 42 42
  6. def a(a_arg): a_var = 20 def inner(inner_arg): inner_var = 42

    def innermost(innermost_arg): innermost_var = 101 def b(b_arg): b_var = 31415
  7. xs = [3, 14, 15, 92, 65] max_index = max((0,

    1, 2, 3, 4), key=lambda i: xs[i]) print(max_index) >>> 3
  8. def D(f): def derivative(x): return (f(x + 0.00001) - f(x))

    / 0.00001 return derivative def f(x): return x**2 g = D(f) print(g(5)) >>> 10.000009999799886
  9. def make_greeter(phrase): prefix = phrase + ', ' def greeter(name):

    return prefix + name return greeter casual_greeter = make_greeter('Hello') informal_greeter = make_greeter('Sup') mysterious_greeter = make_greeter('So we meet again')
  10. from time import time tmp = time() func1('<...>') print('func1 execution

    time:', time() - tmp) from time import time tmp = time() func2('<...>') print('func2 execution time:', time() - tmp)
  11. def execution_time(func, *args, **kwargs): from time import time tmp =

    time() func(*args, **kwargs) return time() - tmp
  12. def print_execution_time(func, *args, **kwargs): from time import time tmp =

    time() result = func(*args, **kwargs) print(fun.__name__, 'executed; time:', time() - tmp) return result smth1 = print_execution_time(func1, '<...>') smth2 = print_execution_time(func2, '<...>')
  13. def func1('<...>'): # заменим имя func1 на dreamfunc1 from time

    import time tmp = time() '<...>' print('func1 executed; time:', time() - tmp) return '<...>' def func2('<...>'): # заменим имя func2 на dreamfunc2 from time import time tmp = time() '<...>' print('func2 executed; time:', time() - tmp) return '<...>'
  14. def make_dreamfunc(func): def dreamfunc(*args, **kwargs): tmp = time() result =

    func(*args, **kwargs) print(func.__name__, 'executed, time:', time() - tmp) return result return dreamfunc dreamfunc1 = make_dreamfunc(func1) dreamfunc2 = make_dreamfunc(func2)
  15. def timed(func): def timed_func(*args, **kwargs): tmp = time() result =

    func(*args, **kwargs) print(func.__name__, 'executed, time:', time() - tmp) return result return timed_func t_func1 = timed(func1) t_func2 = timed(func2)
  16. @decorator def func('<...>'): '<...>' # то же, что и def

    func('<...>'): '<...>' func = decorator(func)
  17. @sends_emails_to_bob @logged @timed def fibonacci_number(n): '<...>' # здесь считается result

    return result # vs def fibonacci_number(n): from time import time tmp = time() logs = open('logs.txt', a) '<...>' # здесь считается result execution_time = time() - tmp logs.write(func.__name__, execution_time) print('fibonacci_number executed; time:', execution_time_) send_email_to_bob('Hey! Check out how fast it is! ', execution_time) return result
  18. def memoized(func): memory = {} def wrapper(*args, **kwargs): key =

    (args, tuple(sorted(kwargs.items()))) if key not in memory: memory[key] = func(*args, **kwargs) return memory[key]) return wrapper
  19. @flip def div(x, y, show=False): res = x / y

    if show: print(res) return res div(2, 4, show=True) >>> 2.0
  20. @introduce_on_debug def identity(x): return x # включена оптимизация (программа запушена

    с флагом -O) identity(239) >>> 239 # в противном случае identity(57) >>> identity 57
  21. def decorator(func): def wrapper(*args, **kwargs): '<...>' return func(*args, **kwargs) wrapper.__name__

    = func.__name__ wrapper.__doc__ = func.__doc__ '<...>' return wrapper
  22. def is_wrapper(wrapper, func): wrapper.__name__ = func.__name__ wrapper.__doc__ = func.__doc__ '<...>'

    def decorator(func): def wrapper(*args, **kwargs): '<...>' return fun(*args, **kwargs) is_wrapper(wrapper, func) return wrapper
  23. # используем “внешний” параметр n def introduce(func): @wraps(func) def wrapper(*args,

    **kwargs): print((func.__name__ + '\n') * n) return func(*args, **kwargs) return wrapper
  24. # предоставляем параметр n def make_introduce(n): def introduce(func): @wraps(func) def

    wrapper(*args, **kwargs): print((func.__name__ + '\n') * n) return func(*args, **kwargs) return wrapper return introduce
  25. # переименовываем всё для пущей красоты def introduce(n): def actual_decorator(func):

    @wraps(func) def wrapper(*args, **kwargs): print((func.__name__ + '\n') * n) return func(*args, **kwargs) return wrapper return actual_decorator
  26. def introduce(func, n, newline=True): @wraps(func) def wrapper(*args, **kwargs): print(('\n' if

    newline else ' ').join([func.__name__] * n)) return func(*args, **kwargs) return wrapper
  27. @decorator def introduce(f, *args, **kwargs): print(f.__name__) return f(*args, **kwargs) @introduce

    def identity(x): return x print(identity(31415)) >>> identity 31415
  28. def introduce(num=1): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): print((func.__name__ +

    ' ') * num) return func(*args, **kwargs) return wrapper return decorator
  29. @introduce(2) def id(x): return x print(id(42)) >>> id id 42

    @introduce() def id(x): return x print(id(42)) >>> id 42
  30. def multiply(x, y): return x * y def twice(y): twice

    = partial(multiply, 2) return multiply(2, y) def bin_to_int(b): bin_to_int = partial(int, base=2) return int(b, base=2) def printnext(string): printnext = partial(print, end=' ') print(string, end=' ')
  31. def introduce(func=None, num=1): if func is None: return partial(introduce, num=num)

    @wraps(func) def wrapper(*args, **kwargs): print((func.__name__ + ' ') * num) return func(*args, **kwargs) return wrapper
  32. @introduce(num=2) def id(x): return x print(id(42)) >>> id id 42

    @introduce() def id(x): return x print(id(42)) >>> id 42
  33. class GentleFunction: def __init__(self, func): self._func = func self._name =

    func.__name__ def __call__(self, *args, **kwargs): print ('My name is', self._name) return self._func(*args, **kwargs)
  34. from types import MethodType def add_method(obj): def actual_decorator(func): func =

    MethodType(func, obj) setattr(obj, func.__name__, func) return func return actual_decorator
  35. class Named: def __init__(self, name): self.name = name a =

    Named('Alice') @add_method(a) def introduce(self): print(self.name) a.introduce() >>> Alice
  36. def check(*preconditions): def actual_decorator(func): @wraps(func) def wrapper(*args, **kwargs): arg_names =

    func.__code__.co_varnames environment = dict(zip(arg_names, args)) environment.update(kwargs) for cond, msg in preconditions: if not eval(cond, environment): raise ValueError(msg) return func(*args, **kwargs) return wrapper return actual_decorator
  37. @check( ('all(xs[i] <= xs[i+1] for i in range(len(xs)-1))', 'The data

    is not sorted'), ('x != 0', 'Can not seek for zeros for some reason')) def binsearch(x, xs): pass binsearch(2, [1, 2, 3]) # всё хорошо binsearch(0, [1, 2, 3]) # исключение (нельзя искать нуль) binsearch(1, [1, 2, 1]) # исключение (данные не отсортированы)
  38. @apply def e(): summand = n = acc = 1

    threshold = 0.00001 while summand >= threshold: acc += summand n += 1 summand /= n return acc print(e, type(e)) >>> 2.71827876984127 <class 'float'>
  39. class Collection: def __init__(self, xs): self.data = xs def length(self):

    return len(self.data) some_collection = Collection([1, 2, 3]) print(some_collection.length()) >>> 3
  40. class Collection: def __init__(self, xs): self.data = xs @Field def

    length(self): return len(self.data) some_collection = Collection([1, 2, 3]) print(some_collection.length) >>> 3
  41. def product(value): if value == []: return 1 if isinstance(value,

    list) and len(value) >= 1: x, xs = value[0], value[1:] return x * product(xs)
  42. from functools import wraps # <- всегда используем wraps def

    decorator(initial_function): @wraps(initial_function) def new_function(*args, **kwargs): # <...> всякие полезности return initial_function(*args, **kwargs) return new_function
  43.  Изменение интерфейсов (в т.ч. при помощи “магии”)  Изменение

    объектов: атрибуты, методы (добавлять, менять значения)  Регистрация, аннотация объявляемых объектов (классов, функций)  Применение конструкторов классов, в т.ч. дескрипторов  Предпроверка условий, предобрабокта входных данных  И другие применения