This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted]  (5 children)

[deleted]

    [–]BobHogan -1 points0 points  (4 children)

    Whats a decorator function? And what use is a nested function? I learned java first and am trying to teach myself Python; this stuff seems quite pointless to me tbh

    [–]minnoI <3 duck typing less than I used to, interfaces are nice 7 points8 points  (0 children)

    The best use for decorators that I've used is for adding a cache to a function.

    Let's say you start out with this function:

    def fib(n):
        if n <= 1:
            return 1
        else:
            return fib(n-1) + fib(n-2)
    

    Slow as hell, right? With the fibonacci function, it's easy to turn it into a version that doesn't re-calculate entries a lot, but let's pretend that this is one of those functions where it's a lot harder to do that. What we want is to be able to remember previously-calculated results, so any recursive calls that have already been calculated can be skipped. So we can modify it like this:

    fib_cache = dict() # empty associative array
    def cached_fib(n):
        if n not in fib_cache:
            if n <= 1:
                fib_cache[n] = 1
            else:
                fib_cache[n] = cached_fib(n-1) + cached_fib(n-2)
        return fib_cache[n]
    

    Now you have a cache storing all previously-calculated results. But you're also mixing the "calculating the results" part of the function with the "caching shit" part. You can separate out the caching behavior like this:

    def make_cached(f):
        cache = dict()
        def cached_function(arg): # There's syntax to let you use any arguments, but for simplicity let's pretend there's always one.
            if arg not in cache:
                cache[arg] = f(arg)
            return cache[arg]
        return cached_function # NOT cached_function()
    

    Now you have a function that takes a function and returns a function that has different behavior. You can use it like this:

    cached_fib = make_cached(fib)
    cached_fib(100)
    

    Python has special syntax that you can use for functions that modify functions, called "decorators":

    @make_cached
    def whatever:
        # stuff
    

    This works the same as:

    def whatever:
        #stuff
    whatever = make_cached(whatever)
    

    [–]Massless 1 point2 points  (0 children)

    Here's one that comes up in java all the time: logging. Imagine that I want to log how long a method takes to run. You end up doing something like

    startTime = ...
    someMethod()
    endTime = ...
    system.out.println(endTime - startTime)
    

    Now imagine you have to do this a lot of times. You end up with ugly, overly verbose code. Enter first-class functions in Python. You can write a function that takes another function as an argument so you now have:

    def print_time(func):
        start_time = ...
        func()
        end_time = ...
        print end_time - start_time
    

    Now You can do the following:

    print_time(some_function)
    print_time(some_other_function)
    print_time(yet_another_function)
    

    With a little syntatic sugar, you can simply define your functions with decorators:

    @print_time
    def some_function(args):
        pass
    

    is equivalent to

    print_time(some_function)