{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 函数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 定义函数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "函数`function`,通常接受输入参数,并有返回值。\n", "\n", "它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def add(x, y):\n", " \"\"\"Add two numbers\"\"\"\n", " a = x + y\n", " return a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "函数通常有一下几个特征:\n", "- 使用 `def` 关键词来定义一个函数。\n", "- `def` 后面是函数的名称,括号中是函数的参数,不同的参数用 `,` 隔开, `def foo():` 的形式是必须要有的,参数可以为空;\n", "- 使用缩进来划分函数的内容;\n", "- `docstring` 用 `\"\"\"` 包含的字符串,用来解释函数的用途,可省略;\n", "- `return` 返回特定的值,如果省略,返回 `None` 。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 使用函数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用函数时,只需要将参数换成特定的值传给函数。\n", "\n", "**Python**并没有限定参数的类型,因此可以使用不同的参数类型:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n", "foobar\n" ] } ], "source": [ "print add(2, 3)\n", "print add('foo', 'bar')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "在这个例子中,如果传入的两个参数不可以相加,那么**Python**会将报错:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'int' and 'str'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\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[1;32mprint\u001b[0m \u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"foo\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m\u001b[0m in \u001b[0;36madd\u001b[1;34m(x, y)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;34m\"\"\"Add two numbers\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0ma\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'" ] } ], "source": [ "print add(2, \"foo\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "如果传入的参数数目与实际不符合,也会报错:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "add() takes exactly 2 arguments (3 given)", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\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[1;32mprint\u001b[0m \u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: add() takes exactly 2 arguments (3 given)" ] } ], "source": [ "print add(1, 2, 3)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "add() takes exactly 2 arguments (1 given)", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\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[1;32mprint\u001b[0m \u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: add() takes exactly 2 arguments (1 given)" ] } ], "source": [ "print add(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "传入参数时,Python提供了两种选项,第一种是上面使用的按照位置传入参数,另一种则是使用关键词模式,显式地指定参数的值:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n", "barfoo\n" ] } ], "source": [ "print add(x=2, y=3)\n", "print add(y=\"foo\", x=\"bar\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以混合这两种模式:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] } ], "source": [ "print add(2, y=3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 设定参数默认值" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以在函数定义的时候给参数设定默认值,例如:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def quad(x, a=1, b=0, c=0):\n", " return a*x**2 + b*x + c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以省略有默认值的参数:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4.0\n" ] } ], "source": [ "print quad(2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以修改参数的默认值:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10.0\n" ] } ], "source": [ "print quad(2.0, b=3)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12.0\n" ] } ], "source": [ "print quad(2.0, 2, c=4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这里混合了位置和指定两种参数传入方式,第二个2是传给 `a` 的。\n", "\n", "注意,在使用混合语法时,要注意不能给同一个值赋值多次,否则会报错,例如:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "quad() got multiple values for keyword argument 'a'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\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[1;32mprint\u001b[0m \u001b[0mquad\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2.0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: quad() got multiple values for keyword argument 'a'" ] } ], "source": [ "print quad(2.0, 2, a=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 接收不定参数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用如下方法,可以使函数接受不定数目的参数:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def add(x, *args):\n", " total = x\n", " for arg in args:\n", " total += arg\n", " return total" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这里,`*args` 表示参数数目不定,可以看成一个元组,把第一个参数后面的参数当作元组中的元素。" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10\n", "3\n" ] } ], "source": [ "print add(1, 2, 3, 4)\n", "print add(1, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这样定义的函数不能使用关键词传入参数,要使用关键词,可以这样:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def add(x, **kwargs):\n", " total = x\n", " for arg, value in kwargs.items():\n", " print \"adding \", arg\n", " total += value\n", " return total" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这里, `**kwargs` 表示参数数目不定,相当于一个字典,关键词和值对应于键值对。" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "adding y\n", "adding z\n", "adding w\n", "46\n" ] } ], "source": [ "print add(10, y=11, z=12, w=13)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "再看这个例子,可以接收任意数目的位置参数和键值对参数:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(2, 3) {'x': 'bar', 'z': 10}\n" ] } ], "source": [ "def foo(*args, **kwargs):\n", " print args, kwargs\n", "\n", "foo(2, 3, x='bar', z=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "不过要按顺序传入参数,先传入位置参数 `args` ,在传入关键词参数 `kwargs` 。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 返回多个值" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "函数可以返回多个值:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5.0 0.927295218002\n" ] } ], "source": [ "from math import atan2\n", "\n", "def to_polar(x, y):\n", " r = (x**2 + y**2) ** 0.5\n", " theta = atan2(y, x)\n", " return r, theta\n", "\n", "r, theta = to_polar(3, 4)\n", "print r, theta" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "事实上,**Python**将返回的两个值变成了元组:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(5.0, 0.9272952180016122)\n" ] } ], "source": [ "print to_polar(3, 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "因为这个元组中有两个值,所以可以使用\n", "\n", " r, theta = to_polar(3, 4)\n", "\n", "给两个值赋值。\n", "\n", "列表也有相似的功能:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 2 3\n" ] } ], "source": [ "a, b, c = [1, 2, 3]\n", "print a, b, c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "事实上,不仅仅返回值可以用元组表示,也可以将参数用元组以这种方式传入:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] } ], "source": [ "def add(x, y):\n", " \"\"\"Add two numbers\"\"\"\n", " a = x + y\n", " return a\n", " \n", "z = (2, 3)\n", "print add(*z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这里的`*`必不可少。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "事实上,还可以通过字典传入参数来执行函数:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] } ], "source": [ "def add(x, y):\n", " \"\"\"Add two numbers\"\"\"\n", " a = x + y\n", " return a\n", "\n", "w = {'x': 2, 'y': 3}\n", "print add(**w)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## map 方法生成序列" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以通过 `map` 的方式利用函数来生成序列:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[4, 9, 16]\n" ] } ], "source": [ "def sqr(x): \n", " return x ** 2\n", "\n", "a = [2,3,4]\n", "print map(sqr, a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "其用法为:\n", " \n", " map(aFun, aSeq)\n", "\n", "将函数 `aFun` 应用到序列 `aSeq` 上的每一个元素上,返回一个列表,不管这个序列原来是什么类型。\n", "\n", "事实上,根据函数参数的多少,`map` 可以接受多组序列,将其对应的元素作为参数传入函数:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[12, 8, 7]\n" ] } ], "source": [ "def add(x, y): \n", " return x + y\n", "\n", "a = (2,3,4)\n", "b = [10,5,3]\n", "print map(add,a,b)" ] } ], "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 }