{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" }, "toc": "true" }, "source": [ "# Table of Contents\n", "

1  函数式编程
1.1  背景
1.2  函数的定义
1.3  普通参数传递
1.4  指定参数传递
1.5  默认参数
1.6  关键字可变长参数
1.7  非关键字可变长参数
1.8  万能参数
1.9  注意事项
1.10  lambda表达式
1.11  装饰器
1.12  迭代器和生成器
1.13  生成器
1.14  递归
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# 函数式编程" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "面向过程:\n", "- 根据业务逻辑从上到下写垒代码\n", "\n", "函数式:\n", "- 将某功能代码封装到函数中,日后便无需重复编写,仅调用这个函数即可\n", "- 函数作用是你的程序有良好的扩展性、复用性。\n", "- 同样的功能要是用3次以上的话就建议使用函数。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "函数可以理解为:一个一个的 **功能块**,你把一个大的功能拆分成一块一块的,用某项功能的时候就去调用某个函数,\n", "\n", "函数可以理解为:乐高积木,给你一块一块的,你可以用这些积木块组成你最终想要实现的东西。\n", "\n", "函数可以调用函数!主函数(**main**)的作用就是把函数进行串联、调用!函数本身是不能自己执行的如果你不调用就永不执行!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 背景\n", "\n", "在学习函数之前,一直遵循:**面向过程编程**,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "while True:\n", " if cpu利用率 > 90%:\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", " \n", " if 硬盘使用空间 > 90%:\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", " \n", " if 内存占用 > 80%:\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "定眼一看上述代码,if条件语句下的内容可以被提取出来公用,如下:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def 发送邮件(内容)\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", "\n", "while True:\n", " \n", " if cpu利用率 > 90%:\n", " 发送邮件('CPU报警')\n", " \n", " if 硬盘使用空间 > 90%:\n", " 发送邮件('硬盘报警')\n", " \n", " if 内存占用 > 80%:\n", " 发送邮件('内存报警')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "对于上述的两种实现方式,第二次必然比第一次的重(chong)用性和可读性要好,其实这就是 **函数式编程** 和 **面向过程编程** 的区别:\n", "\n", "- 面向过程:根据业务逻辑从上到下写代码\n", "- 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 函数的定义" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def 函数名(参数):\n", " \n", " ...\n", " 函数体\n", " ..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "函数的定义主要有如下要点:\n", "\n", "- def:表示函数的关键字\n", "- 函数名:函数的名称,日后根据函数名调用函数\n", "- 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...\n", "- 参数:为函数体提供数据\n", "- 返回值:当函数执行完毕后,可以给调用者返回数据。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "以上要点中,比较重要有参数和返回值:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "1. 返回值\n", "\n", "函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def 发送短信():\n", "\n", " # 发送短信的代码...\n", " \n", " if 发送成功:\n", " return True\n", " else:\n", " return False\n", " \n", " \n", "while True:\n", " \n", " # 每次执行发送短信函数,都会将返回值自动赋值给result\n", " # 之后,可以根据result来写日志,或重发等操作\n", " \n", " result = 发送短信()\n", " if result == False:\n", " 记录日志,短信发送失败..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "2. 参数\n", "\n", "为什么要有参数?\n", "\n", "不使用参数:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def CPU报警邮件()\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", "\n", "def 硬盘报警邮件()\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", "\n", "def 内存报警邮件()\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", "\n", "while True:\n", " \n", " if cpu利用率 > 90%:\n", " CPU报警邮件()\n", " \n", " if 硬盘使用空间 > 90%:\n", " 硬盘报警邮件()\n", " \n", " if 内存占用 > 80%:\n", " 内存报警邮件()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "使用参数:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def 发送邮件(邮件内容)\n", "\n", " #发送邮件提醒\n", " 连接邮箱服务器\n", " 发送邮件\n", " 关闭连接\n", "\n", "\n", "while True:\n", " \n", " if cpu利用率 > 90%:\n", " 发送邮件(\"CPU报警了。\")\n", " \n", " if 硬盘使用空间 > 90%:\n", " 发送邮件(\"硬盘报警了。\")\n", " \n", " if 内存占用 > 80%:\n", " 发送邮件(\"内存报警了。\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "函数的参数分为以下几种:\n", "\n", "- 普通参数\n", "- 默认参数\n", "- 指定参数\n", "- 非关键字可变长参数\n", "- 关键字可变长参数\n", "- 万能参数" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 普通参数传递" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Kevin\n" ] } ], "source": [ "######### 定义函数 ######### \n", "# name 叫做函数send的形式参数,简称:形参\n", "def send(name):\n", " print(name)\n", "\n", "######### 调用函数 #########\n", "# \"Kevin\" 叫做函数send的实际参数,简称:实参\n", "send(\"Kevin\") " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 指定参数传递" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Kevin Lina Gary\n" ] } ], "source": [ "# 指定参数传递\n", "def send(A,B,C):\n", " print(A,B,C)\n", " \n", "# 指定参数必须所有参数都要指定\n", "send(B=\"Lina\", A=\"Kevin\", C=\"Gary\") " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 默认参数" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Gary you're stupid\n" ] } ], "source": [ "# 默认参数,没有传递参数,使用默认参数,传递了则使用传递的参数\n", "def send(A, B, C=\"stupid\"):\n", " print(A, B, C)\n", "\n", "send(\"Gary\", \"you're\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 关键字可变长参数" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'a': 'aaa', 'b': 'bbb', 'c': 'ccc'}\n", "{'a': 'aaa', 'b': 'bbb', 'c': 'ccc'}\n" ] } ], "source": [ "# 关键字可变长参数,也可接收任意个参数,参数传递形式:key-value\n", "def send(**kwargs): # 注意这里,定义函数这里的参数书写格式需要写成这样\n", " print(kwargs)\n", "\n", "f1_dict = {\n", " 'a': 'aaa',\n", " 'b': 'bbb',\n", " 'c': 'ccc'\n", "}\n", "\n", "send(a='aaa', b='bbb', c='ccc')\n", "# 达到如上一样的效果\n", "send(**f1_dict)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 非关键字可变长参数" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('panwenbin', 'lianglian', 'zhaohongfei')\n", "('panwenbin', 'lianglian', 'zhaohongfei')\n" ] } ], "source": [ "# 非关键字可变长参数,可接收任意个参数\n", "def send(*args):\n", " print(args)\n", "\n", "send(\"panwenbin\", \"lianglian\", \"zhaohongfei\")\n", "send(*[\"panwenbin\", \"lianglian\", \"zhaohongfei\"]) # 使用\"*\"可遍历序列,递归传參" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 万能参数" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 11 21\n", "{'k1': 'v1', 'k2': 'v2'}\n" ] } ], "source": [ "# 万能参数,可接收任意个参数,关键字可变长参数和非关键字可变长参数同时使用,接收任意类型任意个数参数\n", "def send(*args, **kwargs):\n", " print(*args)\n", " print(kwargs)\n", "\n", "send(1, 11, 21, **{\"k1\": \"v1\", \"k2\": \"v2\"})" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "python中使用到万能参数的内置函数:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i am lianglian, age 12\n", "i am lianglian, age 12\n", "i am lianglian, age 12\n", "i am liangian, age 12\n" ] } ], "source": [ "# string的format()方法用到万能参数的例子\n", "s1 = \"i am {0}, age {1}\".format(\"lianglian\", 12)\n", "print(s1)\n", "\n", "s2 = \"i am {0}, age {1}\".format(*[\"lianglian\", 12])\n", "print(s2)\n", "\n", "s3 = \"i am {name}, age {age}\".format(name=\"lianglian\", age=12)\n", "print(s3)\n", "\n", "dict={'name': 'liangian', 'age':12}\n", "s4 = \"i am {name}, age {age}\".format(**dict)\n", "print(s4)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 注意事项" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "python 函数多次定义被覆盖:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "64\n" ] } ], "source": [ "# python 函数多次定义被覆盖\n", "def f1(a1, a2):\n", " return a1 + a2\n", "\n", "def f1(a1, a2):\n", " return a1 * a2\n", "\n", "ret = f1(8,8)\n", "print(ret)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "python 参数传递是引用:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[11, 22, 33, 44, 999]\n" ] } ], "source": [ "# python 参数传递是引用\n", "def f1(a1):\n", " a1.append(999)\n", "\n", "li = [11, 22, 33, 44]\n", "f1(li)\n", "\n", "print(li)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "函数内定义的变量只在该函数内有效:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "18 Kevin\n", "19 Kevin\n" ] } ], "source": [ "# 函数内定义的变量只在该函数内有效(注意作用域)\n", "# global 修改全局变量\n", "NAME = 'lianglian'\n", "\n", "def f1():\n", " age = 18\n", " global NAME # 使用global修改过全局生效,作用于全局\n", " NAME = 'Kevin' \n", " print(age, NAME)\n", "\n", "def f2():\n", " age = 19\n", " print(age, NAME)\n", "\n", "f1()\n", "f2()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Python 没有常量这个数据类型,但是在行首定义的常量(变量),遵循不要重新赋值" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "18 [11, 22, 33, 44, 55]\n", "19 [11, 22, 33, 44, 55]\n" ] } ], "source": [ "# 序列(list,tuple...) 行首定义的序列(全局)可以修改 但是不能重新赋值\n", "group = [11,22,33,44]\n", "\n", "def f1():\n", " age = 18\n", " group.append(55)\n", " print(age, group)\n", "\n", "def f2():\n", " age = 19\n", " print(age, group)\n", "\n", "f1()\n", "f2()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "函数实參和形參之间是引用,内部定义的变量和只在内部生效" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4367712648\n", "4367712648\n", "c\n", "4331025664\n", "[1, 2, 3, 'q']\n" ] } ], "source": [ "# 函数实參和形參之间是引用\n", "lists = [1, 2, 3, \"q\"]\n", "print(id(lists)) # 创建变量这个变量得时候的地址空间\n", "\n", "def name(li):\n", " print(id(li)) # 引用实际参数,在这里内存地址空间还是一样\n", "\n", " li = \"c\"\n", " print(li) # 只在这个函数内生效,就像是在这个函数内重新定义了一个\"li\"变量,和外面那个没关系\n", " print(id(li)) # 这里是重新赋值了形参,所以地址空间变了\n", "\n", "name(lists)\n", "print(lists)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "liang\n", "Kevin\n" ] } ], "source": [ "# 函数内重新赋值作用域只限于函数内,函数内变了,外面没变\n", "name = \"Kevin\"\n", "def show():\n", " name='liang'\n", " print(name)\n", "show()\n", "print(name)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## lambda表达式" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "110\n", "110\n" ] } ], "source": [ "# lambda 表达式会自动retrun结果\n", "# lambda表达式 (简单的函数表达式,只能写一行)\n", "def f1(a1):\n", " return a1 + 100\n", "\n", "ret = f1(10)\n", "print(ret)\n", "\n", "f2 = lambda a1: a1 + 100\n", "r2 = f2(10)\n", "print(r2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 装饰器" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "装饰器也是个函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作(装饰:在不改变原函数本身情况下,给他添加额外得功能,就像在一个普通士兵给她装备各种牛逼装备只有他能变得异常强大,而装饰器就是哪些装在它身上的牛逼装备)。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "一、初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需调用基础平台提供的功能即可。如下:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "############### 基础平台提供的功能如下 ###############\n", " \n", "def f1():\n", " print 'f1'\n", "\n", "def f2():\n", " print 'f2'\n", "\n", "def f3():\n", " print 'f3'\n", "\n", "def f4():\n", " print 'f4'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "############### 业务部门A 调用基础平台提供的功能 ###############\n", " \n", "f1()\n", "f2()\n", "f3()\n", "f4()\n", " \n", "############### 业务部门B 调用基础平台提供的功能 ###############\n", " \n", "f1()\n", "f2()\n", "f3()\n", "f4()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即:基础平台的提供的功能可以被任何人使用。现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "老大把工作交给 **worker A**,他是这么做的:\n", "> 跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。诶,这样一来基础平台就不需要做任何修改了。\n", " \n", "当天**worker A** 被开除了..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "老大把工作交给 **worker B**,他是这么做的:\n", "\n", "> 只对基础平台的代码进行重构,让N业务部门无需做任何修改" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "############### 基础平台提供的功能如下 ############### \n", "\n", "def f1():\n", " # 验证1\n", " # 验证2\n", " # 验证3\n", " print 'f1'\n", "\n", "def f2():\n", " # 验证1\n", " # 验证2\n", " # 验证3\n", " print 'f2'\n", "\n", "def f3():\n", " # 验证1\n", " # 验证2\n", " # 验证3\n", " print 'f3'\n", "\n", "def f4():\n", " # 验证1\n", " # 验证2\n", " # 验证3\n", " print 'f4'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "过了一周 **worker B** 被开除了..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "老大把工作交给 **worker C**,他是这么做的:\n", "> 只对基础平台的代码进行重构,其他业务部门无需做任何修改" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "############### 基础平台提供的功能如下 ############### \n", "\n", "def check_login():\n", " # 验证1\n", " # 验证2\n", " # 验证3\n", " pass\n", "\n", "def f1():\n", " check_login()\n", " print 'f1'\n", "\n", "def f2():\n", " check_login()\n", " print 'f2'\n", "\n", "def f3():\n", " check_login()\n", " print 'f3'\n", "\n", "def f4():\n", " check_login()\n", " print 'f4'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "老大看了下Low BBB 的实现,嘴角漏出了一丝的欣慰的笑,语重心长的跟Low BBB聊了个天:\n", "**老大说:**\n", "\n", "写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:\n", "\n", "- 封闭:已实现的功能代码块\n", "- 开放:为已经实现的功能代码库做扩展开发" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "如果将开放封闭原则应用在上述需求中,那么就不允许在函数 f1 、f2、f3、f4的内部进行修改代码,老板就给了Low BBB一个实现方案:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def w1(func):\n", " def inner():\n", " # 验证1\n", " # 验证2\n", " # 验证3\n", " return func()\n", " return inner\n", " \n", "@w1\n", "def f1():\n", " print 'f1'\n", "@w1\n", "def f2():\n", " print 'f2'\n", "@w1\n", "def f3():\n", " print 'f3'\n", "@w1\n", "def f4():\n", " print 'f4'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "对于上述代码,也是仅仅对基础平台的代码进行修改,就可以实现在其他人调用函数 f1 f2 f3 f4 之前都进行【验证】操作,并且其他业务部门无需做任何操作。\n", "\n", "**worker C**心惊胆战的问了下,这段代码的内部执行原理是什么呢?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "单独以 **f1** 为例:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "run inner\n", "F1\n" ] } ], "source": [ "# @ + 函数名\n", "# 功能: 1.自动执行这个函数,并且将下面的函数名f1当做参数传递\n", "# 2.将outer函数的返回值,重新赋值给放f1\n", "def outer(func):\n", " def inner():\n", " print('run inner')\n", " return func()\n", " return inner\n", "\n", "@outer\n", "def f1():\n", " print(\"F1\")\n", "\n", "f1()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "当执行的时候,python是由上到下执行的,首先执行到定义函数:def outer(func) 这里把def outer(func)加载到内存\n", "\n", "当执行到 **@outer** 的时候@outer是python的魔法!它会把它下面的函数进行封装。\n", "\n", "把f1这个函数作为def outer(func)的参数传进去!就是:f1()=outer(f1)\n", "\n", "然后def outer(func): == outer(f1)就会执行:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def outer(func):\n", " def inner():\n", " print('run inner')\n", " return func() # func() == 原函数f1\n", " return inner # 然后把封装后的函数return的结果给原函数 (= f1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "@outer就相当于做了一个重新打了个包,包含原数据和新增数据,然后变成新的包给\"f1\"\n", "\n", "def f1() <==> def inner()" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "@outer # outer(f1)\n", "def f1(): # def inner():\n", " print(\"F1\") # print('run inner')\n", " # return f1()\n", " # return inner()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "用装饰器写一个计时器来统计函数的执行时间:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "111\n", "time_used: 10.00s\n" ] } ], "source": [ "import time\n", "\n", "def timer(func):\n", " def inner():\n", " start_time = time.time()\n", " result = func()\n", " end_time = time.time()\n", " time_used = end_time - start_time\n", " print(\"time_used: %.2fs\" % time_used)\n", " return result\n", " return inner\n", "\n", "@timer\n", "def f1():\n", " time.sleep(10)\n", " print(111)\n", "\n", "f1()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "被装饰的函数如果有参数呢?" ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "before\n", "test\n", "after\n", "F1\n" ] } ], "source": [ "# 装饰函数使用参数\n", "def outer(func):\n", " def inner(name): # func对应f1,f1有参数,这里也要接收参数好传递给内部funce\n", " print(\"before\")\n", " r = func(name)\n", " print(\"after\")\n", " return r # 不要丢弃原函数返回值\n", " return inner\n", "\n", "\n", "@outer\n", "def f1(arge):\n", " print(arge)\n", " return \"F1\"\n", "\n", "ret = f1('test')\n", "print(ret)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "装饰器装饰动态参数函数:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "before\n", "test1\n", "after\n" ] }, { "data": { "text/plain": [ "'F1'" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "before\n", "test1 test2\n", "after\n" ] }, { "data": { "text/plain": [ "'F2'" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 装饰器装饰动态参数函数\n", "def outer(func):\n", " def inner(*arge, **kwargs): # 装饰器使用动态参数,来应对装饰不同得函数参数不确定情况\n", " print(\"before\")\n", " r = func(*arge, **kwargs) # 将原原函数的参数传递进来\n", " print(\"after\")\n", " return r # 不要丢弃原函数返回值\n", " return inner\n", "\n", "\n", "@outer\n", "def f1(a1): # 一个参数\n", " print(a1) \n", " return \"F1\"\n", "\n", "@outer\n", "def f2(a1, b1): # 两个参数\n", " print(a1, b1) \n", " return \"F2\"\n", "\n", "f1('test1')\n", "f2('test1', 'test2')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "多装饰器的使用:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "USER_INFO = {'is_login': None, 'user_type': 1}\n", "# USER_INFO['is_login']\n", "# USER_INFO.get('is_login', None)\n", "\n", "\n", "def check_login(func):\n", " def inner(*args, **kwargs):\n", " if USER_INFO.get('is_login', None):\n", " ret = func(*args, **kwargs)\n", " return ret\n", " else:\n", " print(\"请登录!\")\n", " return inner\n", "\n", "\n", "def check_admin(func):\n", " def inner(*args, **kwargs):\n", " if USER_INFO.get('user_type', None) == 2:\n", " ret = func(*args, **kwargs)\n", " return ret\n", " else:\n", " print('无权查看')\n", " return inner\n", "\n", "\n", "@check_login\n", "@check_admin\n", "def index():\n", " \"\"\"\n", " 管理员的功能\n", " :return:\n", " \"\"\"\n", " print('Index')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "------------------------华丽的分割线-----------------------------\n", "\n", "\n", "# 装饰器装饰也是有顺序的,代码是从上到下加载到内存中,\n", "# 我们知道装饰器会把被 [@装饰器] 下面的函数装饰,并将它当作参数传递到装饰器里面.\n", "# 装饰顺序结构(0),(1),(2); (0)代表被装饰函数本体\n", "@check_login\n", "@check_admin\n", "def index():\n", " \"\"\"\n", " 管理员的功能\n", " :return:\n", " \"\"\"\n", " print('Index')\n", "\n", "\n", "\n", "if USER_INFO.get('is_login', None): # (2) check_login函数体\n", " if USER_INFO.get('user_type', None) == 2: # (1) check_admin函数体\n", " ret = print('Index') # (0) index函数本体\n", " return ret # (0) index函数返回值\n", " else:\n", " print('无权查看') # (1) check_admin函数体\n", "else:\n", " print(\"请登录!\") # (2) check_login函数体" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "因此由上可看出,多个装饰器装饰一个函数,其实就是将这个函数层层嵌套到装饰器得函数体里面.\n", "\n", "多装饰器的顺序:\n", "\n", "  代码由上到下执行,加载到内存中,所有当一个函数上面有多个装饰器的时候,从上往下的顺序依次装饰函数,被装饰的函数则从被装饰的函数由下往上层层嵌套到装饰器中。\n", "\n", "  1、最上面的装饰器是最外一层嵌套\n", "\n", "  2、嵌套需要注意的是,最外层包裹内层,执行时是从上往下,考虑嵌套后代码执行顺序。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 迭代器和生成器\n", "\n", "**迭代器** 是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "特点:\n", "\n", "- 访问者不需要关心迭代器内部的结构,仅需通过 **next()** 方法不断去取下一个内容\n", "- 不能随机访问集合中的某个值 ,只能从头到尾依次访问\n", "- 访问到一半时不能往回退\n", "- 便于循环比较大的数据集合,节省内存" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "1" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "2" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "3" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "4" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "5" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "ename": "StopIteration", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__next__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__next__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m: " ] } ], "source": [ "a = iter([1,2,3,4,5])\n", "a\n", "a.__next__()\n", "a.__next__()\n", "a.__next__()\n", "a.__next__()\n", "a.__next__()\n", "\n", "a.__next__() # 没有了,再迭代会报错" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 生成器\n", "一个函数调用时返回一个迭代器,那这个函数就叫做 **生成器(generator)**;如果函数中包含 **yield** 语法,那这个函数就会变成生成器;" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def func():\n", " yield 1\n", " yield 2\n", " yield 3\n", " yield 4" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "2" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "3" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "4" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "temp = func()\n", "temp.__next__()\n", "temp.__next__()\n", "temp.__next__()\n", "temp.__next__()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Example: **" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "1" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "2" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "3" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def myrange(arg):\n", " start = 0\n", " while True:\n", " if start > arg:\n", " return\n", " yield start\n", " start += 1\n", "\n", "ret = myrange(3)\n", "ret.__next__()\n", "ret.__next__()\n", "ret.__next__()\n", "ret.__next__()" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n" ] } ], "source": [ "# for 是一个自动迭代器,内部也是调的对象的 “__next__()” 方法\n", "ret = myrange(3)\n", "for item in ret:\n", " print(item)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 递归\n", "\n", "在函数体内重复调用自己本身,做到反复运行一个算法达到最终目的然后返回。" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n", "end\n" ] } ], "source": [ "def func(n):\n", " n += 1\n", " if n >= 4:\n", " print(n)\n", " return \"end\"\n", " return func(n)\n", "\n", "r = func(1) # 我传递进去个1,经过递归最后给我返回4\n", "print(r)" ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5040\n" ] } ], "source": [ "# 1*2*3*4*5*6*7\n", "def func(num):\n", " if num == 1:\n", " return 1\n", " return num * func(num-1) # 7 * 7-1 返回递归\n", "\n", "x = func(7)\n", "print(x)" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" }, "toc": { "colors": { "hover_highlight": "#DAA520", "navigate_num": "#000000", "navigate_text": "#333333", "running_highlight": "#FF0000", "selected_highlight": "#FFD700", "sidebar_border": "#EEEEEE", "wrapper_background": "#FFFFFF" }, "moveMenuLeft": true, "nav_menu": { "height": "282px", "width": "252px" }, "navigate_menu": true, "number_sections": false, "sideBar": true, "threshold": 4, "toc_cell": true, "toc_position": { "height": "648px", "left": "0px", "right": "1228px", "top": "111px", "width": "212px" }, "toc_section_display": "block", "toc_window_display": false, "widenNotebook": false } }, "nbformat": 4, "nbformat_minor": 2 }