SlideShare a Scribd company logo
1 of 68
Download to read offline
{{
Python  DECORATORS
DEMYSTIFIED
Python  DECORATORS
DEMYSTIFIED
"ʺevent"ʺ:      "ʺEuroPython 2015"ʺ
"ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ
"ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ
"ʺevent"ʺ:      "ʺEuroPython 2015"ʺ
"ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ
"ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Do  you  know  what’s  happening  each  
time  you  use  the  @    (at)  symbol to  
decorate  a  function  or  class?
Today  we  are  going  to  see  how  
Python’s  decorators  syntactic  sugar
works  under  the  hood
Do  you  know  what’s  happening  each  
time  you  use  the  @    (at)  symbol to  
decorate  a  function  or  class?
Today  we  are  going  to  see  how  
Python’s  decorators  syntactic  sugar
works  under  the  hood
Welcome!Welcome!
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
And  that’s  why  we  will  talk  about  
Python  namespaces  and  scopes
And  that’s  why  we  will  talk  about  
Python  namespaces  and  scopes
Welcome!Welcome!
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
And  finally  will  manually implement  
and  apply  a  handcrafted  decorator
And  finally  will  manually implement  
and  apply  a  handcrafted  decorator
Welcome!Welcome!
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Let’s  start  implementing  some
useful stuff  for  the  talk
Let’s  start  implementing  some
useful stuff  for  the  talk
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  simple  software  cacheA  simple  software  cache
from collections import OrderedDict
CACHE = OrderedDict()
MAX_SIZE = 100
def set_key(key, value):
"Set a key value, removing oldest key if MAX_SIZE exceeded"
CACHE[key] = value
if len(CACHE) > MAX_SIZE:
CACHE.popitem(last=False)
def get_key(key):
"Retrieve a key value from the cache, or None if not found"
return CACHE.get(key, None)
>>> set_key("my_key", "the_value")
>>> print(get_key("my_key"))
the_value
>>> print(get_key("not_found_key"))
None
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Use  functools.lru_cache,  not  this!!!Use  functools.lru_cache,  not  this!!!
from collections import OrderedDict
CACHE = OrderedDict()
MAX_SIZE = 100
def set_key(key, value):
"Set a key value, removing oldest key if MAX_SIZE exceeded"
CACHE[key] = value
if len(CACHE) > MAX_SIZE:
CACHE.popitem(last=False)
def get_key(key):
"Retrieve a key value from the cache, or None if not found"
return CACHE.get(key, None)
>>> set_key("my_key", "the_value")
>>> print(get_key("my_key"))
the_value
>>> print(get_key("not_found_key"))
None
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Factorial  and  fibonacci functionsFactorial  and  fibonacci functions
def factorial(n):
"Return n! (the factorial of n): n! = n * (n-1)!"
if n < 2:
return 1
return n * factorial(n - 1)
>>> list(map(factorial, range(10)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
def fibonacci(n):
"Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)"
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> list(map(fibonacci, range(10)))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Pretty  easy,  right?Pretty  easy,  right?
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
However…However…
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
How  are  we  accessing  this  attribute?How  are  we  accessing  this  attribute?
from collections import OrderedDict
CACHE = OrderedDict()
MAX_SIZE = 100
def set_key(key, value):
"Set a key value, removing oldest key if MAX_SIZE exceeded"
CACHE[key] = value
if len(CACHE) > MAX_SIZE:
CACHE.popitem(last=False)
def get_key(key):
"Retrieve a key value from the cache, or None if not found"
return CACHE.get(key, None)
>>> set_key("my_key", "the_value")
>>> print(get_key("my_key"))
the_value
>>> print(get_key("not_found_key"))
None
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
How  are  recursive  calls  possible?How  are  recursive  calls  possible?
def factorial(n):
"Return n! (the factorial of n): n! = n * (n-1)!"
if n < 2:
return 1
return n * factorial(n - 1)
>>> list(map(factorial, range(10)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
def fibonacci(n):
"Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)"
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> list(map(fibonacci, range(10)))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  simpler  caseA  simpler  case
>>> from os import path
>>> print(type(path), id(path))
<class 'module'> 4300435112
>>> from sys import path
>>> print(type(path), id(path))
<class 'list'> 4298480008
def split_path(path, sep="/"):
print(type(path), id(path))
return path.split(sep)
>>> split_path("/this/is/a/full/path")
<class 'str'> 4302038120
['', 'this', 'is', 'a', 'full', 'path']
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
The  same  name  defined  several  times?The  same  name  defined  several  times?
>>> from os import path
>>> print(type(path), id(path))
<class 'module'> 4300435112
>>> from sys import path
>>> print(type(path), id(path))
<class 'list'> 4298480008
def split_path(path, sep="/"):
print(type(path), id(path))
return path.split(sep)
>>> split_path("/this/is/a/full/path")
<class 'str'> 4302038120
['', 'this', 'is', 'a', 'full', 'path']
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Let  me  introduce  Python  namespacesLet  me  introduce  Python  namespaces
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  namespace  is  a  mapping  
from  names  to  objects
A  namespace  is  a  mapping  
from  names  to  objects
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
> The  set  of  built-­‐‑in  names  (functions,  exceptions)
> Global  names  in  a  module  (including  imports)
> Local  names  in  a  function  invocation
> Names  defined  in  top-­‐‑level  invocation  of  interpreter
> The  set  of  built-­‐‑in  names  (functions,  exceptions)
> Global  names  in  a  module  (including  imports)
> Local  names  in  a  function  invocation
> Names  defined  in  top-­‐‑level  invocation  of  interpreter
Python  namespaces examplesPython  namespaces examples
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
There  is  no  relation  between  names  in  
different  namespaces
Two  modules  or  functions  may  define  the  same  
name  without  confusion
There  is  no  relation  between  names  in  
different  namespaces
Two  modules  or  functions  may  define  the  same  
name  without  confusion
Python  namespacesPython  namespaces
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Namespaces  are  created  (and  deleted)  
at  different  moments  and  have  
different  lifetimes
Namespaces  are  created  (and  deleted)  
at  different  moments  and  have  
different  lifetimes
Python  namespacesPython  namespaces
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
The  built-­‐‑ins  namespace is  created  
when  the  Python  interpreter  starts
And  is  never  deleted
The  built-­‐‑ins  namespace is  created  
when  the  Python  interpreter  starts
And  is  never  deleted
Python  namespaces lifetimesPython  namespaces lifetimes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  module  global  namespace is  
created  when  the  module  definition  is  
read-­‐‑in  (when  it  is  imported)
Normally  it  lasts  until  the  interpreter  quits
A  module  global  namespace is  
created  when  the  module  definition  is  
read-­‐‑in  (when  it  is  imported)
Normally  it  lasts  until  the  interpreter  quits
Python  namespaces lifetimesPython  namespaces lifetimes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  function  local  namespace is  
created  each  time  it  is  called
It  is  deleted  when  the  function  returns  or  raises
A  function  local  namespace is  
created  each  time  it  is  called
It  is  deleted  when  the  function  returns  or  raises
Python  namespaces lifetimesPython  namespaces lifetimes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
And  what  about  Python  scopes?And  what  about  Python  scopes?
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  scope is  a  textual  region  
of  a  program  where  a  
namespace  is  directly  
accessible
A  scope is  a  textual  region  
of  a  program  where  a  
namespace  is  directly  
accessible
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Scopes  are  determined  statically
but  used  dynamically
Scopes  are  determined  statically
but  used  dynamically
Python  scopesPython  scopes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
At  any  time  during  execution,  there  
are  at  least  three  nested  scopes whose  
namespaces  are  directly  accessible
At  any  time  during  execution,  there  
are  at  least  three  nested  scopes whose  
namespaces  are  directly  accessible
Python  scopesPython  scopes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
1. The  innermost  scope  contains  the  local  
names
> The  scopes  of  any  enclosing  functions,  
with  non-­‐‑local,  but  also  non-­‐‑global  names
2. The  next-­‐‑to-­‐‑last  scope  contains  the  
current  module'ʹs  global  names
3. The  outermost  scope  is  the  namespace  
containing  built-­‐‑in  names
1. The  innermost  scope  contains  the  local  
names
> The  scopes  of  any  enclosing  functions,  
with  non-­‐‑local,  but  also  non-­‐‑global  names
2. The  next-­‐‑to-­‐‑last  scope  contains  the  
current  module'ʹs  global  names
3. The  outermost  scope  is  the  namespace  
containing  built-­‐‑in  names
Python  nested scopesPython  nested scopes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Names  are  searched  in  nested  scopes  
from  inside  out
From  locals  to  built-­‐‑ins
Read-­‐‑only  access  except  for  globals
Names  are  searched  in  nested  scopes  
from  inside  out
From  locals  to  built-­‐‑ins
Read-­‐‑only  access  except  for  globals
Python  nested  scopesPython  nested  scopes
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
$ python
Python 2.7.5 (default, Aug 25 2013, 00:04:04)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-
500.0.68)] on darwin
Type "help", "copyright", "credits" or "license"
for more information.
>>> import cache
>>> cache.set_key("my_key", 7)
>>> cache.get_key("my_key")
7
>>>
Python  scopesPython  scopes
"""
Simple cache implementation
"""
from collections import OrderedDict
CACHE = OrderedDict()
MAX_SIZE = 100
def set_key(key, value):
"Set a key value, removing oldest key if MAX_SIZE exceeded"
CACHE[key] = value
if len(CACHE) > MAX_SIZE:
CACHE.popitem(last=False)
def get_key(key):
"Retrieve a key value from the cache, or None if not found"
return CACHE.get(key, None)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
$ python
Python 2.7.5 (default, Aug 25 2013, 00:04:04)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-
500.0.68)] on darwin
Type "help", "copyright", "credits" or "license"
for more information.
>>> import cache
>>> cache.set_key("my_key", 7)
>>> cache.get_key("my_key")
7
>>>
Python  scopesPython  scopes
"""
Simple cache implementation
"""
from collections import OrderedDict
CACHE = OrderedDict()
MAX_SIZE = 100
def set_key(key, value):
"Set a key value, removing oldest key if MAX_SIZE exceeded"
CACHE[key] = value
if len(CACHE) > MAX_SIZE:
CACHE.popitem(last=False)
def get_key(key):
"Retrieve a key value from the cache, or None if not found"
return CACHE.get(key, None)
The  outermost  scope:
built-­‐‑in  names
The  next-­‐‑to-­‐‑last  scope:
current  module’s  global  names
The  innermost  scope:
current  local  names
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Another  more  complex  caseAnother  more  complex  case
def get_power_func(y):
print("Creating function to raise to {}".format(y))
def power_func(x):
print("Calling to raise {} to power of {}".format(x, y))
x = pow(x, y)
return x
return power_func
>>> raise_to_4 = get_power_func(4)
Creating function to raise to 4
>>> x = 3
>>> print(raise_to_4(x))
Calling to raise 3 to power of 4
81
>>> print(x)
3
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Where  is  y defined?Where  is  y defined?
def get_power_func(y):
print("Creating function to raise to {}".format(y))
def power_func(x):
print("Calling to raise {} to power of {}".format(x, y))
x = pow(x, y)
return x
return power_func
>>> raise_to_4 = get_power_func(4)
Creating function to raise to 4
>>> x = 3
>>> print(raise_to_4(x))
Calling to raise 3 to power of 4
81
>>> print(x)
3
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
def get_power_func(y):
print("Creating function to raise to {}".format(y))
def power_func(x):
print("Calling to raise {} to power of {}".format(x, y))
x = pow(x, y)
return x
return power_func
>>> raise_to_4 = get_power_func(4)
Creating function to raise to 4
>>> x = 3
>>> print(raise_to_4(x))
Calling to raise 3 to power of 4
81
>>> print(x)
3
Nested  scopesNested  scopes
The  next-­‐‑to-­‐‑last  scope:
current  module’s  global  names
Enclosing  function  scope:
non-­‐‑local  non-­‐‑global  names
The  innermost  scope:  local  names
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
def get_power_func(y):
print("Creating function to raise to {}".format(y))
def power_func(x):
print("Calling to raise {} to power of {}".format(x, y))
x = pow(x, y)
return x
return power_func
>>> raise_to_4 = get_power_func(4)
Creating function to raise to 4
>>> print(raise_to_4.__globals__)
{'x': 3, 'raise_to_4': <function
get_power_func.<locals>.power_func at 0x100658488>,
'get_power_func': <function get_power_func at 0x1003b6048>, ...}
>>> print(raise_to_4.__closure__)
(<cell at 0x10065f048: int object at 0x10023b280>,)
There  is  a  closure!There  is  a  closure!
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  function  closure is  a  
reference  to  each  of  the  non-­‐‑
local  variables  of  the  function
A  function  closure is  a  
reference  to  each  of  the  non-­‐‑
local  variables  of  the  function
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
def get_power_func(y):
print("Creating function to raise to {}".format(y))
def power_func(x):
print("Calling to raise {} to power of {}".format(x, y))
x = pow(x, y)
return x
return power_func
>>> raise_to_4 = get_power_func(4)
Creating function to raise to 4
>>> print(raise_to_4.__globals__)
{'x': 3, 'raise_to_4': <function
get_power_func.<locals>.power_func at 0x100658488>,
'get_power_func': <function get_power_func at 0x1003b6048>, ...}
>>> print(raise_to_4.__closure__)
(<cell at 0x10065f048: int object at 0x10023b280>,)
So,  where  is  y defined?So,  where  is  y defined?
The  innermost  scope:  local  names
Enclosing  function  scope
The  next-­‐‑to-­‐‑last  scope:
current  module’s  global  names
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Maybe  you  are  wondering
where  are  the decorators in  this  talk…
Maybe  you  are  wondering
where  are  the decorators in  this  talk…
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
So,  let’s  manually apply  a  decoratorSo,  let’s  manually apply  a  decorator
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Let’s  go  back  to  these  functionsLet’s  go  back  to  these  functions
def factorial(n):
"Return n! (the factorial of n): n! = n * (n-1)!"
if n < 2:
return 1
return n * factorial(n - 1)
>>> start = time.time()
>>> factorial(35)
10333147966386144929666651337523200000000
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0007369518280029297
def fibonacci(n):
"Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)"
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> start = time.time()
>>> fibonacci(35)
9227465
>>> print("Elapsed:", time.time() - start)
Elapsed: 6.916048049926758
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
fibonacci(5)  recursive  calls  graphfibonacci(5)  recursive  calls  graph
5
4 3
1
2 1
02 1
0
3 2 1
01
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Do  you  remember  we  have  a  cache?Do  you  remember  we  have  a  cache?
from collections import OrderedDict
CACHE = OrderedDict()
MAX_SIZE = 100
def set_key(key, value):
"Set a key value, removing oldest key if MAX_SIZE exceeded"
CACHE[key] = value
if len(CACHE) > MAX_SIZE:
CACHE.popitem(last=False)
def get_key(key):
"Retrieve a key value from the cache, or None if not found"
return CACHE.get(key, None)
>>> set_key("my_key", "the_value")
>>> print(get_key("my_key"))
the_value
>>> print(get_key("not_found_key"))
None
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
What  about  this  version?What  about  this  version?
import cache
def fibonacci(n):
"Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)"
if n < 2:
return n
fib = cache.get_key(n)
if fib is None:
fib = fibonacci(n - 1) + fibonacci(n - 2)
cache.set_key(n, fib)
return fib
>>> start = time.time()
>>> fibonacci(35)
9227465
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0007810592651367188
>>> start = time.time()
>>> fibonacci(100)
354224848179261915075
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0013179779052734375
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
DRY:  Don’t  Repeat  Yourself!DRY:  Don’t  Repeat  Yourself!
import cache
def fibonacci(n):
"Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)"
if n < 2:
return n
fib = cache.get_key(n)
if fib is None:
fib = fibonacci(n - 1) + fibonacci(n - 2)
cache.set_key(n, fib)
return fib
>>> start = time.time()
>>> fibonacci(35)
9227465
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0007810592651367188
>>> start = time.time()
>>> fibonacci(100)
354224848179261915075
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0013179779052734375
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Pay  attention  to  the  magic  trickPay  attention  to  the  magic  trick
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Original  function  is  not  modifiedOriginal  function  is  not  modified
import time
import cache
def fibonacci(n): # The function remains unchanged
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> real_fibonacci = fibonacci
def fibonacci(n):
fib = cache.get_key(n)
if fib is None:
fib = real_fibonacci(n)
cache.set_key(n, fib)
return fib
>>> start = time.time()
>>> fibonacci(35)
9227465
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0010080337524414062
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Which  function is  called  here?Which  function is  called  here?
import time
import cache
def fibonacci(n): # The function remains unchanged
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> real_fibonacci = fibonacci
def fibonacci(n):
fib = cache.get_key(n)
if fib is None:
fib = real_fibonacci(n)
cache.set_key(n, fib)
return fib
>>> start = time.time()
>>> fibonacci(35)
9227465
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0010080337524414062
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
import time
import cache
def fibonacci(n): # The function remains unchanged
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> real_fibonacci = fibonacci
def fibonacci(n):
fib = cache.get_key(n)
if fib is None:
fib = real_fibonacci(n)
cache.set_key(n, fib)
return fib
>>> start = time.time()
>>> fibonacci(35)
9227465
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0010080337524414062
Remember  the  scopes…Remember  the  scopes…
The  next-­‐‑to-­‐‑last  scope:
current  module’s  global  names
The  innermost  scope:
current  local  names
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
And  now  the  trick  in  slow  motionAnd  now  the  trick  in  slow  motion
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
1.  Create  original  fibonacci function1.  Create  original  fibonacci function
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> print(id(fibonacci))
4298858568
{
fibonacci:  4298858568
}
Global  names
4298858568:  <function  fibonacci at  0x1003b6048>
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
Objects
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
2.  Create  alternative  name  pointing  
to  the  same  function  object
2.  Create  alternative  name  pointing  
to  the  same  function  object
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> print(id(fibonacci))
4298858568
>>> real_fib = fibonacci
{
fibonacci:  4298858568,
real_fib:        4298858568,
}
Global  names
4298858568:  <function  fibonacci at  0x1003b6048>
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
Objects
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
3.  Replace  original  name  with  new  a  
function  which  calls  the  alternative  name
3.  Replace  original  name  with  new  a  
function  which  calls  the  alternative  name
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> print(id(fibonacci))
4298858568
>>> real_fib = fibonacci
def fibonacci(n):
fib = cache.get_key(n)
if fib is None:
fib = real_fib (n)
cache.set_key(n, fib)
return fib
>>> print(id(fibonacci))
4302081696
>>> print(id(real_fib))
4298858568
{
fibonacci:  4302081696,
real_fib:        4298858568,
}
Global  names
4298858568:  <function  fibonacci at  0x1003b6048>
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
4302081696:  <function  fibonacci at  0x1006c8ea0>
fib = cache.get_key(n)
if fib is None:
fib = real_fib (n)
cache.set_key(n, fib)
return fib Objects
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
This  way  we  swap  both  functionsThis  way  we  swap  both  functions
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> print(id(fibonacci))
4298858568
>>> real_fib = fibonacci
def fibonacci(n):
fib = cache.get_key(n)
if fib is None:
fib = real_fib (n)
cache.set_key(n, fib)
return fib
>>> print(id(fibonacci))
4302081696
>>> print(id(real_fib))
4298858568
{
fibonacci:  4302081696,
real_fib:        4298858568,
}
Global  names
4298858568:  <function  fibonacci at  0x1003b6048>
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
4302081696:  <function  fibonacci at  0x1006c8ea0>
fib = cache.get_key(n)
if fib is None:
fib = real_fib (n)
cache.set_key(n, fib)
return fib Objects
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
But  the  original  function  does  not  know  itBut  the  original  function  does  not  know  it
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> print(id(fibonacci))
4298858568
>>> real_fib = fibonacci
def fibonacci(n):
fib = cache.get_key(n)
if fib is None:
fib = real_fib (n)
cache.set_key(n, fib)
return fib
>>> print(id(fibonacci))
4302081696
>>> print(id(real_fib))
4298858568
{
fibonacci:  4302081696,
real_fib:        4298858568,
}
Global  names
4298858568:  <function  fibonacci at  0x1003b6048>
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
4302081696:  <function  fibonacci at  0x1006c8ea0>
fib = cache.get_key(n)
if fib is None:
fib = real_fib (n)
cache.set_key(n, fib)
return fib Objects
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Let’s  make  this  trick  fully  reusableLet’s  make  this  trick  fully  reusable
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Let’s  make  it  work  with  any*  functionLet’s  make  it  work  with  any*  function
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  factory  of  memoization functionsA  factory  of  memoization functions
import cache
def memoize_any_function(func_to_memoize):
"Return a wrapped version of the function using memoization"
def memoized_version_of_func(n):
"Wrapper using memoization"
res = cache.get_key(n)
if res is None:
res = func_to_memoize(n) # Call the real function
cache.set_key(n, res)
return res
return memoized_version_of_func
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> fibonacci = memoize_any_function(fibonacci)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
A  factory  of  memoization functionsA  factory  of  memoization functions
import cache
def memoize_any_function(func_to_memoize):
"Return a wrapped version of the function using memoization"
def memoized_version_of_func(n):
"Wrapper using memoization"
res = cache.get_key(n)
if res is None:
res = func_to_memoize(n) # Call the real function
cache.set_key(n, res)
return res
return memoized_version_of_func
def factorial(n):
if n < 2:
return 1
return n * factorial(n - 1)
>>> factorial= memoize_any_function(factorial)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
It  works  with  any*  functionIt  works  with  any*  function
import time
>>> start = time.time()
>>> fibonacci(250)
7896325826131730509282738943634332893686268675876375
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.0009610652923583984
>>> start = time.time()
>>> factorial(250)
32328562609091077323208145520243684709948437176737806667479424271
12823747555111209488817915371028199450928507353189432926730931712
80899082279103027907128192167652724018926473321804118626100683292
53651336789390895699357135301750405131787600772479330654023390061
64825552248819436572586057399222641254832982204849137721776650641
27685880715312897877767295191399084437747870258917297325515028324
17873206581884820624785826598088488255488000000000000000000000000
00000000000000000000000000000000000000
>>> print("Elapsed:", time.time() - start)
Elapsed: 0.00249481201171875
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
And  finally,  at  long  last,  decoratorsAnd  finally,  at  long  last,  decorators
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Pay  attention…Pay  attention…
import cache
def memoize_any_function(func_to_memoize):
"Return a wrapped version of the function using memoization"
def memoized_version_of_func(n):
"Wrapper using memoization"
res = cache.get_key(n)
if res is None:
res = func_to_memoize(n) # Call the real function
cache.set_key(n, res)
return res
return memoized_version_of_func
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> fibonacci = memoize_any_function(fibonacci)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Did  you  spot  the  difference?Did  you  spot  the  difference?
import cache
def memoize_any_function(func_to_memoize):
"Return a wrapped version of the function using memoization"
def memoized_version_of_func(n):
"Wrapper using memoization"
res = cache.get_key(n)
if res is None:
res = func_to_memoize(n) # Call the real function
cache.set_key(n, res)
return res
return memoized_version_of_func
@memoize_any_function
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Did  you  spot  the  difference?Did  you  spot  the  difference?
import cache
def memoize_any_function(func_to_memoize):
"Return a wrapped version of the function using memoization"
def memoized_version_of_func(n):
"Wrapper using memoization"
res = cache.get_key(n)
if res is None:
res = func_to_memoize(n) # Call the real function
cache.set_key(n, res)
return res
return memoized_version_of_func
@memoize_any_function
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
This  is  the  only  thing  the  @  does
Calls  a  decorator  providing  the  decorated  
function,  then  makes  the  function  name  point  to  
the  result
This  is  the  only  thing  the  @  does
Calls  a  decorator  providing  the  decorated  
function,  then  makes  the  function  name  point  to  
the  result
Decorators  demystifiedDecorators  demystified
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> fibonacci = memoize_any_function(fibonacci)
@memoize_any_function
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n – 2)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
This  is  the  only  thing  the  @  does
Calls  a  decorator  providing  the  decorated  
function,  then  makes  the  function  name  point  to  
the  result
This  is  the  only  thing  the  @  does
Calls  a  decorator  providing  the  decorated  
function,  then  makes  the  function  name  point  to  
the  result
Decorators  demystifiedDecorators  demystified
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
>>> fibonacci = memoize_any_function(fibonacci)
@memoize_any_function
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n – 2)
{  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
Q&AQ&A
Thanks  for  coming!
Slides:  https://goo.gl/fMP4jH
Thanks  for  coming!
Slides:  https://goo.gl/fMP4jH

More Related Content

What's hot

The Ring programming language version 1.6 book - Part 48 of 189
The Ring programming language version 1.6 book - Part 48 of 189The Ring programming language version 1.6 book - Part 48 of 189
The Ring programming language version 1.6 book - Part 48 of 189Mahmoud Samir Fayed
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG CampinasFabio Akita
 
50 new things we can do with Java 8
50 new things we can do with Java 850 new things we can do with Java 8
50 new things we can do with Java 8José Paumard
 
Nigel hamilton-megameet-2013
Nigel hamilton-megameet-2013Nigel hamilton-megameet-2013
Nigel hamilton-megameet-2013trexy
 
plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6Nobuo Danjou
 
Whirlwind Tour of Puppet 4
Whirlwind Tour of Puppet 4Whirlwind Tour of Puppet 4
Whirlwind Tour of Puppet 4ripienaar
 
2010/7/31 LTの虎@LL Tiger
2010/7/31 LTの虎@LL Tiger2010/7/31 LTの虎@LL Tiger
2010/7/31 LTの虎@LL TigerAkihiro Okuno
 
Writing Apps the Google-y Way (Brisbane)
Writing Apps the Google-y Way (Brisbane)Writing Apps the Google-y Way (Brisbane)
Writing Apps the Google-y Way (Brisbane)Pamela Fox
 
Testing Jboss Seam Bottom Up
Testing Jboss Seam Bottom UpTesting Jboss Seam Bottom Up
Testing Jboss Seam Bottom UpDan Hinojosa
 
#SPUG - Legacy applications
#SPUG - Legacy applications#SPUG - Legacy applications
#SPUG - Legacy applicationsPiotr Pasich
 
GenStage and Flow - Jose Valim
GenStage and Flow - Jose Valim GenStage and Flow - Jose Valim
GenStage and Flow - Jose Valim Elixir Club
 
Wykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie AndroidWykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie Android3camp
 
Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015Lukas Ruebbelke
 
Code obfuscation, php shells & more
Code obfuscation, php shells & moreCode obfuscation, php shells & more
Code obfuscation, php shells & moreMattias Geniar
 
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of ElixirYurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of ElixirElixir Club
 
Building Interpreters with PyPy
Building Interpreters with PyPyBuilding Interpreters with PyPy
Building Interpreters with PyPyDaniel Neuhäuser
 
Joy of Six - Discover the Joy of Perl 6
Joy of Six - Discover the Joy of Perl 6Joy of Six - Discover the Joy of Perl 6
Joy of Six - Discover the Joy of Perl 6trexy
 
PuppetConf. 2016: External Data in Puppet 4 – R.I. Pienaar
PuppetConf. 2016: External Data in Puppet 4 – R.I. PienaarPuppetConf. 2016: External Data in Puppet 4 – R.I. Pienaar
PuppetConf. 2016: External Data in Puppet 4 – R.I. PienaarPuppet
 

What's hot (20)

The Ring programming language version 1.6 book - Part 48 of 189
The Ring programming language version 1.6 book - Part 48 of 189The Ring programming language version 1.6 book - Part 48 of 189
The Ring programming language version 1.6 book - Part 48 of 189
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
 
50 new things we can do with Java 8
50 new things we can do with Java 850 new things we can do with Java 8
50 new things we can do with Java 8
 
Nigel hamilton-megameet-2013
Nigel hamilton-megameet-2013Nigel hamilton-megameet-2013
Nigel hamilton-megameet-2013
 
plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6
 
Whirlwind Tour of Puppet 4
Whirlwind Tour of Puppet 4Whirlwind Tour of Puppet 4
Whirlwind Tour of Puppet 4
 
2010/7/31 LTの虎@LL Tiger
2010/7/31 LTの虎@LL Tiger2010/7/31 LTの虎@LL Tiger
2010/7/31 LTの虎@LL Tiger
 
Perl6 in-production
Perl6 in-productionPerl6 in-production
Perl6 in-production
 
Writing Apps the Google-y Way (Brisbane)
Writing Apps the Google-y Way (Brisbane)Writing Apps the Google-y Way (Brisbane)
Writing Apps the Google-y Way (Brisbane)
 
Testing Jboss Seam Bottom Up
Testing Jboss Seam Bottom UpTesting Jboss Seam Bottom Up
Testing Jboss Seam Bottom Up
 
#SPUG - Legacy applications
#SPUG - Legacy applications#SPUG - Legacy applications
#SPUG - Legacy applications
 
P3 2018 python_regexes
P3 2018 python_regexesP3 2018 python_regexes
P3 2018 python_regexes
 
GenStage and Flow - Jose Valim
GenStage and Flow - Jose Valim GenStage and Flow - Jose Valim
GenStage and Flow - Jose Valim
 
Wykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie AndroidWykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie Android
 
Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015
 
Code obfuscation, php shells & more
Code obfuscation, php shells & moreCode obfuscation, php shells & more
Code obfuscation, php shells & more
 
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of ElixirYurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
 
Building Interpreters with PyPy
Building Interpreters with PyPyBuilding Interpreters with PyPy
Building Interpreters with PyPy
 
Joy of Six - Discover the Joy of Perl 6
Joy of Six - Discover the Joy of Perl 6Joy of Six - Discover the Joy of Perl 6
Joy of Six - Discover the Joy of Perl 6
 
PuppetConf. 2016: External Data in Puppet 4 – R.I. Pienaar
PuppetConf. 2016: External Data in Puppet 4 – R.I. PienaarPuppetConf. 2016: External Data in Puppet 4 – R.I. Pienaar
PuppetConf. 2016: External Data in Puppet 4 – R.I. Pienaar
 

Viewers also liked

The (unknown) collections module
The (unknown) collections moduleThe (unknown) collections module
The (unknown) collections modulePablo Enfedaque
 
An Introduction to Object-Oriented Programming (DrupalCamp North 2015)
An Introduction to Object-Oriented Programming (DrupalCamp North 2015)An Introduction to Object-Oriented Programming (DrupalCamp North 2015)
An Introduction to Object-Oriented Programming (DrupalCamp North 2015)Bart Feenstra
 
Oop concepts classes_objects
Oop concepts classes_objectsOop concepts classes_objects
Oop concepts classes_objectsWilliam Olivier
 
Message-passing concurrency in Python
Message-passing concurrency in PythonMessage-passing concurrency in Python
Message-passing concurrency in PythonSarah Mount
 
Meta-Classes in Python
Meta-Classes in PythonMeta-Classes in Python
Meta-Classes in PythonGuy Wiener
 
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Samuel Fortier-Galarneau
 
Python decorators
Python decoratorsPython decorators
Python decoratorsAlex Su
 
Multiprocessing with python
Multiprocessing with pythonMultiprocessing with python
Multiprocessing with pythonPatrick Vergain
 
Prepping the Analytics organization for Artificial Intelligence evolution
Prepping the Analytics organization for Artificial Intelligence evolutionPrepping the Analytics organization for Artificial Intelligence evolution
Prepping the Analytics organization for Artificial Intelligence evolutionRamkumar Ravichandran
 
QCon Rio - Machine Learning for Everyone
QCon Rio - Machine Learning for EveryoneQCon Rio - Machine Learning for Everyone
QCon Rio - Machine Learning for EveryoneDhiana Deva
 
Python for Image Understanding: Deep Learning with Convolutional Neural Nets
Python for Image Understanding: Deep Learning with Convolutional Neural NetsPython for Image Understanding: Deep Learning with Convolutional Neural Nets
Python for Image Understanding: Deep Learning with Convolutional Neural NetsRoelof Pieters
 
Tutorial on Deep learning and Applications
Tutorial on Deep learning and ApplicationsTutorial on Deep learning and Applications
Tutorial on Deep learning and ApplicationsNhatHai Phan
 
An Introduction to Supervised Machine Learning and Pattern Classification: Th...
An Introduction to Supervised Machine Learning and Pattern Classification: Th...An Introduction to Supervised Machine Learning and Pattern Classification: Th...
An Introduction to Supervised Machine Learning and Pattern Classification: Th...Sebastian Raschka
 
Hands-on Deep Learning in Python
Hands-on Deep Learning in PythonHands-on Deep Learning in Python
Hands-on Deep Learning in PythonImry Kissos
 
Deep Learning - The Past, Present and Future of Artificial Intelligence
Deep Learning - The Past, Present and Future of Artificial IntelligenceDeep Learning - The Past, Present and Future of Artificial Intelligence
Deep Learning - The Past, Present and Future of Artificial IntelligenceLukas Masuch
 

Viewers also liked (20)

The (unknown) collections module
The (unknown) collections moduleThe (unknown) collections module
The (unknown) collections module
 
An Introduction to Object-Oriented Programming (DrupalCamp North 2015)
An Introduction to Object-Oriented Programming (DrupalCamp North 2015)An Introduction to Object-Oriented Programming (DrupalCamp North 2015)
An Introduction to Object-Oriented Programming (DrupalCamp North 2015)
 
Oop concepts classes_objects
Oop concepts classes_objectsOop concepts classes_objects
Oop concepts classes_objects
 
Message-passing concurrency in Python
Message-passing concurrency in PythonMessage-passing concurrency in Python
Message-passing concurrency in Python
 
Meta-Classes in Python
Meta-Classes in PythonMeta-Classes in Python
Meta-Classes in Python
 
Python decorators
Python decoratorsPython decorators
Python decorators
 
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
 
Python decorators
Python decoratorsPython decorators
Python decorators
 
Multiprocessing with python
Multiprocessing with pythonMultiprocessing with python
Multiprocessing with python
 
Interfacing C/C++ and Python with SWIG
Interfacing C/C++ and Python with SWIGInterfacing C/C++ and Python with SWIG
Interfacing C/C++ and Python with SWIG
 
Python in Action (Part 1)
Python in Action (Part 1)Python in Action (Part 1)
Python in Action (Part 1)
 
Prepping the Analytics organization for Artificial Intelligence evolution
Prepping the Analytics organization for Artificial Intelligence evolutionPrepping the Analytics organization for Artificial Intelligence evolution
Prepping the Analytics organization for Artificial Intelligence evolution
 
Mastering Python 3 I/O (Version 2)
Mastering Python 3 I/O (Version 2)Mastering Python 3 I/O (Version 2)
Mastering Python 3 I/O (Version 2)
 
An Introduction to Python Concurrency
An Introduction to Python ConcurrencyAn Introduction to Python Concurrency
An Introduction to Python Concurrency
 
QCon Rio - Machine Learning for Everyone
QCon Rio - Machine Learning for EveryoneQCon Rio - Machine Learning for Everyone
QCon Rio - Machine Learning for Everyone
 
Python for Image Understanding: Deep Learning with Convolutional Neural Nets
Python for Image Understanding: Deep Learning with Convolutional Neural NetsPython for Image Understanding: Deep Learning with Convolutional Neural Nets
Python for Image Understanding: Deep Learning with Convolutional Neural Nets
 
Tutorial on Deep learning and Applications
Tutorial on Deep learning and ApplicationsTutorial on Deep learning and Applications
Tutorial on Deep learning and Applications
 
An Introduction to Supervised Machine Learning and Pattern Classification: Th...
An Introduction to Supervised Machine Learning and Pattern Classification: Th...An Introduction to Supervised Machine Learning and Pattern Classification: Th...
An Introduction to Supervised Machine Learning and Pattern Classification: Th...
 
Hands-on Deep Learning in Python
Hands-on Deep Learning in PythonHands-on Deep Learning in Python
Hands-on Deep Learning in Python
 
Deep Learning - The Past, Present and Future of Artificial Intelligence
Deep Learning - The Past, Present and Future of Artificial IntelligenceDeep Learning - The Past, Present and Future of Artificial Intelligence
Deep Learning - The Past, Present and Future of Artificial Intelligence
 

Similar to EuroPython 2015 - Decorators demystified

Execution model and other must-know's
Execution model and other must-know'sExecution model and other must-know's
Execution model and other must-know'sPablo Enfedaque
 
Total World Domination with i18n (es)
Total World Domination with i18n (es)Total World Domination with i18n (es)
Total World Domination with i18n (es)Zé Fontainhas
 
Writing a compiler in go
Writing a compiler in goWriting a compiler in go
Writing a compiler in goYusuke Kita
 
Python-GTK
Python-GTKPython-GTK
Python-GTKYuren Ju
 
Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone DevelopmentGiordano Scalzo
 
COSCUP2012: How to write a bash script like the python?
COSCUP2012: How to write a bash script like the python?COSCUP2012: How to write a bash script like the python?
COSCUP2012: How to write a bash script like the python?Lloyd Huang
 
Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...
Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...
Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...Edureka!
 
Python: the coolest is yet to come
Python: the coolest is yet to comePython: the coolest is yet to come
Python: the coolest is yet to comePablo Enfedaque
 
OpenGurukul : Language : Python
OpenGurukul : Language : PythonOpenGurukul : Language : Python
OpenGurukul : Language : PythonOpen Gurukul
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018 Codemotion
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntityBasuke Suzuki
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607Kevin Hazzard
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesNaresha K
 
An (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to PythonAn (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to PythonNicholas Tollervey
 
Refactor legacy code through pure functions
Refactor legacy code through pure functionsRefactor legacy code through pure functions
Refactor legacy code through pure functionsAlexandru Bolboaca
 

Similar to EuroPython 2015 - Decorators demystified (20)

Decorators demystified
Decorators demystifiedDecorators demystified
Decorators demystified
 
Execution model and other must-know's
Execution model and other must-know'sExecution model and other must-know's
Execution model and other must-know's
 
effective_r27
effective_r27effective_r27
effective_r27
 
Total World Domination with i18n (es)
Total World Domination with i18n (es)Total World Domination with i18n (es)
Total World Domination with i18n (es)
 
Ruby
RubyRuby
Ruby
 
Writing a compiler in go
Writing a compiler in goWriting a compiler in go
Writing a compiler in go
 
Python-GTK
Python-GTKPython-GTK
Python-GTK
 
Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone Development
 
Charming python
Charming pythonCharming python
Charming python
 
COSCUP2012: How to write a bash script like the python?
COSCUP2012: How to write a bash script like the python?COSCUP2012: How to write a bash script like the python?
COSCUP2012: How to write a bash script like the python?
 
Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...
Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...
Advanced Python Tutorial | Learn Advanced Python Concepts | Python Programmin...
 
Python: the coolest is yet to come
Python: the coolest is yet to comePython: the coolest is yet to come
Python: the coolest is yet to come
 
OpenGurukul : Language : Python
OpenGurukul : Language : PythonOpenGurukul : Language : Python
OpenGurukul : Language : Python
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
 
Wait, IPython can do that?
Wait, IPython can do that?Wait, IPython can do that?
Wait, IPython can do that?
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good Practices
 
An (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to PythonAn (Inaccurate) Introduction to Python
An (Inaccurate) Introduction to Python
 
Refactor legacy code through pure functions
Refactor legacy code through pure functionsRefactor legacy code through pure functions
Refactor legacy code through pure functions
 

Recently uploaded

Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Standamitlee9823
 
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdfONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdfKamal Acharya
 
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Bookingroncy bisnoi
 
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...ranjana rawat
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Call Girls in Nagpur High Profile
 
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Bookingdharasingh5698
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlysanyuktamishra911
 
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...Call Girls in Nagpur High Profile
 
AKTU Computer Networks notes --- Unit 3.pdf
AKTU Computer Networks notes ---  Unit 3.pdfAKTU Computer Networks notes ---  Unit 3.pdf
AKTU Computer Networks notes --- Unit 3.pdfankushspencer015
 
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...tanu pandey
 
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELLPVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELLManishPatel169454
 
Thermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptThermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptDineshKumar4165
 
Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01KreezheaRecto
 
Unit 1 - Soil Classification and Compaction.pdf
Unit 1 - Soil Classification and Compaction.pdfUnit 1 - Soil Classification and Compaction.pdf
Unit 1 - Soil Classification and Compaction.pdfRagavanV2
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756dollysharma2066
 

Recently uploaded (20)

Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
 
Water Industry Process Automation & Control Monthly - April 2024
Water Industry Process Automation & Control Monthly - April 2024Water Industry Process Automation & Control Monthly - April 2024
Water Industry Process Automation & Control Monthly - April 2024
 
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdfONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
 
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
 
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
 
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
 
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Palanpur 7001035870 Whatsapp Number, 24/07 Booking
 
NFPA 5000 2024 standard .
NFPA 5000 2024 standard                                  .NFPA 5000 2024 standard                                  .
NFPA 5000 2024 standard .
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghly
 
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
 
AKTU Computer Networks notes --- Unit 3.pdf
AKTU Computer Networks notes ---  Unit 3.pdfAKTU Computer Networks notes ---  Unit 3.pdf
AKTU Computer Networks notes --- Unit 3.pdf
 
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
 
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELLPVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
 
Thermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptThermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.ppt
 
Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01
 
Unit 1 - Soil Classification and Compaction.pdf
Unit 1 - Soil Classification and Compaction.pdfUnit 1 - Soil Classification and Compaction.pdf
Unit 1 - Soil Classification and Compaction.pdf
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
 

EuroPython 2015 - Decorators demystified

  • 1. {{ Python  DECORATORS DEMYSTIFIED Python  DECORATORS DEMYSTIFIED "ʺevent"ʺ:      "ʺEuroPython 2015"ʺ "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ "ʺevent"ʺ:      "ʺEuroPython 2015"ʺ "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ
  • 2. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Do  you  know  what’s  happening  each   time  you  use  the  @    (at)  symbol to   decorate  a  function  or  class? Today  we  are  going  to  see  how   Python’s  decorators  syntactic  sugar works  under  the  hood Do  you  know  what’s  happening  each   time  you  use  the  @    (at)  symbol to   decorate  a  function  or  class? Today  we  are  going  to  see  how   Python’s  decorators  syntactic  sugar works  under  the  hood Welcome!Welcome!
  • 3. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } And  that’s  why  we  will  talk  about   Python  namespaces  and  scopes And  that’s  why  we  will  talk  about   Python  namespaces  and  scopes Welcome!Welcome!
  • 4. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } And  finally  will  manually implement   and  apply  a  handcrafted  decorator And  finally  will  manually implement   and  apply  a  handcrafted  decorator Welcome!Welcome!
  • 5. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Let’s  start  implementing  some useful stuff  for  the  talk Let’s  start  implementing  some useful stuff  for  the  talk
  • 6. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  simple  software  cacheA  simple  software  cache from collections import OrderedDict CACHE = OrderedDict() MAX_SIZE = 100 def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False) def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None) >>> set_key("my_key", "the_value") >>> print(get_key("my_key")) the_value >>> print(get_key("not_found_key")) None
  • 7. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Use  functools.lru_cache,  not  this!!!Use  functools.lru_cache,  not  this!!! from collections import OrderedDict CACHE = OrderedDict() MAX_SIZE = 100 def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False) def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None) >>> set_key("my_key", "the_value") >>> print(get_key("my_key")) the_value >>> print(get_key("not_found_key")) None
  • 8. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Factorial  and  fibonacci functionsFactorial  and  fibonacci functions def factorial(n): "Return n! (the factorial of n): n! = n * (n-1)!" if n < 2: return 1 return n * factorial(n - 1) >>> list(map(factorial, range(10))) [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880] def fibonacci(n): "Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)" if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> list(map(fibonacci, range(10))) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
  • 9. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Pretty  easy,  right?Pretty  easy,  right?
  • 10. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } However…However…
  • 11. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } How  are  we  accessing  this  attribute?How  are  we  accessing  this  attribute? from collections import OrderedDict CACHE = OrderedDict() MAX_SIZE = 100 def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False) def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None) >>> set_key("my_key", "the_value") >>> print(get_key("my_key")) the_value >>> print(get_key("not_found_key")) None
  • 12. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } How  are  recursive  calls  possible?How  are  recursive  calls  possible? def factorial(n): "Return n! (the factorial of n): n! = n * (n-1)!" if n < 2: return 1 return n * factorial(n - 1) >>> list(map(factorial, range(10))) [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880] def fibonacci(n): "Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)" if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> list(map(fibonacci, range(10))) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
  • 13. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  simpler  caseA  simpler  case >>> from os import path >>> print(type(path), id(path)) <class 'module'> 4300435112 >>> from sys import path >>> print(type(path), id(path)) <class 'list'> 4298480008 def split_path(path, sep="/"): print(type(path), id(path)) return path.split(sep) >>> split_path("/this/is/a/full/path") <class 'str'> 4302038120 ['', 'this', 'is', 'a', 'full', 'path']
  • 14. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } The  same  name  defined  several  times?The  same  name  defined  several  times? >>> from os import path >>> print(type(path), id(path)) <class 'module'> 4300435112 >>> from sys import path >>> print(type(path), id(path)) <class 'list'> 4298480008 def split_path(path, sep="/"): print(type(path), id(path)) return path.split(sep) >>> split_path("/this/is/a/full/path") <class 'str'> 4302038120 ['', 'this', 'is', 'a', 'full', 'path']
  • 15. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Let  me  introduce  Python  namespacesLet  me  introduce  Python  namespaces
  • 16. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  namespace  is  a  mapping   from  names  to  objects A  namespace  is  a  mapping   from  names  to  objects
  • 17. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } > The  set  of  built-­‐‑in  names  (functions,  exceptions) > Global  names  in  a  module  (including  imports) > Local  names  in  a  function  invocation > Names  defined  in  top-­‐‑level  invocation  of  interpreter > The  set  of  built-­‐‑in  names  (functions,  exceptions) > Global  names  in  a  module  (including  imports) > Local  names  in  a  function  invocation > Names  defined  in  top-­‐‑level  invocation  of  interpreter Python  namespaces examplesPython  namespaces examples
  • 18. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } There  is  no  relation  between  names  in   different  namespaces Two  modules  or  functions  may  define  the  same   name  without  confusion There  is  no  relation  between  names  in   different  namespaces Two  modules  or  functions  may  define  the  same   name  without  confusion Python  namespacesPython  namespaces
  • 19. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Namespaces  are  created  (and  deleted)   at  different  moments  and  have   different  lifetimes Namespaces  are  created  (and  deleted)   at  different  moments  and  have   different  lifetimes Python  namespacesPython  namespaces
  • 20. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } The  built-­‐‑ins  namespace is  created   when  the  Python  interpreter  starts And  is  never  deleted The  built-­‐‑ins  namespace is  created   when  the  Python  interpreter  starts And  is  never  deleted Python  namespaces lifetimesPython  namespaces lifetimes
  • 21. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  module  global  namespace is   created  when  the  module  definition  is   read-­‐‑in  (when  it  is  imported) Normally  it  lasts  until  the  interpreter  quits A  module  global  namespace is   created  when  the  module  definition  is   read-­‐‑in  (when  it  is  imported) Normally  it  lasts  until  the  interpreter  quits Python  namespaces lifetimesPython  namespaces lifetimes
  • 22. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  function  local  namespace is   created  each  time  it  is  called It  is  deleted  when  the  function  returns  or  raises A  function  local  namespace is   created  each  time  it  is  called It  is  deleted  when  the  function  returns  or  raises Python  namespaces lifetimesPython  namespaces lifetimes
  • 23. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } And  what  about  Python  scopes?And  what  about  Python  scopes?
  • 24. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  scope is  a  textual  region   of  a  program  where  a   namespace  is  directly   accessible A  scope is  a  textual  region   of  a  program  where  a   namespace  is  directly   accessible
  • 25. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Scopes  are  determined  statically but  used  dynamically Scopes  are  determined  statically but  used  dynamically Python  scopesPython  scopes
  • 26. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } At  any  time  during  execution,  there   are  at  least  three  nested  scopes whose   namespaces  are  directly  accessible At  any  time  during  execution,  there   are  at  least  three  nested  scopes whose   namespaces  are  directly  accessible Python  scopesPython  scopes
  • 27. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } 1. The  innermost  scope  contains  the  local   names > The  scopes  of  any  enclosing  functions,   with  non-­‐‑local,  but  also  non-­‐‑global  names 2. The  next-­‐‑to-­‐‑last  scope  contains  the   current  module'ʹs  global  names 3. The  outermost  scope  is  the  namespace   containing  built-­‐‑in  names 1. The  innermost  scope  contains  the  local   names > The  scopes  of  any  enclosing  functions,   with  non-­‐‑local,  but  also  non-­‐‑global  names 2. The  next-­‐‑to-­‐‑last  scope  contains  the   current  module'ʹs  global  names 3. The  outermost  scope  is  the  namespace   containing  built-­‐‑in  names Python  nested scopesPython  nested scopes
  • 28. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Names  are  searched  in  nested  scopes   from  inside  out From  locals  to  built-­‐‑ins Read-­‐‑only  access  except  for  globals Names  are  searched  in  nested  scopes   from  inside  out From  locals  to  built-­‐‑ins Read-­‐‑only  access  except  for  globals Python  nested  scopesPython  nested  scopes
  • 29. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } $ python Python 2.7.5 (default, Aug 25 2013, 00:04:04) [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang- 500.0.68)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import cache >>> cache.set_key("my_key", 7) >>> cache.get_key("my_key") 7 >>> Python  scopesPython  scopes """ Simple cache implementation """ from collections import OrderedDict CACHE = OrderedDict() MAX_SIZE = 100 def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False) def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None)
  • 30. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } $ python Python 2.7.5 (default, Aug 25 2013, 00:04:04) [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang- 500.0.68)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import cache >>> cache.set_key("my_key", 7) >>> cache.get_key("my_key") 7 >>> Python  scopesPython  scopes """ Simple cache implementation """ from collections import OrderedDict CACHE = OrderedDict() MAX_SIZE = 100 def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False) def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None) The  outermost  scope: built-­‐‑in  names The  next-­‐‑to-­‐‑last  scope: current  module’s  global  names The  innermost  scope: current  local  names
  • 31. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Another  more  complex  caseAnother  more  complex  case def get_power_func(y): print("Creating function to raise to {}".format(y)) def power_func(x): print("Calling to raise {} to power of {}".format(x, y)) x = pow(x, y) return x return power_func >>> raise_to_4 = get_power_func(4) Creating function to raise to 4 >>> x = 3 >>> print(raise_to_4(x)) Calling to raise 3 to power of 4 81 >>> print(x) 3
  • 32. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Where  is  y defined?Where  is  y defined? def get_power_func(y): print("Creating function to raise to {}".format(y)) def power_func(x): print("Calling to raise {} to power of {}".format(x, y)) x = pow(x, y) return x return power_func >>> raise_to_4 = get_power_func(4) Creating function to raise to 4 >>> x = 3 >>> print(raise_to_4(x)) Calling to raise 3 to power of 4 81 >>> print(x) 3
  • 33. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } def get_power_func(y): print("Creating function to raise to {}".format(y)) def power_func(x): print("Calling to raise {} to power of {}".format(x, y)) x = pow(x, y) return x return power_func >>> raise_to_4 = get_power_func(4) Creating function to raise to 4 >>> x = 3 >>> print(raise_to_4(x)) Calling to raise 3 to power of 4 81 >>> print(x) 3 Nested  scopesNested  scopes The  next-­‐‑to-­‐‑last  scope: current  module’s  global  names Enclosing  function  scope: non-­‐‑local  non-­‐‑global  names The  innermost  scope:  local  names
  • 34. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } def get_power_func(y): print("Creating function to raise to {}".format(y)) def power_func(x): print("Calling to raise {} to power of {}".format(x, y)) x = pow(x, y) return x return power_func >>> raise_to_4 = get_power_func(4) Creating function to raise to 4 >>> print(raise_to_4.__globals__) {'x': 3, 'raise_to_4': <function get_power_func.<locals>.power_func at 0x100658488>, 'get_power_func': <function get_power_func at 0x1003b6048>, ...} >>> print(raise_to_4.__closure__) (<cell at 0x10065f048: int object at 0x10023b280>,) There  is  a  closure!There  is  a  closure!
  • 35. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  function  closure is  a   reference  to  each  of  the  non-­‐‑ local  variables  of  the  function A  function  closure is  a   reference  to  each  of  the  non-­‐‑ local  variables  of  the  function
  • 36. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } def get_power_func(y): print("Creating function to raise to {}".format(y)) def power_func(x): print("Calling to raise {} to power of {}".format(x, y)) x = pow(x, y) return x return power_func >>> raise_to_4 = get_power_func(4) Creating function to raise to 4 >>> print(raise_to_4.__globals__) {'x': 3, 'raise_to_4': <function get_power_func.<locals>.power_func at 0x100658488>, 'get_power_func': <function get_power_func at 0x1003b6048>, ...} >>> print(raise_to_4.__closure__) (<cell at 0x10065f048: int object at 0x10023b280>,) So,  where  is  y defined?So,  where  is  y defined? The  innermost  scope:  local  names Enclosing  function  scope The  next-­‐‑to-­‐‑last  scope: current  module’s  global  names
  • 37. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
  • 38. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Maybe  you  are  wondering where  are  the decorators in  this  talk… Maybe  you  are  wondering where  are  the decorators in  this  talk…
  • 39. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } So,  let’s  manually apply  a  decoratorSo,  let’s  manually apply  a  decorator
  • 40. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Let’s  go  back  to  these  functionsLet’s  go  back  to  these  functions def factorial(n): "Return n! (the factorial of n): n! = n * (n-1)!" if n < 2: return 1 return n * factorial(n - 1) >>> start = time.time() >>> factorial(35) 10333147966386144929666651337523200000000 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0007369518280029297 def fibonacci(n): "Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)" if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> start = time.time() >>> fibonacci(35) 9227465 >>> print("Elapsed:", time.time() - start) Elapsed: 6.916048049926758
  • 41. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } fibonacci(5)  recursive  calls  graphfibonacci(5)  recursive  calls  graph 5 4 3 1 2 1 02 1 0 3 2 1 01
  • 42. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Do  you  remember  we  have  a  cache?Do  you  remember  we  have  a  cache? from collections import OrderedDict CACHE = OrderedDict() MAX_SIZE = 100 def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False) def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None) >>> set_key("my_key", "the_value") >>> print(get_key("my_key")) the_value >>> print(get_key("not_found_key")) None
  • 43. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
  • 44. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } What  about  this  version?What  about  this  version? import cache def fibonacci(n): "Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)" if n < 2: return n fib = cache.get_key(n) if fib is None: fib = fibonacci(n - 1) + fibonacci(n - 2) cache.set_key(n, fib) return fib >>> start = time.time() >>> fibonacci(35) 9227465 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0007810592651367188 >>> start = time.time() >>> fibonacci(100) 354224848179261915075 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0013179779052734375
  • 45. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } DRY:  Don’t  Repeat  Yourself!DRY:  Don’t  Repeat  Yourself! import cache def fibonacci(n): "Return nth fibonacci number: fib(n) = fib(n-1) + fib(n-2)" if n < 2: return n fib = cache.get_key(n) if fib is None: fib = fibonacci(n - 1) + fibonacci(n - 2) cache.set_key(n, fib) return fib >>> start = time.time() >>> fibonacci(35) 9227465 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0007810592651367188 >>> start = time.time() >>> fibonacci(100) 354224848179261915075 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0013179779052734375
  • 46. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Pay  attention  to  the  magic  trickPay  attention  to  the  magic  trick
  • 47. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Original  function  is  not  modifiedOriginal  function  is  not  modified import time import cache def fibonacci(n): # The function remains unchanged if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> real_fibonacci = fibonacci def fibonacci(n): fib = cache.get_key(n) if fib is None: fib = real_fibonacci(n) cache.set_key(n, fib) return fib >>> start = time.time() >>> fibonacci(35) 9227465 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0010080337524414062
  • 48. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Which  function is  called  here?Which  function is  called  here? import time import cache def fibonacci(n): # The function remains unchanged if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> real_fibonacci = fibonacci def fibonacci(n): fib = cache.get_key(n) if fib is None: fib = real_fibonacci(n) cache.set_key(n, fib) return fib >>> start = time.time() >>> fibonacci(35) 9227465 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0010080337524414062
  • 49. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } import time import cache def fibonacci(n): # The function remains unchanged if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> real_fibonacci = fibonacci def fibonacci(n): fib = cache.get_key(n) if fib is None: fib = real_fibonacci(n) cache.set_key(n, fib) return fib >>> start = time.time() >>> fibonacci(35) 9227465 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0010080337524414062 Remember  the  scopes…Remember  the  scopes… The  next-­‐‑to-­‐‑last  scope: current  module’s  global  names The  innermost  scope: current  local  names
  • 50. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } And  now  the  trick  in  slow  motionAnd  now  the  trick  in  slow  motion
  • 51. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } 1.  Create  original  fibonacci function1.  Create  original  fibonacci function def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> print(id(fibonacci)) 4298858568 { fibonacci:  4298858568 } Global  names 4298858568:  <function  fibonacci at  0x1003b6048> if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) Objects
  • 52. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } 2.  Create  alternative  name  pointing   to  the  same  function  object 2.  Create  alternative  name  pointing   to  the  same  function  object def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> print(id(fibonacci)) 4298858568 >>> real_fib = fibonacci { fibonacci:  4298858568, real_fib:        4298858568, } Global  names 4298858568:  <function  fibonacci at  0x1003b6048> if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) Objects
  • 53. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } 3.  Replace  original  name  with  new  a   function  which  calls  the  alternative  name 3.  Replace  original  name  with  new  a   function  which  calls  the  alternative  name def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> print(id(fibonacci)) 4298858568 >>> real_fib = fibonacci def fibonacci(n): fib = cache.get_key(n) if fib is None: fib = real_fib (n) cache.set_key(n, fib) return fib >>> print(id(fibonacci)) 4302081696 >>> print(id(real_fib)) 4298858568 { fibonacci:  4302081696, real_fib:        4298858568, } Global  names 4298858568:  <function  fibonacci at  0x1003b6048> if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) 4302081696:  <function  fibonacci at  0x1006c8ea0> fib = cache.get_key(n) if fib is None: fib = real_fib (n) cache.set_key(n, fib) return fib Objects
  • 54. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } This  way  we  swap  both  functionsThis  way  we  swap  both  functions def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> print(id(fibonacci)) 4298858568 >>> real_fib = fibonacci def fibonacci(n): fib = cache.get_key(n) if fib is None: fib = real_fib (n) cache.set_key(n, fib) return fib >>> print(id(fibonacci)) 4302081696 >>> print(id(real_fib)) 4298858568 { fibonacci:  4302081696, real_fib:        4298858568, } Global  names 4298858568:  <function  fibonacci at  0x1003b6048> if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) 4302081696:  <function  fibonacci at  0x1006c8ea0> fib = cache.get_key(n) if fib is None: fib = real_fib (n) cache.set_key(n, fib) return fib Objects
  • 55. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } But  the  original  function  does  not  know  itBut  the  original  function  does  not  know  it def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> print(id(fibonacci)) 4298858568 >>> real_fib = fibonacci def fibonacci(n): fib = cache.get_key(n) if fib is None: fib = real_fib (n) cache.set_key(n, fib) return fib >>> print(id(fibonacci)) 4302081696 >>> print(id(real_fib)) 4298858568 { fibonacci:  4302081696, real_fib:        4298858568, } Global  names 4298858568:  <function  fibonacci at  0x1003b6048> if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) 4302081696:  <function  fibonacci at  0x1006c8ea0> fib = cache.get_key(n) if fib is None: fib = real_fib (n) cache.set_key(n, fib) return fib Objects
  • 56. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  }
  • 57. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Let’s  make  this  trick  fully  reusableLet’s  make  this  trick  fully  reusable
  • 58. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Let’s  make  it  work  with  any*  functionLet’s  make  it  work  with  any*  function
  • 59. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  factory  of  memoization functionsA  factory  of  memoization functions import cache def memoize_any_function(func_to_memoize): "Return a wrapped version of the function using memoization" def memoized_version_of_func(n): "Wrapper using memoization" res = cache.get_key(n) if res is None: res = func_to_memoize(n) # Call the real function cache.set_key(n, res) return res return memoized_version_of_func def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> fibonacci = memoize_any_function(fibonacci)
  • 60. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } A  factory  of  memoization functionsA  factory  of  memoization functions import cache def memoize_any_function(func_to_memoize): "Return a wrapped version of the function using memoization" def memoized_version_of_func(n): "Wrapper using memoization" res = cache.get_key(n) if res is None: res = func_to_memoize(n) # Call the real function cache.set_key(n, res) return res return memoized_version_of_func def factorial(n): if n < 2: return 1 return n * factorial(n - 1) >>> factorial= memoize_any_function(factorial)
  • 61. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } It  works  with  any*  functionIt  works  with  any*  function import time >>> start = time.time() >>> fibonacci(250) 7896325826131730509282738943634332893686268675876375 >>> print("Elapsed:", time.time() - start) Elapsed: 0.0009610652923583984 >>> start = time.time() >>> factorial(250) 32328562609091077323208145520243684709948437176737806667479424271 12823747555111209488817915371028199450928507353189432926730931712 80899082279103027907128192167652724018926473321804118626100683292 53651336789390895699357135301750405131787600772479330654023390061 64825552248819436572586057399222641254832982204849137721776650641 27685880715312897877767295191399084437747870258917297325515028324 17873206581884820624785826598088488255488000000000000000000000000 00000000000000000000000000000000000000 >>> print("Elapsed:", time.time() - start) Elapsed: 0.00249481201171875
  • 62. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } And  finally,  at  long  last,  decoratorsAnd  finally,  at  long  last,  decorators
  • 63. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Pay  attention…Pay  attention… import cache def memoize_any_function(func_to_memoize): "Return a wrapped version of the function using memoization" def memoized_version_of_func(n): "Wrapper using memoization" res = cache.get_key(n) if res is None: res = func_to_memoize(n) # Call the real function cache.set_key(n, res) return res return memoized_version_of_func def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> fibonacci = memoize_any_function(fibonacci)
  • 64. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Did  you  spot  the  difference?Did  you  spot  the  difference? import cache def memoize_any_function(func_to_memoize): "Return a wrapped version of the function using memoization" def memoized_version_of_func(n): "Wrapper using memoization" res = cache.get_key(n) if res is None: res = func_to_memoize(n) # Call the real function cache.set_key(n, res) return res return memoized_version_of_func @memoize_any_function def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2)
  • 65. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Did  you  spot  the  difference?Did  you  spot  the  difference? import cache def memoize_any_function(func_to_memoize): "Return a wrapped version of the function using memoization" def memoized_version_of_func(n): "Wrapper using memoization" res = cache.get_key(n) if res is None: res = func_to_memoize(n) # Call the real function cache.set_key(n, res) return res return memoized_version_of_func @memoize_any_function def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2)
  • 66. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } This  is  the  only  thing  the  @  does Calls  a  decorator  providing  the  decorated   function,  then  makes  the  function  name  point  to   the  result This  is  the  only  thing  the  @  does Calls  a  decorator  providing  the  decorated   function,  then  makes  the  function  name  point  to   the  result Decorators  demystifiedDecorators  demystified def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> fibonacci = memoize_any_function(fibonacci) @memoize_any_function def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n – 2)
  • 67. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } This  is  the  only  thing  the  @  does Calls  a  decorator  providing  the  decorated   function,  then  makes  the  function  name  point  to   the  result This  is  the  only  thing  the  @  does Calls  a  decorator  providing  the  decorated   function,  then  makes  the  function  name  point  to   the  result Decorators  demystifiedDecorators  demystified def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) >>> fibonacci = memoize_any_function(fibonacci) @memoize_any_function def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n – 2)
  • 68. {  "ʺevent"ʺ:  "ʺEuroPython 2015"ʺ,  "ʺauthor"ʺ:  "ʺPablo  Enfedaque"ʺ,  "ʺtwitter"ʺ:  "ʺ@pablitoev56"ʺ  } Q&AQ&A Thanks  for  coming! Slides:  https://goo.gl/fMP4jH Thanks  for  coming! Slides:  https://goo.gl/fMP4jH