<jupyter_start><jupyter_text>修饰符  函数是一种对象 在 `Python` 中，函数是也是一种对象。<jupyter_code>def foo(x):
    print x
    
print(type(foo))<jupyter_output><type 'function'><jupyter_text>查看函数拥有的方法：<jupyter_code>dir(foo)<jupyter_output><empty_output><jupyter_text>在这些方法中，`__call__` 是最重要的一种方法：<jupyter_code>foo.__call__(42)<jupyter_output>42<jupyter_text>相当于：<jupyter_code>foo(42)<jupyter_output>42<jupyter_text>因为函数是对象，所以函数可以作为参数传入另一个函数：<jupyter_code>def bar(f, x):
    x += 1
    f(x)
bar(foo, 4)<jupyter_output>5<jupyter_text>修饰符 修饰符是这样的一种函数，它接受一个函数作为输入，通常输出也是一个函数：<jupyter_code>def dec(f):
    print 'I am decorating function', id(f)
    return f<jupyter_output><empty_output><jupyter_text>将 `len` 函数作为参数传入这个修饰符函数：<jupyter_code>declen = dec(len)<jupyter_output>I am decorating function 33716168<jupyter_text>使用这个新生成的函数：<jupyter_code>declen([10,20,30])<jupyter_output><empty_output><jupyter_text>上面的例子中，我们仅仅返回了函数的本身，也可以利用这个函数生成一个新的函数，看一个新的例子：<jupyter_code>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
loudlen = loud(len)
loudlen([10, 20, 30])<jupyter_output>calling with ([10, 20, 30],) {}
return value is 3<jupyter_text>用 @ 来使用修饰符 `Python` 使用 `@` 符号来将某个函数替换为修饰符之后的函数：  例如这个函数：<jupyter_code>def foo(x):
    print x
    
foo = dec(foo)<jupyter_output>I am decorating function 64021672<jupyter_text>可以替换为：<jupyter_code>@dec
def foo(x):
    print x<jupyter_output>I am decorating function 64021112<jupyter_text>事实上，如果修饰符返回的是一个函数，那么可以链式的使用修饰符：```python@dec1@dec2def foo(x):    print x```使用修饰符 `loud` 来定义这个函数：<jupyter_code>@loud
def foo(x):
    print x
foo(42)<jupyter_output>calling with (42,) {}
42
return value is None<jupyter_text>例子 定义两个修饰器函数，一个将原来的函数值加一，另一个乘二：<jupyter_code>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<jupyter_output><empty_output><jupyter_text>定义函数，先乘二再加一：<jupyter_code>@plus_one
@times_two
def foo(x):
    return int(x)
foo(13)<jupyter_output><empty_output><jupyter_text>修饰器工厂 `decorators factories` 是返回修饰器的函数，例如：<jupyter_code>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<jupyter_output><empty_output><jupyter_text>它的作用在于产生一个可以接受参数的修饰器，例如我们想将 `loud` 输出的内容写入一个文件去，可以这样做：<jupyter_code>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<jupyter_output><empty_output><jupyter_text>可以这样使用这个修饰器工厂：<jupyter_code>@super_loud('test.txt')
def foo(x):
    print x<jupyter_output><empty_output><jupyter_text>调用 `foo` 就会在文件中写入内容：<jupyter_code>foo(12)<jupyter_output>12<jupyter_text>查看文件内容：<jupyter_code>with open('test.txt') as fp:
    print fp.read()
import os
os.remove('test.txt')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13557722554262347, 'fraction_numerical': 0.02201950298836112, 'mean_word_length': 5.334661354581673, 'pattern_counts': {'":': 0, '<': 68, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '517014', 'license': 'MIT', 'n_tokens_mistral': 1613, 'n_tokens_neox': 1640, 'n_words': 195, 'path': 'lijin-THU:notes-python/05-advanced-python/05.12-decorators.ipynb', 'repo_name': 'Maecenas/python-getting-started', 'size': '3179'}