Skip to content

Latest commit

 

History

History
252 lines (189 loc) · 4.93 KB

File metadata and controls

252 lines (189 loc) · 4.93 KB

Decorators

import functools

Enable/disable decorator

trace_enabled = False

def trace(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print(func.__name__, args, kwargs)
        return func(*args, **kwargs)
    return inner if trace_enabled else func

Decorator with args

trace_enabled = False

def trace(handle):
    # handle - catching args
    def decorator(func):
        # real decorator
        @functools.wraps(func)
        def inner(*args, **kwargs):
            print(func.__name__, args, kwargs, file=handle)
            return func(*args, **kwargs)
        return inner if trace_enabled else func
    return decorator

The universal decorator with args

def with_arguments(deco):
    @functools.wraps(func)
    def wrapper(*dargs, **dkwargs):
        def decorator(func):
            result = deco(func, *dargs, **dkwargs)
            functools.update_wrapper(result, func)
            return result
        return decorator
    return  wrapper

@with_arguments
def trace(func, handle):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print(func.__name__, args, kwargs, file=handle)
        return func(*args, **kwargs)
    return inner

@trace(sys.stderr)
def identity(x):
    return x

OTHER WAY (LOL)

Oh my fuCng god!!!! 😲😲😲

def trace(func=None, *, handle=sys.stdout):
    # with kwarg
    if func is None:
        return lambda func: trace(func, handle=handle)
    
    # without kwarg
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print(func.__name__, args, kwargs, handle)
        return func(*args, **kwargs)
    return inner

example

def timethis(func=None, *, n_iter=100):
    if func is None:
        return lambda func: timethis(func, n_iter=n_iter)
    
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print(func.__name__, end=" ... ")
        acc = float("inf")
        for i in range(n_iter):
            tick = time.perf_counter()
            result = func(*args, **kwargs)
            acc = min(acc, time.perf_counter() - tick)
        print(acc)
        return result
    return inner
    
result = timethis(sum)(range(10 ** 6))

Cool thing

time.perf_counter # !!!!!!!!!!!!!!!!!!

Strange thing, attribute of function

def lol(val):
    lol.val = val

lol(10)

print(lol.val) # 10

Decorator "Once"

def once(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        if not inner.called:
            inner.called = True # attribute of wrapper
            inner.result = func(*args, **kwargs) # returned value
        return inner.result
    inner.called = False
    return inner

@once
def init_settings():
    print("Username == Alex")
    return 1
    
init_settings() # Username == Alex
init_settings() #
init_settings() #

Cache / memoized

def memoized(func):
    cache = {}

    @functools.wraps(func)
    def inner(*args, **kwargs):
        key = args + tuple(sorted(kwargs.items()))
        if key not in cache:
            cache[key] = func(*args, **kwargs)
        return cache[key]
    return inner

def addon(a, b):
    return a + b

Pre, post

def pre(cond, message):
    def wrapper(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            assert cond(*args, **kwargs), message
            return func(*args, **kwargs)
    return wrapper

        
@pre(lambda x: x > 0, "negative argument")
def checked_log():
    pass

checked_log(-42) # AssertionError: negative argument
def post(cond, message):
    def wrapper(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)
            assert cond(*args, **kwargs), message
            return result
    return wrapper

        
@post(lambda x: not math,isnan(x), "result not a number")
def something():
    return 'h'

something() # AssertionError: result not a number

functools

import functools

@functools.lru_cache(maxsize=64)
def cached_func():
    pass

cached_func()

cached_func.cache_info() # CacheInfo(hits=65, misses=315, maxsize=64, currsize=64)
# hits - cases when answer were in cache
# mass - cases when answer wasn't in cache

@functools.lru_cache(maxsize=None)  # unlimited
def __():
    pass

# =====================================

f = functools.partial(sorted, key=lambda p: p[1])
f([('a', 4), ('b', 2)]) # [('b', 2), ('a', 4)]

# =====================================

# reserving for any type
@functools.singledispatch
def pack(obj):
    type_name = type(obj).__name__
    assert False, f"Unsupported type: {type_name}"
    
# reserving for int
@pack.register(int)
def _(obj):
    return f"I{hex(obj)}"

# reserving for list
@pack.register(list)
def _(obj):
    return f"I{'-'.join(str(x) for x in obj)}"


all([1,2,3,0])   # False
all([1,2,3,1])   # True
any([1,0,0,0])   # True
any([0,0,0,0])   # False