Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python Decorators: How Do You Even

Bill Israel
February 07, 2015

Python Decorators: How Do You Even

All the hip frameworks have them, you see them scattered around your codebase, but what IS a decorator? In this talk, Bill Israel will cover the features of Python that make decorators possible, how they work under the hood, what they're good for, and how you can start writing your own.

Bill Israel

February 07, 2015
Tweet

More Decks by Bill Israel

Other Decks in Programming

Transcript

  1. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
 
 
 def create_user():
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)
 
 data = request.get_json()
 new_user = users.create(**data)
 return jsonify(user=new_user.to_json()), 201
  2. @login_required
 def get_user_profile():
 user = users.get(session.get('user_id')
 return jsonify(user=user.to_json())
 
 


    @login_required
 @role_required('admin')
 def create_user():
 data = request.get_json()
 new_user = users.create(**data)
 return jsonify(user=new_user.to_json()), 201
  3. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
 
 
 def create_user():
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)
 
 data = request.get_json()
 new_user = users.create(**data)
 return jsonify(user=new_user.to_json()), 201
  4. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
  5. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
  6. def example():
 print("I'm a function!") >>> f = first_class2() >>>

    f() I'm a function! def first_class2():
 return example
  7. def first_class3():
 msg = "I'm a function!"
 
 def example():


    print(msg)
 
 example() >>> first_class3() I'm a function!
  8. Nest functions inside of functions Save functions into variables Pass

    functions as arguments Return functions from functions
  9. Return functions from functions Pass functions as arguments Nest functions

    inside of functions Save functions into variables
  10. Return functions from functions Pass functions as arguments Nest functions

    inside of functions Save functions into variables Decorators
  11. >>> wrapped = decorator(example) >>> wrapped() I'm a wrapper. I'm

    a function! def decorator(func):
 def wrapper():
 print("I'm a wrapper.")
 func()
 
 return wrapper def example():
 print("I'm a function!")
  12. >>> wrapped = decorator(example) >>> wrapped() I'm a wrapper. I'm

    a function! >>> wrapped = decorator(example) >>> wrapped() I'm a wrapper. I'm a function!
  13. >>> example = decorator(example) >>> example() I'm a wrapper. I'm

    a function! >>> wrapped = decorator(example) >>> wrapped() I'm a wrapper. I'm a function!
  14. def decorator(f):
 def wrapper():
 print("I'm a wrapper.")
 f()
 
 return

    wrapper
 
 def example():
 print("I'm a function!") example = decorator(example)
  15. def decorator(f):
 def wrapper():
 print("I'm a wrapper.")
 f()
 
 return

    wrapper
 
 def example():
 print("I'm a function!") example = decorator(example)
  16. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
  17. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
  18. def decorator(func):
 def wrapper():
 user_id = session.get('user_id')
 if user_id is

    None:
 return redirect('/login', code=302)
 
 func()
 
 return wrapper
  19. def login_required(func):
 def wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id

    is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  20. @login_required
 def get_user_profile():
 user = users.get(session.get('user_id'))
 return jsonify(user=user.to_json()) def login_required(func):


    def wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  21. @login_required
 def get_user_profile():
 user = users.get(session.get('user_id'))
 return jsonify(user=user.to_json()) def login_required(func):


    def wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  22. def create_new_user():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)
 
 data = request.get_json()
 newbie = users.create(**data)
 return jsonify(user=newbie.to_json()), 201
  23. def create_new_user():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)
 
 data = request.get_json()
 newbie = users.create(**data)
 return jsonify(user=newbie.to_json()), 201
  24. @login_required def create_new_user(): user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)


    
 data = request.get_json()
 newbie = users.create(**data)
 return jsonify(user=newbie.to_json()), 201
  25. @login_required
 def create_new_user():
 user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)


    
 data = request.get_json()
 newbie = users.create(**data)
 return jsonify(user=newbie.to_json()), 201
  26. create_user = role_required('admin')(create_user) @role_required('admin')
 def create_user():
 # ... OR decorator

    = role_required('admin')
 create_user = decorator(create_user) ...is the same as...
  27. def admin_required(func): 
 def wrapper(*args, **kwargs):
 user = users.get(session.get('user_id'))
 if

    not user.has_role('admin'):
 abort(403) 
 return func(*args, **kwargs)
 
 return wrapper
  28. def admin_required():
 def decorator(func): 
 def wrapper(*args, **kwargs):
 user =

    users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403) return func(*args, **kwargs) 
 return wrapper
 return decorator
  29. def role_required(role):
 def decorator(func): 
 def wrapper(*args, **kwargs):
 user =

    users.get(session.get('user_id'))
 if not user.has_role(role):
 abort(403)
 return func(*args, **kwargs) 
 return wrapper
 return decorator
  30. @login_required @role_required('admin')
 def create_user():
 data = request.get_json()
 new_user = users.create(**data)


    return jsonify(user=new_user.to_json()), 201 def role_required(role):
 def decorator(func): 
 def wrapper(*args, **kwargs):
 user = users.get(session.get('user_id'))
 if not user.has_role(role):
 abort(403)
 return func(*args, **kwargs) 
 return wrapper
 return decorator
  31. @login_required @role_required('admin')
 def create_user():
 data = request.get_json()
 new_user = users.create(**data)


    return jsonify(user=new_user.to_json()), 201 def role_required(role):
 def decorator(func): 
 def wrapper(*args, **kwargs):
 user = users.get(session.get('user_id'))
 if not user.has_role(role):
 abort(403)
 return func(*args, **kwargs) 
 return wrapper
 return decorator
  32. @login_required
 @role_required('admin')
 def create_user(): # ... ...is the same as...

    create_user = login_required( role_required('admin')(create_user) )
  33. @login_required
 def get_user_profile():
 # ... def login_required(func):
 def wrapper(*args, **kwargs):


    user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  34. @login_required
 def get_user_profile():
 # ... >>> get_user_profile.__name__ def login_required(func):
 def

    wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  35. @login_required
 def get_user_profile():
 # ... >>> get_user_profile.__name__ 'wrapper' def login_required(func):


    def wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  36. def login_required(func):
 def wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id

    is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper
  37. from functools import wraps
 
 def login_required(func):
 @wraps(func)
 def wrapper(*args,

    **kwargs):
 user_id = session.get(user_id)
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 return wrapper
  38. from functools import wraps
 
 def login_required(func):
 @wraps(func)
 def wrapper(*args,

    **kwargs):
 user_id = session.get(user_id)
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 return wrapper @login_required
 def get_user_profile():
 # ...
  39. from functools import wraps
 
 def login_required(func):
 @wraps(func)
 def wrapper(*args,

    **kwargs):
 user_id = session.get(user_id)
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 return wrapper @login_required
 def get_user_profile():
 # ... >>> get_user_profile.__name__
  40. from functools import wraps
 
 def login_required(func):
 @wraps(func)
 def wrapper(*args,

    **kwargs):
 user_id = session.get(user_id)
 if user_id is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 return wrapper @login_required
 def get_user_profile():
 # ... >>> get_user_profile.__name__ ‘get_user_profile’
  41. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
 
 
 def create_user():
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 user = users.get(session.get('user_id'))
 if not user.has_role('admin'):
 abort(403)
 
 data = request.get_json()
 new_user = users.create(**data)
 return jsonify(user=new_user.to_json()), 201
  42. def get_user_profile():
 user_id = session.get('user_id')
 if user_id is None:
 return

    redirect('/login', code=302)
 
 user = users.get(user_id)
 return jsonify(user=user.to_json())
 
 
 def create_user():
 user_id = session.get('user_id')
 if user_id is None:
 return redirect('/login', code=302)
 
 user = users.get(g.get('user_id'))
 if not user.has_role('admin'):
 abort(403)
 
 data = request.get_json()
 new_user = users.create(**data)
 return jsonify(user=new_user.to_json()), 201
  43. def login_required(func):
 def wrapper(*args, **kwargs):
 user_id = session.get('user_id')
 if user_id

    is None:
 return redirect('/login', code=302)
 
 return func(*args, **kwargs)
 
 return wrapper def role_required(role):
 def decorator(func): 
 def wrapper(*args, **kwargs):
 user = users.get(session.get('user_id'))
 if not user.has_role(role):
 abort(403)
 return func(*args, **kwargs) 
 return wrapper
 return decorator
  44. @login_required
 def get_user_profile():
 user = users.get(session.get(‘user_id'))
 return jsonify(user=user.to_json())
 
 


    @login_required
 @role_required('admin')
 def create_user():
 data = request.get_json()
 new_user = users.create(**data)
 return jsonify(user=new_user.to_json()), 201