Add files via upload · fluentpython/example-code-2e@4deb247
1+def make_upper(func):
2+def inner_func(arg): # def inner_func(*args, **kwargs):
3+return func(arg).upper() # return func(*args, **kwargs).upper() -- to support compatibility for all the type of functions irrespective of function signature
4+return inner_func
5+6+7+@make_upper
8+def remove_vowel(in_data):
9+vowels = list('aeiou')
10+print(vowels)
11+consonants = [char for char in in_data.lower() if char not in vowels]
12+return ''.join(consonants)
13+14+print(remove_vowel('Ezhilarasi'))
15+16+# <h2>Data in Decorators</h2>
17+# Decorater function with shared variables
18+def running_average(func):
19+data = {"total" : 0, "count" : 0} #Run once for every decoraters and data got created. Whenever decorated function call happens just the wrapper function getting called not the entire decorator
20+def wrapper(*args, **kwargs):
21+val = func(*args, **kwargs)
22+data["total"] += val
23+data["count"] += 1
24+print("Average of {} so far: {:.01f}".format(
25+func.__name__, data["total"] / data["count"]))
26+return func(*args, **kwargs)
27+return wrapper
28+29+"""
30+The decorator function itself is executed exactly once for every function it decorates. If you decorate N functions, running_average() is executed N times, so we get N different data dictionaries, each tied to one of the resulting decorated functions. This has nothing to do with how many times a decorated function is executed. The decorated function is, basically, one of the created wrapper() functions. That wrapper() can be executed many times, using the same data dictionary that was in scope when that wrapper() was defined.
31+"""
32+33+#<h2>Accessing Inner Data</h2>
34+def collectstats(func):
35+data = {"total" : 0, "count" : 0}
36+def wrapper(*args, **kwargs):
37+val = func(*args, **kwargs)
38+data["total"] += val
39+data["count"] += 1
40+return val
41+wrapper.data = data #ties the data's current value with the wrapper function
42+return wrapper
43+44+#decorator to count how many times a function being called
45+def countcalls(func):
46+count = 0
47+def wrapper(*args, **kwargs):
48+nonlocal count #Notice nonlocal keyword
49+count += 1
50+print(f"# of calls: {count}")
51+return func(*args, **kwargs)
52+return wrapper
53+54+55+# Decorators That Take Arguments
56+def add(increment): #one more nested function when we add arguments to decorators
57+def decorator(func):
58+def wrapper(*args, **kwargs):
59+return func(*args, **kwargs) + increment # increment will vary based on the argument passed
60+return wrapper
61+return decorator
62+63+@add(2) # add is the function that takes argument and return decorator function
64+def foo(x):
65+return x ** 2
66+67+@add(4)
68+def bar(n):
69+return n * 2
70+71+72+# Class-Based Decorators
73+class PrintLog:
74+def __init__(self, func): # pass the function as arguments to constructor
75+self.func = func
76+def __call__(self, *args, **kwargs): # replace wrapper with __call__
77+print(f"CALLING: {self.func.__name__}")
78+return self.func(*args, **kwargs)
79+80+@PrintLog
81+def foo(x):
82+print(x + 2)
83+84+85+# class based decorators with nonlocal variables
86+class CountCalls:
87+def __init__(self, func):
88+self.func = func
89+self.count = 0 #count can be accessed outside decorator function
90+def __call__(self, *args, **kwargs):
91+self.count += 1
92+print(f"# of calls: {self.count}")
93+return self.func(*args, **kwargs)
94+95+@CountCalls
96+def foo(x):
97+return x + 2
98+99+# Class-based version of the "add" decorator above.
100+class Add:
101+def __init__(self, increment): # parameter accepted here
102+self.increment = increment
103+def __call__(self, func): # accepts function to be decorated
104+def wrapper(n): # nested function
105+return func(n) + self.increment
106+return wrapper
107+108+109+# Decorators for Classes
110+111+def autorepr(cls): #accepts class
112+def cls_repr(self):
113+return f"{cls.__name__}()"
114+cls.__repr__ = cls_repr # redefines the function implementation
115+return cls # returns original class not a wrapper function
116+117+@autorepr
118+class Penny:
119+value = 1
120+121+penny = Penny()
122+repr(penny)
123+'Penny()'