05.12 修饰符

修饰符

函数是一种对象

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

1def foo(x):
2    print x
3    
4print(type(foo))
<type 'function'>

查看函数拥有的方法:

1dir(foo)
['__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__ 是最重要的一种方法:

1foo.__call__(42)
42

相当于:

1foo(42)
42

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

1def bar(f, x):
2    x += 1
3    f(x)
1bar(foo, 4)
5

修饰符

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

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

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

1declen = dec(len)
I am decorating function 33716168

使用这个新生成的函数:

1declen([10,20,30])
3

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

1def loud(f):
2    def new_func(*args, **kw):
3        print 'calling with', args, kw
4        rtn = f(*args, **kw)
5        print 'return value is', rtn
6        return rtn
7    return new_func
1loudlen = loud(len)
1loudlen([10, 20, 30])
calling with ([10, 20, 30],) {}
return value is 3





3

用 @ 来使用修饰符

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

例如这个函数:

1def foo(x):
2    print x
3    
4foo = dec(foo)
I am decorating function 64021672

可以替换为:

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

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

1@dec1
2@dec2
3def foo(x):
4    print x

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

1@loud
2def foo(x):
3    print x
1foo(42)
calling with (42,) {}
42
return value is None

例子

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

1def plus_one(f):
2    def new_func(x):
3        return f(x) + 1
4    return new_func
5
6def times_two(f):
7    def new_func(x):
8        return f(x) * 2
9    return new_func

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

1@plus_one
2@times_two
3def foo(x):
4    return int(x)
1foo(13)
27

修饰器工厂

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

1def super_dec(x, y, z):
2    def dec(f):
3        def new_func(*args, **kw):
4            print x + y + z
5            return f(*args, **kw)
6        return new_func
7    return dec

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

 1def super_loud(filename):
 2    fp = open(filename, 'w')
 3    def loud(f):
 4        def new_func(*args, **kw):
 5            fp.write('calling with' + str(args) + str(kw))
 6            # 确保内容被写入
 7            fp.flush()
 8            fp.close()
 9            rtn = f(*args, **kw)
10            return rtn
11        return new_func
12    return loud

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

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

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

1foo(12)
12

查看文件内容:

1with open('test.txt') as fp:
2    print fp.read()
calling with(12,){}
1import os
2os.remove('test.txt')