13. "@" decorators

最後更新: 2015-02-24

DOC:

http://thecodeship.com/patterns/guide-to-python-function-decorators/
https://pythonconquerstheuniverse.wordpress.com/2012/04/29/python-decora...
https://wiki.python.org/moin/PythonDecoratorLibrary

 


什麼是 "@"

 

* decorators = macros
* decorators = Nested functions
* outer is a constructor for inner

Nested functions

def outer():
    x = 1
    def inner():
        print x
    inner() # 2

outer()

# you can pass functions to functions as arguments

def add(x, y):
    return x + y

def sub(x, y):
    return x - y

def apply(func, x, y):
    return func(x, y)

apply(add, 2, 1) # 3

# return functions from functions as return values!

def outer():
    def inner():
        print "Inside inner"
    return inner

foo = outer()
foo
<function inner at 0x...>

foo()
Inside inner

 

function closures

inner functions defined in non-global scope remember what their enclosing namespaces looked like at definition time.

def outer():
    x = 1
    def inner():
        print x # 1
    return inner

foo = outer()

outer is a constructor for inner with x acting like a private member variable.

 


decorators

 

returns a modified version of a function (add)

- it does something useful by checking and normalizing the input parameters(wrapper)

class Coordinate(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "Coord: " + str(self.__dict__)

def wrapper(func):
    def checker(a, b): # 1
        if a.x < 0 or a.y < 0:
            a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
        if b.x < 0 or b.y < 0:
            b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
        ret = func(a, b)
        if ret.x < 0 or ret.y < 0:
            ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
        return ret
    return checker


# "@" 有類似 "add = wrapper(add)" 的作用

@wrapper
def add(a, b):
    return Coordinate(a.x + b.x, a.y + b.y)

"@" 的作用

* Python just adds some syntactic sugar to make what is going on very explicit.
* "@" 這寫法有 "makes our code cleaner" 效果

 


*args  **kwargs 與 "@"

 

def logger(func):
    def inner(*args, **kwargs):
        print "Arguments were: %s, %s" % (args, kwargs)
        return func(*args, **kwargs)
    return inner

@logger
def foo1(x, y=2):
    return x * y


print foo1(5)

 

Creative Commons license icon Creative Commons license icon