1 高阶函数

满足下列条件之一就可成函数为高阶函数

某一函数当做参数传入另一个函数中

函数的返回值包含n个函数,n>0

高阶函数示范

  1. def bar():
  2. print 'in the bar'
  3. def foo(func):
  4. res=func()
  5. return res
  6. foo(bar)

foo(bar)()等价于 先bar=foo(bar) 再 bar()

2 内嵌函数和变量作用域

定义:在一个函数体内创建另外一个函数,这种函数就叫内嵌函数(基于python支持静态嵌套域)

嵌套函数示例

  1. def foo(): #定义函数foo(),
  2. m=3 #定义变量m=3;
  3. def bar(): #在foo内定义函数bar()
  4. n=4 #定义局部变量n=4
  5. print m+n #m相当于函数bar()的全局变量
  6. bar() #foo()函数内调用函数bar()

当运行bar函数的时候,会首先找局部变量发现没有m,就会去父函数里找,发现有m,就会引用。这就是嵌套函数,而引用外部变量的嵌套函数就被称为闭包。

3 闭包

定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是 closure(闭包)

  1. def counter(start_num=0):
  2. count = [start_num]
  3. def incr():
  4. count[0] += 1
  5. return count[0]
  6. return incr
  7. print(counter()) #1
  8. print(counter()()) #2
  9. print(counter()()) #3
  10. c = counter() #4
  11. print(c()) #5
  12. print(c()) #6
  13. #####运行结果#####
  14. #1运行结果 <function counter.<locals>.incr at 0x0053D390> //返回incr这个函数变量在内存中的地址
  15. #2运行结果 1 //先运行counter函数得到incr这个函数变量,再运行incr()得到结果1
  16. #3运行结果 1//因为先运行了counter函数所以会初始化start_num为0,所以结果还是1
  17. #5运行结果 1//把incr这个函数变量赋给c这个对象然后运行会得到incr()结果
  18. #6运行结果 2//此时count[0]=1,所以直接执行这个会继续使count[0]加1,所以运行结果为2。

4 装饰器初识

定义:装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。并且不会改变函数的调用方式。

使用装饰器方法:@具有装饰功能的函数。例如下面的@foo。


有些人说装饰器就是高阶函数+带有闭包特性的嵌套函数,但是我认为没有嵌套函数也可以写出装饰器。

无参数和无嵌套函数装饰器

  1. def foo(func):
  2. print 'decorator foo'
  3. return func
  4. @foo
  5. def bar():
  6. print 'bar'
  7. bar()
  8. #没有嵌套函数,增加了打印"decorator foo"功能,并且没有改变函数的调用方式。这个相当于 ①先执行 bar=foo(bar)②再执行bar()因为bar()是函数调用所以foo(bar)必须有函数返回值,且是一个可调用的对象

无参装饰器

无参装饰器是指装饰器没有参数

  1. import time
  2. def decorator(func):
  3. def wrapper(*args,**kwargs):
  4. start=time.time()
  5. func(*args,**kwargs)
  6. stop=time.time()
  7. print 'run time is %s ' %(stop-start)
  8. print timeout
  9. return wrapper
  10. @decorator //装饰器
  11. def test(list_test):
  12. for i in list_test:
  13. time.sleep(0.1)
  14. print '-'*20,i
  15. #decorator(test)(range(10))
  16. test(range(10)
  17. #可以看出装饰器decorator并没有参数,装饰器实际上是在函数里内嵌被装饰的函数,但是如果没有内嵌被装饰的函数,那么被装饰的函数就毫无意义。

有参数的装饰器

  1. import time
  2. def timer(timeout=0):
  3. def decorator(func):
  4. def wrapper(*args,**kwargs): #会给被装饰的函数传递参数,因为无法确定装饰器有多少参数,所以使用这个。
  5. start=time.time()
  6. func(*args,**kwargs)
  7. stop=time.time()
  8. print 'run time is %s ' %(stop-start)
  9. print timeout
  10. return wrapper
  11. return decorator
  12. @timer(2) #装饰器的参数为2
  13. def test(list_test):
  14. for i in list_test:
  15. time.sleep(0.1)
  16. print '-'*20,i
  17. #timer(timeout=10)(test)(range(10))
  18. test(range(10))
  19. #装饰器timer的参数为2,@timer(2)相当于test=timer(2)(test)

5 生成器

定义:如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

  1. >>> L = [x * x for x in range(10)]
  2. >>> L
  3. [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  4. >>> g = (x * x for x in range(10))
  5. >>> g
  6. <generator object <genexpr> at 0x1022ef630>

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

  1. >>> next(g)
  2. 0
  3. >>> next(g)
  4. 1
  5. >>> next(g)
  6. 4
  7. >>> next(g)
  8. 9
  9. >>> next(g)
  10. 16
  11. >>> next(g)
  12. 25
  13. >>> next(g)
  14. 36
  15. >>> next(g)
  16. 49
  17. >>> next(g)
  18. 64
  19. >>> next(g)
  20. 81
  21. >>> next(g)
  22. Traceback (most recent call last):
  23. File "<stdin>", line 1, in <module>
  24. StopIteration

正确的方法是使用for循环,因为generator也是可迭代对象:

  1. >>> g = (x * x for x in range(10))
  2. >>> for n in g:
  3. ... print(n)
  4. ...

函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了

  1. def fib(max): #第一步
  2. n,a,b = 0,0,1
  3. while n < max:
  4. #print(b)
  5. yield b
  6. a,b = b,a+b
  7. n += 1
  8. return 'done'
  9. #执行
  10. data = fib(10) #第二步
  11. print(data) #第三步
  12. print(data.__next__())#第四步
  13. print(data.__next__())
  14. print("干点别的事")
  15. print(data.__next__())
  16. print(data.__next__())
  17. print(data.__next__())
  18. print(data.__next__())
  19. print(data.__next__())
  20. #1第一步会定义一个函数
  21. #2第二步会定义一个data对象,但是此时并没有赋值给data
  22. #4第四步__next__()激活生成器,并开始运行生成器函数,遇到yield结束

next()和send()的区别

其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。

需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。

貌似很吊的生成器

  1. #_*_coding:utf-8_*_
  2. __author__ = 'Alex Li'
  3. import time
  4. def consumer(name):
  5. print("%s 准备吃包子啦!" %name)
  6. while True:
  7. baozi = yield
  8. print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
  9. def producer(name):
  10. c = consumer('A')
  11. c2 = consumer('B')
  12. c.__next__() //这里其实就是启动一下,装饰器等价于c.send(None)下面这行也是类似
  13. c2.__next__()
  14. print("老子开始准备做包子啦!")
  15. for i in range(10):
  16. time.sleep(1)
  17. print("做了2个包子!")
  18. c.send(i)
  19. c2.send(i)
  20. producer("alex")
  21. 通过生成器实现协程并行运算

next和send源代码

  1. nextsend函数,如下:
  2. static PyObject *
  3. gen_iternext(PyGenObject *gen)
  4. {
  5. return gen_send_ex(gen, NULL, 0);
  6. }
  7. static PyObject *
  8. gen_send(PyGenObject *gen, PyObject *arg)
  9. {
  10. return gen_send_ex(gen, arg, 0);
  11. }
  12. 函数gen_send_ex如下:
  13. static PyObject *
  14. gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
  15. {
  16. PyThreadState *tstate = PyThreadState_GET();
  17. PyFrameObject *f = gen->gi_frame;
  18. PyObject *result;
  19. if (gen->gi_running) { // 判断生成器是否已经运行
  20. PyErr_SetString(PyExc_ValueError,
  21. "generator already executing");
  22. return NULL;
  23. }
  24. if (f==NULL || f->f_stacktop == NULL) { // 如果代码块为空或调用栈为空,
  25. //则抛出StopIteration异常
  26. /* Only set exception if called from send() */
  27. if (arg && !exc)
  28. PyErr_SetNone(PyExc_StopIteration);
  29. return NULL;
  30. }
  31. if (f->f_lasti == -1) { // f_lasti=1 代表首次执行
  32. if (arg && arg != Py_None) { // 首次执行不允许带有参数
  33. PyErr_SetString(PyExc_TypeError,
  34. "can't send non-None value to a "
  35. "just-started generator");
  36. return NULL;
  37. }
  38. } else {
  39. /* Push arg onto the frame's value stack */
  40. result = arg ? arg : Py_None;
  41. Py_INCREF(result); // 该参数引用计数+1
  42. *(f->f_stacktop++) = result; // 参数压栈
  43. }
  44. /* Generators always return to their most recent caller, not
  45. * necessarily their creator. */
  46. f->f_tstate = tstate;
  47. Py_XINCREF(tstate->frame);
  48. assert(f->f_back == NULL);
  49. f->f_back = tstate->frame;
  50. gen->gi_running = 1; // 修改生成器执行状态
  51. result = PyEval_EvalFrameEx(f, exc); // 执行字节码
  52. gen->gi_running = 0; // 恢复为未执行状态
  53. /* Don't keep the reference to f_back any longer than necessary. It
  54. * may keep a chain of frames alive or it could create a reference
  55. * cycle. */
  56. assert(f->f_back == tstate->frame);
  57. Py_CLEAR(f->f_back);
  58. /* Clear the borrowed reference to the thread state */
  59. f->f_tstate = NULL;
  60. /* If the generator just returned (as opposed to yielding), signal
  61. * that the generator is exhausted. */
  62. if (result == Py_None && f->f_stacktop == NULL) {
  63. Py_DECREF(result);
  64. result = NULL;
  65. /* Set exception if not called by gen_iternext() */
  66. if (arg)
  67. PyErr_SetNone(PyExc_StopIteration);
  68. }
  69. if (!result || f->f_stacktop == NULL) {
  70. /* generator can't be rerun, so release the frame */
  71. Py_DECREF(f);
  72. gen->gi_frame = NULL;
  73. }
  74. return result;
  75. }

6 迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

可以使用isinstance()判断一个对象是否是Iterable对象:

  1. >>> from collections import Iterable
  2. >>> isinstance([], Iterable)
  3. True
  4. >>> isinstance({}, Iterable)
  5. True
  6. >>> isinstance('abc', Iterable)
  7. True
  8. >>> isinstance((x for x in range(10)), Iterable)
  9. True
  10. >>> isinstance(100, Iterable)
  11. False

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator可以使用iter()函数:

  1. >>> isinstance(iter([]), Iterator)
  2. True
  3. >>> isinstance(iter('abc'), Iterator)
  4. True

你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

7 json & pickle 模块

用于序列化的两个模块

  • json,用于字符串 和 python数据类型间进行转换
  • pickle,用于python特有的类型 和 python的数据类型间进行转换

Json模块提供了四个功能:dumps、dump、loads、load

pickle模块提供了四个功能:dumps、dump、loads、load

Json模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load

pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load (不仅可以序列化字典,列表...还可以把一个程序,一个类给序列化掉)

  1. import json
  2. #loads #--> 内部必须是双引号
  3. #dumps --loads (对现有的一个操作)
  4. s = '{"desc":"invilad-citykey", "status":1002}'
  5. l = [11,22,33,44]
  6. result = json.loads(s)
  7. print(result,type(result))
  8. result = json.dumps(l)
  9. print(result,type(result))
  10. 结果:
  11. {'status': 1002, 'desc': 'invilad-citykey'} <class 'dict'>
  12. [11, 22, 33, 44] <class 'str'>

dump -- load(对文件的一个操作)

  1. s = {"desc":"invilad-citykey", "status":1002}
  2. l = [11,22,33,44]
  3. a = json.dump(s,open("db","w", encoding="utf-8"))
  4. b = json.load(open("db","r", encoding="utf-8"))
  5. print(b, type(b))
  6. import json
  7. s = '{"key1":"value1","key2":"value2"}' # ==> 用json模块将字符串转化成其他数据类型,字符串里出现引号必须用双引号
  8. ret = json.loads(s) # ==> loads 由字符串转其他数据类型
  9. print(ret,type(ret))
  10. ret = json.load(open('ethan.txt','r')) # ==> 将文档(内部是字符串格式)转换成python的其他数据类型
  11. print(ret,type(ret)) # ==> 文档里是字典样式的字符串
  12. l = '[11,22,3,56,75]'
  13. result =json.loads(l)
  14. print(result,type(result))
  15. # 总结:
  16. # json.loads()用于将形似字典、列表、元组的字符串,转换成字典、列表、元组
  17. # json.load() 用于将文档(内容是形似字典、列表、元组的字符串)转换成字典、列表、元组
  18. di = {"key1":"value1","key2":"value2"}
  19. ret = json.dumps(di) # ==> 将字典、列表、元组 转换成字符串格式
  20. print(ret,type(ret))
  21. json.dump(di,open('ethan.txt','a+')) # ==> 将字典、元组、列表转换成字符串格式并写入文档
  22. import pickle
  23. d = {'name':'ethan','age':28}
  24. ret = pickle.dumps(d) # ==> pickle将字典、元组、列表转换成二进制
  25. print(ret,type(ret))
  26. l = [11,22,3,45,54]
  27. res = pickle.dumps(l)
  28. print(res)
  29. pickle.dump(d,open('ethan.txt','ab')) # ==> 将字典、元组、列表转换成二进制写入文档
  30. # 注意 dump load 不要一起运行,会报错,一步一步来
  31. f = open('ethan.txt','rb')
  32. r = pickle.loads(f.read()) # ==> 将二进制转换成字典、列表、元组
  33. print(r)

python自动化之装饰器的更多相关文章

  1. Python自动化开发 - 装饰器

    本节内容 一.装饰器导引 1.函数对象特性 2.扩展业务功能需求 3.各种解决方案 二.装饰器解析 1.装饰器基本概念 2.无参装饰器解析 一.装饰器导引 1.函数对象特性 #### 第一波 #### ...

  2. Day04 - Python 迭代器、装饰器、软件开发规范

    1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...

  3. python中的装饰器decorator

    python中的装饰器 装饰器是为了解决以下描述的问题而产生的方法 我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码 例如有三个函数: def f1(x): retur ...

  4. python高级之装饰器

    python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...

  5. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

  6. python笔记 - day4-之装饰器

                 python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...

  7. Python深入05 装饰器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法 ...

  8. Noah的学习笔记之Python篇:装饰器

    Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) ...

  9. 第二篇:python高级之装饰器

    python高级之装饰器   python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...

随机推荐

  1. 关于Spring常用的注解

    参考文献:http://www.cnblogs.com/xdp-gacl/p/3495887.html 使用注解来构造IoC容器 用注解来向Spring容器注册Bean.需要在applicationC ...

  2. (转)Java中的String为什么是不可变的

    转自:http://www.importnew.com/7440.html String是所有语言中最常用的一个类.我们知道在Java中,String是不可变的.final的.Java在运行时也保存了 ...

  3. CSS中常见的位置(position)属性

    常用的位置属性列表: position(top.bottom.left.right) .overflow.z-index position用法: 值 描述 relative 相对定位,原位置仍占用空间 ...

  4. java中的各个数据结构区别

    ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢 ...

  5. Jquery中的$().each() 方法

    先举例子, 输出每个 li 元素的文本: <html> <head> <script type="text/javascript" src=" ...

  6. 两种html幻灯片效果

    650) this.width=650;" src="http://img1.51cto.com/attachment/201307/165757318.jpg" tit ...

  7. MYSql存储过程的作用及语法

    1.使用了存过程,很多相似性的删除,更新,新增等操作就变得轻松了,并且以后也便于管理! 2.存储过程因为SQL语句已经预编绎过了,因此运行的速度比较快. 3.存储过程可以接受参数.输出参数.返回单个或 ...

  8. 【转】Kafka producer原理 (Scala版同步producer)

    转载自:http://www.cnblogs.com/huxi2b/p/4583249.html     供参考 本文分析的Kafka代码为kafka-0.8.2.1.另外,由于Kafka目前提供了两 ...

  9. ajava包的命名

    2. Package的命名 Package名的第一部分应是小写ASCII字符,并且是顶级域名之一,通常是com.edu.gov.mil.net.org或由ISO标准3166.1981定义的国家唯一标志 ...

  10. 解决pydev报unsolved import的问题

    安装Flask_RESTful-0.2.11包后, 并在pydev 对应的 interpreter 重新刷新了System PYTHONPATH, 看见Lib\site-packages\flask_ ...