Skip to content

Instantly share code, notes, and snippets.

@ayushkumarshah
Forked from jangia/decorator.py
Created January 7, 2021 13:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayushkumarshah/8083150f0b8b8cde9302a4055fe15ba3 to your computer and use it in GitHub Desktop.
Save ayushkumarshah/8083150f0b8b8cde9302a4055fe15ba3 to your computer and use it in GitHub Desktop.
def my_function():
print('Hi')
print(my_function)
# <function my_function at 0x7efea5c36050>
def send_email_ses(email_message):
print(f'Send email using AWS SES: {email_message}')
def send_email_sendgrid(email_message):
print(f'Send email using SendGrid: {email_message}')
def send_email(send_email_function):
email_message = 'Hi'
send_email_function(email_message)
send_email(send_email_ses)
# Send email using AWS SES: Hi
send_email(send_email_sendgrid)
# Send email using SendGrid: Hi
def get_send_email_function(email_service):
def send_email_ses(email_message):
print(f'Send email using AWS SES: {email_message}')
def send_email_sendgrid(email_message):
print(f'Send email using SendGrid: {email_message}')
def send_email_dummy(email_message):
print(f'I just pretend that I will send email: {email_message}')
if email_service == 'SES':
return send_email_ses
elif email_service == 'SENDGRID':
return send_email_sendgrid
else:
return send_email_dummy
send_email = get_send_email_function('SES')
send_email('Hi')
# Send email using AWS SES: Hi
def log_enter_leave(func):
def wrapper(*args, **kwargs):
print('Enter function')
result = func(*args, **kwargs)
print('Leave function')
return result
return wrapper
def my_function():
print('Hi')
my_function = log_enter_leave(my_function)
my_function()
# Enter function
# Hi
# Leave function
"""
*log_enter_leave* is a decorator - it accepts any function object as an argument.
We want to call decorated function *func* the same way as undecorated *func*.
To do that we define inner function *wrapper*.
It accepts any arguments and keyword arguments.
*wrapper* alters behavior of *func*.
It prints before and after *func* is executed.
*log_enter_leave* just returns *wrapper* function object to the caller.
Because functions are objects we can store them in variables.
So to alter *my_function* we reassign decorated *my_function* to *my_function* - my_function = log_enter_leave(my_function).
When we do that *wrapper* function is returned which now looks like this:
```
def wrapper(*args, **kwargs):
print('Enter function')
result = my_function(*args, **kwargs)
print('Leave function')
return result
˙˙˙
So now when we call:
```
my_function()
```
We see this printed out:
Enter function
Hi
Leave function
"""
def log_enter_leave(func):
def wrapper(*args, **kwargs):
print('Enter function')
result = func(*args, **kwargs)
print('Leave function')
return result
return wrapper
@log_enter_leave
def my_function():
print('Hi')
my_function()
# Enter function
# Hi
# Leave function
def log_enter_leave(func):
def wrapper(*args, **kwargs):
print('Enter function')
result = func(*args, **kwargs)
print('Leave function')
return result
return wrapper
@log_enter_leave
def my_function():
print('Hi')
print(my_function.__name__)
# wrapper
from functools import wraps
def log_enter_leave(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('Enter function')
result = func(*args, **kwargs)
print('Leave function')
return result
return wrapper
@log_enter_leave
def my_function():
print('Hi')
print(my_function.__name__)
# my_function
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
import functools
class CallCounter:
def __init__(self, function):
functools.update_wrapper(self, function)
self.function = function
self.number_calls = 0
def __call__(self, *args, **kwargs):
self.number_calls += 1
print(f"{self.function.__name__} was called {self.number_calls} times.")
return self.function(*args, **kwargs)
@CallCounter
def my_function():
print("Hi!")
"""
What's going one here?
@CallCounter actually does this:
```
my_function = CallCounter(my_function)
```
So my function is now instance of CallCounter class.
It must be callable to be able to call it the same way as my_function.
When instance of CallCounter is called - __call__ is executed ->
number_calls is incremented and result from decorated function is returned.
Every time we call my_function the same instance of CallCounter is called.
That's why number_calls is bigger for every consecutive call.
"""
my_function()
# my_function was called 1 times.
# Hi!
my_function()
# my_function was called 2 times.
# Hi!
from flask import Flask, Response
app = Flask(__name__)
@app.route('/get-csv/')
def users_csv():
csv_string = 'name,surname\nJan,Giacomelli'
response = Response(
csv_string,
mimetype='text/csv',
headers={
"Content-disposition": "attachment; filename=users.csv"}
)
return response
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment