跳转至

修饰符

函数是一种对象

Python 中,函数是也是一种对象。

In [1]:

def foo(x):
    print x

print(type(foo))
<type 'function'>

查看函数拥有的方法:

In [2]:

dir(foo)

Out[2]:

['__call__',
 '__class__',
 '__closure__',
 '__code__',
 '__defaults__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__get__',
 '__getattribute__',
 '__globals__',
 '__hash__',
 '__init__',
 '__module__',
 '__name__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'func_closure',
 'func_code',
 'func_defaults',
 'func_dict',
 'func_doc',
 'func_globals',
 'func_name']

在这些方法中,__call__ 是最重要的一种方法:

In [3]:

foo.__call__(42)
42

相当于:

In [4]:

foo(42)
42

因为函数是对象,所以函数可以作为参数传入另一个函数:

In [5]:

def bar(f, x):
    x += 1
    f(x)

In [6]:

bar(foo, 4)
5

修饰符

修饰符是这样的一种函数,它接受一个函数作为输入,通常输出也是一个函数:

In [7]:

def dec(f):
    print 'I am decorating function', id(f)
    return f

len 函数作为参数传入这个修饰符函数:

In [8]:

declen = dec(len)
I am decorating function 33716168

使用这个新生成的函数:

In [9]:

declen([10,20,30])

Out[9]:

3

上面的例子中,我们仅仅返回了函数的本身,也可以利用这个函数生成一个新的函数,看一个新的例子:

In [10]:

def loud(f):
    def new_func(*args, **kw):
        print 'calling with', args, kw
        rtn = f(*args, **kw)
        print 'return value is', rtn
        return rtn
    return new_func

In [11]:

loudlen = loud(len)

In [12]:

loudlen([10, 20, 30])
calling with ([10, 20, 30],) {}
return value is 3

Out[12]:

3

用 @ 来使用修饰符

Python 使用 @ 符号来将某个函数替换为修饰符之后的函数:

例如这个函数:

In [13]:

def foo(x):
    print x

foo = dec(foo)
I am decorating function 64021672

可以替换为:

In [14]:

@dec
def foo(x):
    print x
I am decorating function 64021112

事实上,如果修饰符返回的是一个函数,那么可以链式的使用修饰符:

@dec1
@dec2
def foo(x):
    print x

使用修饰符 loud 来定义这个函数:

In [15]:

@loud
def foo(x):
    print x

In [16]:

foo(42)
calling with (42,) {}
42
return value is None

例子

定义两个修饰器函数,一个将原来的函数值加一,另一个乘二:

In [17]:

def plus_one(f):
    def new_func(x):
        return f(x) + 1
    return new_func

def times_two(f):
    def new_func(x):
        return f(x) * 2
    return new_func

定义函数,先乘二再加一:

In [18]:

@plus_one
@times_two
def foo(x):
    return int(x)

In [19]:

foo(13)

Out[19]:

27

修饰器工厂

decorators factories 是返回修饰器的函数,例如:

In [20]:

def super_dec(x, y, z):
    def dec(f):
        def new_func(*args, **kw):
            print x + y + z
            return f(*args, **kw)
        return new_func
    return dec

它的作用在于产生一个可以接受参数的修饰器,例如我们想将 loud 输出的内容写入一个文件去,可以这样做:

In [21]:

def super_loud(filename):
    fp = open(filename, 'w')
    def loud(f):
        def new_func(*args, **kw):
            fp.write('calling with' + str(args) + str(kw))
            # 确保内容被写入
            fp.flush()
            fp.close()
            rtn = f(*args, **kw)
            return rtn
        return new_func
    return loud

可以这样使用这个修饰器工厂:

In [22]:

@super_loud('test.txt')
def foo(x):
    print x

调用 foo 就会在文件中写入内容:

In [23]:

foo(12)
12

查看文件内容:

In [24]:

with open('test.txt') as fp:
    print fp.read()
calling with(12,){}

In [25]:

import os
os.remove('test.txt')

我们一直在努力

apachecn/AiLearning

【布客】中文翻译组