{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 修饰符的使用" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## @classmethod 修饰符" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "在 `Python` 标准库中,有很多自带的修饰符,例如 `classmethod` 将一个对象方法转换了类方法: " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Foo(object):\n", " @classmethod\n", " def bar(cls, x):\n", " print 'the input is', x\n", " \n", " def __init__(self):\n", " pass\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "类方法可以通过 `类名.方法` 来调用:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the input is 12\n" ] } ], "source": [ "Foo.bar(12)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## @property 修饰符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "有时候,我们希望像 __Java__ 一样支持 `getters` 和 `setters` 的方法,这时候就可以使用 `property` 修饰符:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Foo(object):\n", " def __init__(self, data):\n", " self.data = data\n", " \n", " @property\n", " def x(self):\n", " return self.data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "此时可以使用 `.x` 这个属性查看数据(不需要加上括号):" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "23" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "foo = Foo(23)\n", "foo.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这样做的好处在于,这个属性是只读的:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "can't set attribute", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfoo\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m: can't set attribute" ] } ], "source": [ "foo.x = 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "如果想让它变成可读写,可以加上一个修饰符 `@x.setter`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Foo(object):\n", " def __init__(self, data):\n", " self.data = data\n", " \n", " @property\n", " def x(self):\n", " return self.data\n", " \n", " @x.setter\n", " def x(self, value):\n", " self.data = value" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "23\n" ] } ], "source": [ "foo = Foo(23)\n", "print foo.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以通过属性改变它的值:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] } ], "source": [ "foo.x = 1\n", "print foo.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numpy 的 @vectorize 修饰符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`numpy` 的 `vectorize` 函数讲一个函数转换为 `ufunc`,事实上它也是一个修饰符:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([-10., -9., -8., -7., -6., -5., -4., -3., -2., -1., 0.,\n", " 0., 0., 0., 0., 0., 0., 0., 0., 0.])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from numpy import vectorize, arange\n", "\n", "@vectorize\n", "def f(x):\n", " if x <= 0:\n", " return x\n", " else:\n", " return 0\n", "\n", "f(arange(-10.0,10.0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 注册一个函数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "来看这样的一个例子,定义一个类:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Registry(object):\n", " def __init__(self):\n", " self._data = {}\n", " def register(self, f, name=None):\n", " if name == None:\n", " name = f.__name__\n", " self._data[name] = f\n", " setattr(self, name, f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`register` 方法接受一个函数,将这个函数名作为属性注册到对象中。\n", "\n", "产生该类的一个对象:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "registry = Registry()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用该对象的 `register` 方法作为修饰符:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "@registry.register\n", "def greeting():\n", " print \"hello world\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这样这个函数就被注册到 `registry` 这个对象中去了:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "{'greeting': }" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "registry._data" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "registry.greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[flask](flask.pocoo.org) ,一个常用的网络应用,处理 url 的机制跟这个类似。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 使用 @wraps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "一个通常的问题在于:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None wrapper\n" ] } ], "source": [ "def logging_call(f):\n", " def wrapper(*a, **kw):\n", " print 'calling {}'.format(f.__name__)\n", " return f(*a, **kw)\n", " return wrapper\n", "\n", "@logging_call\n", "def square(x):\n", " '''\n", " square function.\n", " '''\n", " return x ** 2\n", "\n", "print square.__doc__, square.__name__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我们使用修饰符之后,`square` 的 `metadata` 完全丢失了,返回的函数名与函数的 `docstring` 都不对。\n", "\n", "一个解决的方法是从 `functools` 模块导入 `wraps` 修饰符来修饰我们的修饰符:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " square function.\n", " square\n" ] } ], "source": [ "import functools\n", "\n", "def logging_call(f):\n", " @functools.wraps(f)\n", " def wrapper(*a, **kw):\n", " print 'calling {}'.format(f.__name__)\n", " return f(*a, **kw)\n", " return wrapper\n", "\n", "@logging_call\n", "def square(x):\n", " '''\n", " square function.\n", " '''\n", " return x ** 2\n", "\n", "print square.__doc__, square.__name__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "现在这个问题解决了,所以在自定义修饰符方法的时候为了避免出现不必要的麻烦,尽量使用 `wraps` 来修饰修饰符!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Class 修饰符" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "与函数修饰符类似,类修饰符是这样一类函数,接受一个类作为参数,通常返回一个新的类。" ] } ], "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 }