{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 修饰符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 函数是一种对象" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "在 `Python` 中,函数是也是一种对象。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "def foo(x):\n", " print x\n", " \n", "print(type(foo))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "查看函数拥有的方法:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['__call__',\n", " '__class__',\n", " '__closure__',\n", " '__code__',\n", " '__defaults__',\n", " '__delattr__',\n", " '__dict__',\n", " '__doc__',\n", " '__format__',\n", " '__get__',\n", " '__getattribute__',\n", " '__globals__',\n", " '__hash__',\n", " '__init__',\n", " '__module__',\n", " '__name__',\n", " '__new__',\n", " '__reduce__',\n", " '__reduce_ex__',\n", " '__repr__',\n", " '__setattr__',\n", " '__sizeof__',\n", " '__str__',\n", " '__subclasshook__',\n", " 'func_closure',\n", " 'func_code',\n", " 'func_defaults',\n", " 'func_dict',\n", " 'func_doc',\n", " 'func_globals',\n", " 'func_name']" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dir(foo)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "在这些方法中,`__call__` 是最重要的一种方法: " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "42\n" ] } ], "source": [ "foo.__call__(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "相当于:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "42\n" ] } ], "source": [ "foo(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "因为函数是对象,所以函数可以作为参数传入另一个函数:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def bar(f, x):\n", " x += 1\n", " f(x)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] } ], "source": [ "bar(foo, 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 修饰符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "修饰符是这样的一种函数,它接受一个函数作为输入,通常输出也是一个函数:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def dec(f):\n", " print 'I am decorating function', id(f)\n", " return f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "将 `len` 函数作为参数传入这个修饰符函数:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am decorating function 33716168\n" ] } ], "source": [ "declen = dec(len)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用这个新生成的函数:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "declen([10,20,30])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上面的例子中,我们仅仅返回了函数的本身,也可以利用这个函数生成一个新的函数,看一个新的例子:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def loud(f):\n", " def new_func(*args, **kw):\n", " print 'calling with', args, kw\n", " rtn = f(*args, **kw)\n", " print 'return value is', rtn\n", " return rtn\n", " return new_func" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [], "source": [ "loudlen = loud(len)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "calling with ([10, 20, 30],) {}\n", "return value is 3\n" ] }, { "data": { "text/plain": [ "3" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "loudlen([10, 20, 30])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 用 @ 来使用修饰符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Python` 使用 `@` 符号来将某个函数替换为修饰符之后的函数: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "例如这个函数:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am decorating function 64021672\n" ] } ], "source": [ "def foo(x):\n", " print x\n", " \n", "foo = dec(foo)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以替换为:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am decorating function 64021112\n" ] } ], "source": [ "@dec\n", "def foo(x):\n", " print x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "事实上,如果修饰符返回的是一个函数,那么可以链式的使用修饰符:\n", "\n", "```python\n", "@dec1\n", "@dec2\n", "def foo(x):\n", " print x\n", "```\n", "\n", "使用修饰符 `loud` 来定义这个函数:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [], "source": [ "@loud\n", "def foo(x):\n", " print x" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "calling with (42,) {}\n", "42\n", "return value is None\n" ] } ], "source": [ "foo(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 例子" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "定义两个修饰器函数,一个将原来的函数值加一,另一个乘二:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def plus_one(f):\n", " def new_func(x):\n", " return f(x) + 1\n", " return new_func\n", "\n", "def times_two(f):\n", " def new_func(x):\n", " return f(x) * 2\n", " return new_func" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "定义函数,先乘二再加一:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true }, "outputs": [], "source": [ "@plus_one\n", "@times_two\n", "def foo(x):\n", " return int(x)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "27" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "foo(13)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 修饰器工厂" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`decorators factories` 是返回修饰器的函数,例如:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def super_dec(x, y, z):\n", " def dec(f):\n", " def new_func(*args, **kw):\n", " print x + y + z\n", " return f(*args, **kw)\n", " return new_func\n", " return dec" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "它的作用在于产生一个可以接受参数的修饰器,例如我们想将 `loud` 输出的内容写入一个文件去,可以这样做:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def super_loud(filename):\n", " fp = open(filename, 'w')\n", " def loud(f):\n", " def new_func(*args, **kw):\n", " fp.write('calling with' + str(args) + str(kw))\n", " # 确保内容被写入\n", " fp.flush()\n", " fp.close()\n", " rtn = f(*args, **kw)\n", " return rtn\n", " return new_func\n", " return loud" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以这样使用这个修饰器工厂:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [], "source": [ "@super_loud('test.txt')\n", "def foo(x):\n", " print x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "调用 `foo` 就会在文件中写入内容:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12\n" ] } ], "source": [ "foo(12)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "查看文件内容:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "calling with(12,){}\n" ] } ], "source": [ "with open('test.txt') as fp:\n", " print fp.read()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import os\n", "os.remove('test.txt')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.10" } }, "nbformat": 4, "nbformat_minor": 0 }