What are Python decorators and generators?
What are Python decorators and generators?
Python decorators and generators are two fundamental concepts in Python programming that help you write more concise, readable, and maintainable code.
Decorators
A decorator is a small function that takes another function as an argument and returns a new function that "wraps" the original function. The purpose of a decorator is to modify or extend the behavior of the original function without changing its source code.
Here's how you can use decorators:
Define a decorator:@my_decorator def my_function(): pass
Call the decorated function: my_function()
In this example, my_decorator
takes in the original function (my_function
) as an argument and returns a new function that "wraps" it.
Decorators are often used to:
Logging: Record information about each function call Authentication: Check if the user is authenticated before allowing them to access certain functions Error handling: Catch and handle exceptions thrown by the original functionFor example, you can create a decorator to log every time a function is called:
def log_calls(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.name} with args {args} and kwargs {kwargs}")
return func(*args, **kwargs)
return wrapper
@log_calls
def my_function(x, y):
return x + y
result = my_function(2, 3) # Output: Calling my_function with args (2, 3) and kwargs {}
print(result) # Output: 5
Generators
A generator is a type of iterable that generates values on-the-fly as you iterate over it. Generators are useful when working with large datasets or when you need to process data in chunks.
Here's how you can create a generator:
Define a generator function:def my_generator(): yield 1; yield 2;
Call the generator and iterate over its values: for value in my_generator(): print(value)
In this example, the my_generator
function yields two values (1 and 2). When you call it with a for loop, it generates these values one by one.
Generators are often used to:
Process large datasets in chunks Generate random numbers or data Create iterators that yield values based on some conditionFor example, you can create a generator to generate all prime numbers up to 100:
def prime_numbers(n):
for i in range(2, n+1):
is_prime = True
for j in range(2, int(i ** 0.5) + 1):
if i % j == 0:
is_prime = False
break
if is_prime:
yield i
for prime in prime_numbers(100): print(prime)
This code generates all prime numbers up to 100 and prints them one by one.
In summary, Python decorators are used to modify or extend the behavior of functions without changing their source code. Generators are used to generate values on-the-fly as you iterate over them. Both concepts help you write more concise, readable, and maintainable code in Python!
What are the famous decorators in Python?
I'd be happy to respond in English!
Python is a popular programming language known for its simplicity and ease of use. One of its key features is its extensive library collection, which includes many useful modules for data analysis, machine learning, web development, and more.
Decorators are a type of function that can modify the behavior of another function. They're often used to implement aspects or behaviors that would be repeated throughout your code. Python has several decorators that can simplify your code and make it easier to read and maintain.
Here are some of the most famous decorators in Python:
@property: This decorator is used to create getter and setter methods for attributes in a class. For example, if you have aPerson
class with an age
attribute, you can use this decorator to create a property that allows you to get or set the age.
class Person:
def init(self, name):
self.name = name
self._age = 0
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self._age = value
p = Person("John")
print(p.age) # Output: 0
p.age = 30
print(p.age) # Output: 30
@functools.lru_cache: This decorator is used to cache the results of a function, which can significantly speed up performance by avoiding redundant calculations.
import functools
@functools.lru_cache(maxsize=None)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # Output: 55
@singledispatch: This decorator is used to define a single function that can be applied to multiple types of input.
from functools import singledispatch
@singledispatch
def greet(obj):
if isinstance(obj, str):
return f"Hello, {obj}!"
elif isinstance(obj, int):
return "Hello, world!"
print(greet("John")) # Output: Hello, John!
print(greet(123)) # Output: Hello, world!
@contextmanager: This decorator is used to create a context manager that can be used with the with
statement.
from contextlib import contextmanager
@contextmanager
def my_context():
print("Entering my context")
try:
yield
finally:
print("Exiting my context")
with my_context():
pass # Output: Entering my context; Exiting my context
@timed: This decorator is used to time how long a function takes to execute.
import time
def timed(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.name} took {end_time - start_time:.2f} seconds")
return result
return wrapper
@timed
def example_function():
time.sleep(1)
example_function() # Output: example_function took 1.00 seconds
These are just a few examples of the many decorators available in Python. By using these decorators, you can create more robust and efficient code that's easier to read and maintain.
(Note: This response is written entirely in English.)