How to learn OO of python?

Steven Bethard steven.bethard at gmail.com
Thu May 19 03:03:12 EDT 2005


could ildg wrote:
> I think decorator is a function which return a function, is this right?
> e.g. The decorator below if from http://www.python.org/peps/pep-0318.html#id1.
> 
> def accepts(*types):
>     def check_accepts(f):
>         assert len(types) == f.func_code.co_argcount
>         def new_f(*args, **kwds):
>             for (a, t) in zip(args, types):
>                 assert isinstance(a, t), \
>                        "arg %r does not match %s" % (a,t)
>             return f(*args, **kwds)
>         new_f.func_name = f.func_name
>         return new_f
>     return check_accepts
> 
> After I saw all the examples, I concluded that every decorator must
> define an inner function which takes only one argument, the
> function to decorate. Is this right?

It's close, but not quite right.  (I will use the word "function" for 
the moment, but see below for why this is inaccurate.)  Every 
*decorator* must take only one argument, the function to decorate. It is 
not at all necessary that a decorator define an inner function. 
Consider (from [1]):

def onexit(f):
     import atexit
     atexit.register(f)
     return f

onexit is a decorator because it takes a function and returns a 
function.  In this case, it happens to be that the same function is 
accepted and returned.

Note that in the 'accepts' example above, *check_accepts* is the 
decorator, not accepts.  The accepts function is actually a function 
that *returns* decorators.

Now about that word "function".  Decorators are actually *callables* 
that accept a single *callable* and return a *callable*.  Why does the 
terminology matter?  Because I can construct decorators from classes too 
(from [2]):

class memoized(object):
    def __init__(self, func):
       self.func = func
       self.cache = {}
    def __call__(self, *args):
       try:
          return self.cache[args]
       except KeyError:
          self.cache[args] = value = self.func(*args)
          return value
       except TypeError:
          return self.func(*args)

Now the memoized decorator can be used just like any other decorator, e.g.:

@memoized
def fibonacci(n):
    if n in (0, 1):
       return n
    return fibonacci(n-1) + fibonacci(n-2)

Note however that memoized is a *callable*, not a *function*.

STeVe

[1] http://www.python.org/peps/pep-0318.html
[2] http://wiki.python.org/moin/PythonDecoratorLibrary



More information about the Python-list mailing list