<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Dekoratory
obiekty, które są callable
specjalna składnia @
modyfikacje runtime funkcji, metod, klas
od wersji Python 2.4
implementacja w formie funkcji albo klasy
Step1:  <h1><center>?</center></h1>
Step3:  moduł functools
Zawiera funkcje, zwracające funkcje albo działające na funkcjach
wiele przydatnych zaimplementowanych rozwiązań
wrapper_update i wraps, signal dispatch, lru_cache, partial
wraps
dekorator na update_wrapper
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
__module__, __name__, __qualname__, __annotations__ and __doc__ wrapper assignemnts
__dict__ wrapper updates
Step4:  singledispatch
dekorator pozwalający symulować przeciążenia funkcji
przeciążenie tylko na pierwszym argumencie funkcji
metoda register - rejestrowanie typów z implementacjami funkcji
Step5:  lru_cache (least recently used)
implementacja dekoratora do cache'owania ostatnich wynków
atrybut maxsize - zalecana liczba, która jest n**2
atrybut typed (od v3.3) - gdy ustawiony na true, rozróżnia typy np. foo(3) !=  foo(3.0)
cache_info() - metoda zwracająca  namedtuple(hits, misses, maxsize, currsize)
cache_clear() - czyszczenie cache'a
Step6:  partial
dekorator do tworzenia funkcji z wypełnionymi parametrami
upraszczanie sygnatury funkcji
<ASSISTANT_TASK:>
Python Code:
def greetings(f):
    print(f)
    def wrapper(*args, **kwargs):
        print("dekorator foo mówi: ", "Hello world!")
        return f(*args, **kwargs)
    
    return wrapper
    
@greetings    
def foo(a, b):
    print(a, b)
    print("Foo function")
    
def bar():
    pass
    
foo(4, 5)
#foo(1, 2)
#print(foo)
#print(bar)
def greetings(a, b, *args, **kwargs):
    print("parametry funkcji tworzącej dekorator: ", a, b, args, kwargs)
    def wrapper(f):
        def inner_wrapper(*args, **kwargs):
            print("dekorator foo mówi: ", "Hello world!")
            print("parametry przekazane do foo: ", args, kwargs)
            return f(*args, **kwargs)
        return inner_wrapper
    
    return wrapper
    
@greetings(1, 2, 3, liczba10=10, liczba20=20)  
def foo(a, b):
    print(a, b) 
    print("Foo function")
    
def bar():
    pass  
    
foo(4, 5)
#print(foo)
#print(bar)
Explanation: Dekoratory
obiekty, które są callable
specjalna składnia @
modyfikacje runtime funkcji, metod, klas
od wersji Python 2.4
implementacja w formie funkcji albo klasy
End of explanation
def greetings(f):
    def wrapper(*args, **kwargs):
        print("greetings")
        f(*args, **kwargs)
    return wrapper
def hello(f):
    def wrapper(*args, **kwargs):
        print("hello world")
        f(*args, **kwargs)
    return wrapper
@greetings
@hello
def foo():
    print("foo")
    
foo()
def attrs(**kwargs):
    def decorate(f):
        for k in kwargs:
            setattr(f, k, kwargs[k])
        return f
    return decorate
@attrs(version="1.0", author="Andrzej Krawczyk")
def foo():
    print("Hi!")
    
print(foo.version)
print(foo.author)
print(foo())
Explanation: <h1><center>?</center></h1>
End of explanation
from functools import wraps
def greetings(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        print("Parametry przekazane do nowej funkcji: ", args, kwargs)
        return f(*args, **kwargs)
    
    return wrapper
    
@greetings    
def foo(a, b):
    Docstring funkcji foo
    print(a, b)
    print("Foo function")
    
foo(4, 5)
#print(foo.__wrapped__)
#print(foo)
#print(foo.__doc__)
class greetings():
    def __init__(self, f):
        self.f = f
    
    def __call__(self, *args, **kwargs):
        print("pozdrowienia z dekoratora w formie klasy", self.f)
        return self.f(*args, **kwargs)
    
    
@greetings    
def foo(a, b):
    print(a, b)
    print("Foo function")
    
def bar():
    pass
    
foo(4, 5)
print(foo)
print(bar)
from functools import wraps
class greetings():
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
    
    def __call__(self, f, *args, **kwargs):
        @wraps(f)
        def wrapper(*args, **kwargs):
            print("pozdrowienia z dekoratora w formie klasy", f)
            print(self.a, self.b, self.c)
            return f(*args, **kwargs)
        return wrapper
    
    
@greetings("ala", "ma", "kota")    
def foo(a, b):
    print("Foo function", a, b)
    
def bar():
    pass
    
foo(4, 5)
print(foo)
print(bar)
Explanation: moduł functools
Zawiera funkcje, zwracające funkcje albo działające na funkcjach
wiele przydatnych zaimplementowanych rozwiązań
wrapper_update i wraps, signal dispatch, lru_cache, partial
wraps
dekorator na update_wrapper
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
__module__, __name__, __qualname__, __annotations__ and __doc__ wrapper assignemnts
__dict__ wrapper updates
End of explanation
from functools import singledispatch
@singledispatch
def suma(arg):
    print("inicjalizacja sumy")
    
@suma.register(tuple)
def _(arg):
    print("suma dla krotki", arg)
    return arg[0] + arg[1]
@suma.register(list)
def _(arg):
    print("suma dla listy", arg)
    return sum(arg)
@suma.register(int)
@suma.register(str)
def _(arg):
    print("dla int lub str", arg)
    
print("int: ", suma(1))
print("str: ", suma("1"))
print("krotka: ", suma((1, 2)))
print("lista: ", suma([1, 2, 3, 4]))
print(suma.dispatch(int))
print(suma.registry)
Explanation: singledispatch
dekorator pozwalający symulować przeciążenia funkcji
przeciążenie tylko na pierwszym argumencie funkcji
metoda register - rejestrowanie typów z implementacjami funkcji
End of explanation
from functools import lru_cache
import requests
@lru_cache(maxsize=32, typed=False)
def get_web(url):
    return requests.get(url=url)
print(get_web("http://www.trojmiasto.pl"))
print(get_web.cache_info())
Explanation: lru_cache (least recently used)
implementacja dekoratora do cache'owania ostatnich wynków
atrybut maxsize - zalecana liczba, która jest n**2
atrybut typed (od v3.3) - gdy ustawiony na true, rozróżnia typy np. foo(3) !=  foo(3.0)
cache_info() - metoda zwracająca  namedtuple(hits, misses, maxsize, currsize)
cache_clear() - czyszczenie cache'a
End of explanation
from functools import partial
from operator import add
def foo(a, b, d=5, e=10):
    print(a, b, d, e)
add_to_five = partial(add, 5)
print(add_to_five(2))
print(add_to_five(10))
p1 = partial(foo, d=-5)
p2 = partial(p1, 5)
p2(-3, e=-100)
Explanation: partial
dekorator do tworzenia funkcji z wypełnionymi parametrami
upraszczanie sygnatury funkcji
End of explanation
<END_TASK>