decorators

mike warren
https://meejah.ca

decorators

wild decorators

decorators

what they do

how decorators work

def decorator(fn):
    return fn

what they do

def decorator(fn):
    fn._mike_wuz_here = True
    return fn

what they do

def boldify(fn):
    def wrapper(*args):
        r = fn(*args)
        return "<b>{}</b>".format(r)
    return wrapper

what they do

def foo(a, b):
    return a + b
print(foo(1, 2))  # "3"
foo = boldify(foo)
print(foo(1, 2))  # "<b>3</b>"
3
<b>3</b>

what they do

def boldify(fn):
    def wrapper(*args):
        r = fn(*args)
        return "<b>{}</b>".format(r)
    return wrapper
@boldify
def foo(a, b):
    return a + b
print(foo(1, 2))
<b>3</b>

how decorators work

def fib(x):
    if x in [1, 2]:
        return 1
    return fib(x - 1) + fib(x - 2)
print(fib(3))
print(fib(10))
2
55

how decorators work

from time import time
from contextlib import contextmanager

@contextmanager
def timer():
    s = time()
    yield
    print("took {:.6f}s".format(time() - s))
with timer():
    pass
took 0.000002s

how decorators work

def fib(x):
    if x in [1, 2]:
        return 1
    return fib(x - 1) + fib(x - 2)
with timer():
    print("fib(35) =", fib(35))
fib(35) = 9227465
took 2.930136s

how decorators work

def memoize(fn):
    cache = dict()
    def wrapper(*args):
        try:
            return cache[args]
        except KeyError:
            r = fn(*args)
            cache[args] = r
            return r
    return wrapper

how decorators work

@memoize
def fib(x):
    if x in [1, 2]:
        return 1
    return fib(x - 1) + fib(x - 2)
with timer():
    print("fib(35) =", fib(35))
# remember: ~1.6 seconds previously
fib(35) = 9227465
took 0.000190s

how decorators work

with timer():
    print("fib(100) =", fib(100))
with timer():
    print("fib(200) =", fib(200))
fib(100) = 354224848179261915075
took 0.000866s
fib(200) = 280571172992510140037611932413038677189525
took 0.000196s

memoize: questions?

def memoize(fn):
    cache = {}
    def wrapper(*args):
        try:
            return cache[args]
        except KeyError:
            r = fn(*args)
            cache[args] = r
            return r
    return wrapper
@memoize
def fib(x):
    if x in [1, 2]:
        return 1
    return fib(x - 1) + fib(x - 2)

decorators with args

decorators with args

decorators with args: Flask

class Flask(object):
    def __init__(self):
        self.url_map = dict()
    def route(self, url):
        def decorator(fn):
            self.url_map[url] = fn
            return fn
        return decorator
app = Flask()  # yuck! globals!
@app.route("/foo")
def foo(request):
    return "Gorgeous HTMLs"
print(app.url_map['/foo']("fake request object"))
Gorgeous HTMLs

class decorators

class decorators

def implements(iface):
    def decorate(cls):
        try:
            cls._interfaces.append(iface)
        except AttributeError:
            cls._interfaces = [iface]
        return cls
    return decorate

class decorators

@implements("fake interface")
@implements("another interface")
class Foo(object):
    pass
f = Foo()
print("f has interfaces: {}".format(f._interfaces))
f has interfaces: ['another interface', 'fake interface']

@contextmanager

@contextmanager
def a_thing():
    print("enter")
    yield "a thing"
    print("exit")
with a_thing() as foo:
   print("inside: {}".format(foo))
enter
inside: a thing
exit

@contextmanager

class Helper(object):
    def __init__(self, gen):
        self._gen = gen
    def __enter__(self):
        return next(self._gen)
    def __exit__(self, type, value, traceback):
        if type is None:
            try:
                next(self._gen)
            except StopIteration:
                return
        else:
            self._gen.throw(type, value, traceback)

@contextmanager

def contextmanager(fn):
    def wrapper(*args, **kw):
        return Helper(fn(*args, **kw))
    return wrapper
@contextmanager
def foo():
    print("hi")
    yield "a thing"
    print("bye")
with foo() as x:
    print("inside:", x)
hi
inside: a thing
bye

thanks

thanks for your attention



questions?



@meejah
github.com/meejah
https://meejah.ca

;