Python - Generator and Decorator
Generator:
A generator function is like a normal function but contains yield keyword and returns generator object instead of a value. The yield keyword doesn't exit the function's execution instead, it maintains the state by halting it. It waits until the next request is received and continues executing from where it is left off.
A caller can request the next value by calling next method, the generator code executes, and yield statement provides back the value. At this point, the generator halts its execution and waits for the next request. When its iteration is completed it generates a StopIteration exception and exit. Caller can also send any value to a generator by send method. A generator function can also delegate other generator functions.
>>> def get_list(limit):
... for i in range(limit):
... yield i
...
>>> x = get_list(5)
>>> x
<generator object get_list at 0x10eb56570>
>>> def get_str():
... yield "A"
... yield "B"
...
>>> def get_int():
... yield 1
... yield 2
...
>>> def get_values():
... yield from get_str()
... yield from get_int()
...
>>> delg = get_values()
>>> print(next(delg))
A
>>> print(next(delg))
B
>>> print(next(delg))
1
>>> print(next(delg))
2
>>> generator_exp = (i * 5 for i in range(5) if i % 2 == 0)
>>> generator_exp
<generator object <genexpr> at 0x10eb56570>
It uses the list comprehension technique and generates generator object instead of storing the elements in a list in memory. It provides a quick and space-efficient method to process large data files (i.e. log files, reports) because it accesses and computes value on demand. It avoids unnecessary computing and storing the values in memory and hence increases performance and memory efficiency.
Decorator:
Decorator allows us to wrap functions to modify or extend a function or class without permanently modifying it. Because of first class objects, functions in python can be stored into variable, passed as parameter, return another function from a function.
领英推荐
>>> def decorator(func): # [step-2]
... def inner_func(*args, **kwargs): # [step-3] [step-6]
... print("Inside decorator") # [step-7]
... output = func(*args, **kwargs) # [step-8]
...
... print("Function is executed") # [step-12]
... return output # [step-13]
...
... return inner_func # [step-4]
...
>>> def used_func(a, b): # [step-9]
... print("Function is executing") # [step-10]
... return a + b # [step-11]
>>> used_func = decorator(used_func) # [step-1]
>>> used_func(1, 2) # [step-5] [step-14]
Inside decorator
Function is executing
Function is executed
These above snippet is equivalent to:
@decorator
def used_func(a, b):
print("Function is executing")
return a + b
used_func(1, 2)
If you need to use multiple decorator it can be used by chaining them.
def sum_decorator(func):
def inner():
output = func()
return output + output
return inner
def multipy_decorator(func):
def inner():
output = func()
return output * output
return inner
@sum_decorator
@multipy_decorator
def get_num():
return 5
print(get_num())
50
These above snippet is equivalent to:
used_method = sum_decorator(multipy_decorator(get_num))
used_method()
50