zoukankan      html  css  js  c++  java
  • day04_20170521_函数(二)

    课前补充个新的概念:为什么要定义函数?

      为了使用。函数即变量。变量怎么定义的x=1调用函数分为两部分:先找到当前你要调用的函数有没有那个名字。有了这个函数名字,加括号,才是执行这个函数里面的代码。定义函数就相当于在定义了一个变量,函数名就是变量名,函数值就是函数体里面的代码。如果没有事先定义函数,而直接引用,就相当于在引用一个不存在的变量。所以函数的使用一定要遵循先定义后使用的原则。

    第一节:函数对象

      函数对象指的是函数可以当做数据去传递!(什么叫数据呢?x=1相当于定义了一个数据,那x与什么特性,函数就应该有什么特性!特性如下:)

        1.可以被引用

        2.可以当参数传递

        3.返回值可以是函数

        4.可以当做容器类型的元素

    那分别解析这几种特性:

    可以被引用-------->怎么叫引用函数呢?

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    def foo():
        print('from foo')
    func = foo #func和foo指向相同的内存地址
    print(foo)
    print(func)
    func()#有了内存地址,加括号就可以直接调用
    输出结果:
    <function foo at 0x001C6738>
    <function foo at 0x001C6738>
    from foo
    

    可以当参数传递-------->下面的数字为函数执行顺序

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    def foo():
    print('from foo')#4、打印
    def bar(func):
        print(func)#2、打印func就相当于打印的是foo的内存地址
        func()#3、func已经获得foo的内存地址,那么加括号就可以直接运行
    bar(foo)#1、func需要一个参数,这个参数可以把foo这个名字传进去,这就相当于传了一个内存地址给他
    输出结果:
    <function foo at 0x001D6738>
    from foo
    

    返回值可以是函数-------->return

     1 #!/usr/bin/python
     2 # -*- coding:utf-8 -*-
     3 def foo():
     4     print('from foo')
     5 def bar(func):
     6     return func
     7 f = bar(foo)#bar相当于传了一个内存地址,赋值给f之后,f加括号直接调用
     8 print(f)
     9 f()
    10 输出结果:
    11 <function foo at 0x002F6738>
    12 from foo

    可以当做容器类型的元素-------->

    x = 1
    dic = {'x':x}#把x当做数据进行传递,就相当于{'x':1}.函数就是变量,函数有第一类对象的感念,可以当数据进行传递,意味着他可以当容器类型的一个元素
    

    #那么就可以这样写:

    1 def foo():
    2     print('from foo')
    3 dic = {'func':foo}#func的值为foo这个函数的内存地址。如果这句我写成dic = {'func':foo()} 表示此处的值就是调用foo这个函数的结果了
    4 print(dic['func'])#进行调用,得到foo的内存地址
    5 dic['func']()#记上括号就可以直接运行
    6 输出结果:
    7 <function foo at 0x00566738>
    8 from foo

    #这样写有什么好处呢?看下面的应用:

     1 def select(sql):
     2     print('======>select')
     3 def insert(sql):
     4     print('====>insert')
     5 def delete(sql):
     6     print('=====>delete')
     7 def update(sql):
     8     print('========>update')
     9 
    10 #定义好函数之后,要根据用户的输入进行不同函数的调用
    11 #我可以根据函数对象来这样写:
    12 func_dic = {
    13     'select':select,
    14     'update':update,
    15     'insert':insert,
    16     'delete':delete,
    17 
    18 }
    19 def main():
    20     #涉及到用户交互的要加上while循环
    21     while True:
    22         sql = input('>>:')#用户输入sql
    23         if not sql:continue#如果不加这句,执行代码之后直接回车,会报 list index out of range
    24         l = sql.split()#对sql语句进行切分
    25         print(l)
    26         #这种写法很冗余,所以我们用 func_dic 这个字典来完成
    27         # if l[0] == 'select':#判断看select是否在l中,如果在,就调用select函数
    28         #     select(l)
    29         # elif l[0] == 'insert':
    30         #     insert(l)
    31         # elif l[0] == 'delte':
    32         #     delete(l)
    33         # elif l[0] == 'update':
    34         #     update(l)
    35 
    36         cmd = l[0]
    37         if cmd in func_dic:
    38             func_dic[cmd](1)
    39 main()
    40 输出结果:
    41 >>:select * from mysql.db
    42 ['select', '*', 'from', 'mysql.db']
    43 ======>select
    44 >>:delete * from user
    45 ['delete', '*', 'from', 'user']
    46 =====>delete
    47 >>: 

    第二节:函数嵌套

      函数的嵌套分为两种:1)函数的嵌套调用 2)函数的嵌套定义

    分别来解析一下:

    函数的嵌套调用------->在一个函数内部再去调用其他的函数

      上节课我们讲了求两个数的最大值,那求四个数的最大值呢?:

     1 #!/usr/bin/python
     2 # -*- coding:utf-8 -*-
     3 def max2(x,y):
     4     return x if x > y else y
     5 
     6 #那如果求四个值中最大的值呢?思路:我先两个比较,比较的大的结果和第三个比较,然后在和最后一个比较
     7 def max4(a,b,c,d):
     8     res1 = max2(a,b)
     9     res2 = max2(res1,c)
    10     res3 = max2(res2,d)
    11     return res3
    12 print(max4(10,99,31,22))

    函数的嵌套定义------->注意:一层一层执行,最后调用的时候也要看好层次,巧用折叠的方式

     1 def f1():
     2     def f2():
     3         print('from f2')
     4         def f3():
     5             print('from f3')
     6         f3()
     7     f2()
     8 f1()#如果不调用f2(),那么调用f1()不输出任何结果。如果加上f2(),就会输出from f2 .加上f3()就会输出from f3
     9 输出结果:
    10 from f2
    11 from f3

    第三节:函数名称空间与作用域

    一、名称空间

    Python当中名字和值之间是一种绑定的关系。

    Python中分三种名称空间:

    1)内置名称空间    2)全局名称空间   3)局部名称空间

    分别解析一下:

    内置名称空间------->存放内置的名字,内置到Python解释器里面的名字

    典型的如下:

    print(sum)#输出结果:<built-in function sum> 含built-in的称为内置名字

    名称空间什么时候会产生呢?Python解释器只要一启动,这个名称空间就会产生,里面的名字就会定义好

    内置函数的特点:无需定义,直接调用

    怎么查看内置函数的名字呢:

      1 #!/usr/bin/python
      2 # -*- coding:utf-8 -*-
      3 import builtins
      4 for i in dir(builtins):
      5     print(i)
      6 输出结果:
      7 ArithmeticError
      8 AssertionError
      9 AttributeError
     10 BaseException
     11 BlockingIOError
     12 BrokenPipeError
     13 BufferError
     14 BytesWarning
     15 ChildProcessError
     16 ConnectionAbortedError
     17 ConnectionError
     18 ConnectionRefusedError
     19 ConnectionResetError
     20 DeprecationWarning
     21 EOFError
     22 Ellipsis
     23 EnvironmentError
     24 Exception
     25 False
     26 FileExistsError
     27 FileNotFoundError
     28 FloatingPointError
     29 FutureWarning
     30 GeneratorExit
     31 IOError
     32 ImportError
     33 ImportWarning
     34 IndentationError
     35 IndexError
     36 InterruptedError
     37 IsADirectoryError
     38 KeyError
     39 KeyboardInterrupt
     40 LookupError
     41 MemoryError
     42 NameError
     43 None
     44 NotADirectoryError
     45 NotImplemented
     46 NotImplementedError
     47 OSError
     48 OverflowError
     49 PendingDeprecationWarning
     50 PermissionError
     51 ProcessLookupError
     52 RecursionError
     53 ReferenceError
     54 ResourceWarning
     55 RuntimeError
     56 RuntimeWarning
     57 StopAsyncIteration
     58 StopIteration
     59 SyntaxError
     60 SyntaxWarning
     61 SystemError
     62 SystemExit
     63 TabError
     64 TimeoutError
     65 True
     66 TypeError
     67 UnboundLocalError
     68 UnicodeDecodeError
     69 UnicodeEncodeError
     70 UnicodeError
     71 UnicodeTranslateError
     72 UnicodeWarning
     73 UserWarning
     74 ValueError
     75 Warning
     76 WindowsError
     77 ZeroDivisionError
     78 __build_class__
     79 __debug__
     80 __doc__
     81 __import__
     82 __loader__
     83 __name__
     84 __package__
     85 __spec__
     86 abs
     87 all
     88 any
     89 ascii
     90 bin
     91 bool
     92 bytearray
     93 bytes
     94 callable
     95 chr
     96 classmethod
     97 compile
     98 complex
     99 copyright
    100 credits
    101 delattr
    102 dict
    103 dir
    104 divmod
    105 enumerate
    106 eval
    107 exec
    108 exit
    109 filter
    110 float
    111 format
    112 frozenset
    113 getattr
    114 globals
    115 hasattr
    116 hash
    117 help
    118 hex
    119 id
    120 input
    121 int
    122 isinstance
    123 issubclass
    124 iter
    125 len
    126 license
    127 list
    128 locals
    129 map
    130 max
    131 memoryview
    132 min
    133 next
    134 object
    135 oct
    136 open
    137 ord
    138 pow
    139 print
    140 property
    141 quit
    142 range
    143 repr
    144 reversed
    145 round
    146 set
    147 setattr
    148 slice
    149 sorted
    150 staticmethod
    151 str
    152 sum
    153 super
    154 tuple
    155 type
    156 vars
    157 zip
    View Code

    全局名称空间------->什么时候会产生的呢?文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间。

     1 #!/usr/bin/python
     2 # -*- coding:utf-8 -*-
     3 x = 1
     4 def func():
     5     money = 2000
     6     x = 2 #这个x的定义不会影响上面的x=1
     7     print('func')
     8 print(x)
     9 print(func)
    10 func()
    11 print(money)#现在找不到money,因为他是在函数级别定义的 

    局部名称空间------->在函数内部定义的!局部名称空间什么时候会产生呢?调用函数时会产生局部名称空间。局部名称空间里面存的就是局部的名字。

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 x = 10000
    4 def func():
    5     x =1
    6     def f1():#f1只能在func这个函数级别里面使用,这种名字和值的绑定关系,什么时候有效,什么时候失效呢?只在函数调用时临时绑定,调用结束解除绑定。
    7         pass
    8     f1()

    以上三个名称空间是彼此互相隔离的!

    二、作用域

    域指的是一个范围,指的是在哪个范围内找名字!分为 1) 全局作用域    2)局部作用域 

    解析如下:

    全局作用域------>包含哪几个空间呢?内置名称空间,全局名称空间

    局部作用域------>局部名称空间

    作用域里面有个找名字的过程,是在哪个范围里面找名字。名字的查找顺序:局部名称空间---》全局名称空间---》内置名称空间

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 x = 1
    4 def func():
    5     x = 2#如果把这句注释掉,就说明局部名称空间里面没有,就到全局名称空间里面找,x 为1 
    6     print(x)#先在局部范围里面找,如果没有在到全局范围里面找
    7 func()
    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 def func():
    4     sum = 123123#如果注释此句,那么局部空间不存在名字,就去全局空间找,也不存在,所以最终去内置名称空间找,输出内存地址<built-in function sum>
    5     print(sum)#sum首先在局部空间进行查找,结果为123123
    6 func()
    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 def func():
    4     x = 2
    5 func()
    6 print(x)#已经处于全局范围了,只能从全局名称空间及以上开始找。不能找内置名称空间了

    查看全局作用域和局部作用域里面名字的方法:

    查看全局作用域内的名字:gloabls()

    查看局部作用域内的名字:locals()

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 x = 1000
    4 def func():
    5     x = 2
    6 print(globals())
    7 print(locals())#在全局里面查看局部,那得到的还是全局
    8 print(globals() is locals())
    在全局看不到局部,他的局部就是自己,局部就是函数内部定义的名字,全局是文件级别的。
    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 x = 1000
    4 def func(y):
    5     x = 2
    6     print(locals())#{'x': 2, 'y': 1}
    7     print(globals())#可以输出
    8 func(1)

    全局作用域是全局有效,在当前文件的任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕!

    局部作用域的名字:局部有效。只能在局部范围调用,只在函数调用时才有效,函数调用结束才失效。

    在全局看不到局部,他的局部就是自己,局部就是函数内部定义的名字,全局是文件级别的。

     第四节 闭包函数

    闭包:内部函数包含对外部作用域而非全局作用域的引用,该内部函数就称为闭包函数

    如下就是一个闭包函数的定义:

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 def f1():
    4     x = 1
    5     def f2():
    6         print(x)

    如果代码写成如下,就不是闭包函数了,因为x引用的是全局作用域的名称了

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 x = 1
    4 def f1():
    5     def f2():
    6         print(x)

    闭包函数需要满足的条件:1)必须是内部定义的函数  2)要引用自己外部作用域,而不是对全局作用域中名字的引用

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 
    4 def f1():
    5     x = 1#2、先定义了一个名字
    6     def f2():#3、又定义了一个名字
    7         print(x)#5、里面有个 打印的操作,这个x在f2这个函数里面没有,就要去上一层级别,他要拿到的就是x=1
    8     return f2()#4、拿到一个结果f2,此时这个f2就是f1()
    9 f1()#1、执行f1

    闭包函数可以做什么用呢?闭包应用:惰性计算:

    如果想爬虫一个网页,怎么操作呢?

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 from urllib.request import  urlopen
    4 res = urlopen('http://crm.oldboyedu.com').read()
    5 print(res.decode('utf-8'))
    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 def index(url):
    4     def get():#这个get可以获取url
    5        return  urlopen(url).read()
    6     return get#return这个值的时候不仅仅是函数,还有一层作用域关系
    7 oldboy = index('http://crm.oldboyedu.com')
    8 print(oldboy().decode('utf-8'))

    闭包函数的特点:拿到函数,在任何位置执行,要找他里面引用的值优先从哪里找?优先从自己包的那层作用域开始找,也就相当于这个函数自带的一种状态。

    辅助验证闭包函数的概念,可以看出他外面包的内容:

      print(oldboy.__closure__[0].cell_contents)

    输出结果:http://crm.oldboyedu.com

    闭包函数的核心:内部函数,包含对外部作用域的引用。return把这个函数返回来。

    第五节 装饰器

      装饰器指的是修饰别人的工具。修饰指的是添加功能,工具指的是函数。装饰器本身可以是任何可调用(名字加括号可以执行的,这就是可调用的)对象,被装饰的对象也可以是任意可调用对象。

    为什么要用装饰器啊?

      开放封闭原则:对修改是封闭的,对扩展是开放的,(比如你在公司写了一款游戏,这个游戏最终要上线,上线完了之后这些代码就一直不动了么?会有改的需求,那么问题来了!假如你写的代码是一个一个的函数,让你进行功能的修改,那么你打算怎样去做?去改源代码的话风险特别大,因为你一个函数可能很多地方都在用,你把定义的源代码给改掉了,影响的可能不是一个点,可能影响到好多其他地方,牵一发而动全身,如果你改对了,那就没问题,一旦你改错了呢?就会导致一系列的连锁反应,可能这个软件都会垮掉,所以,已经上线的程序,源代码要尽量避免修改,但是,难道就不改了么?对修改源代码这种操作应该封闭起来,但是对于扩展功能你还不得不做,你的代码一定要为后期的这种扩展留下可能性,而且还不能动源代码,这就用到了装饰器的功能。)装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能。

    应用:

     1 #!/usr/bin/python
     2 # -*- coding:utf-8 -*-
     3 #模拟统计一个函数执行了多长时间
     4 import time
     5 def index():
     6     time.sleep(3)
     7     print('welcome to index')
     8 index()
     9 
    10 #现在就统计上面的按个函数执行用了多长时间,如果用下面这种写法,就违反了不可修改源代码的规则
    11 import time
    12 def index():
    13     start_time = time.time()
    14     time.sleep(3)
    15     print('welcome to index')
    16     stop_time = time.time()
    17     print('run time is %s' %(stop_time-start_time))
    18 index()
    19 
    20 #要保证源代码不能动,调用方式也不能动
    21 import time
    22 def timmer(func):
    23     def wrapper(*args,**kwargs):
    24         start_time = time.time()
    25         res = func(*args,**kwargs)
    26         stop_time = time.time()
    27         print('run time is %s' %(stop_time-start_time))
    28     return wrapper
    29 @timmer
    30 def index():
    31     time.sleep(3)
    32     print('welcome to index')
    33 index()
    34 输出结果:
    35 welcome to index
    36 run time is 3.0002999305725098

    上面例子也可以用闭包函数实现:

     1 import time
     2 def timmer(func):
     3     def wrapper():
     4         start_time = time.time()
     5         func()#调的是index()
     6         stop_time = time.time()
     7         print('run time is %s' %(stop_time - start_time))
     8     return wrapper
     9 def index():
    10     time.sleep(3)
    11     print('welcome to index')
    12 
    13 index = timmer(index)
    14 index()

    不能每次都调用,也可以使用装饰器完成:

     1 import time
     2 def timmer(func):
     3     def wrapper():
     4         start_time = time.time()
     5         func()#调的是index()
     6         stop_time = time.time()
     7         print('run time is %s' %(stop_time - start_time))
     8     return wrapper
     9 @timmer #他会把他正下方的这个函数名当成是参数传进来,结果在给index。index=timmer(index)
    10 def index():
    11     time.sleep(3)
    12     print('welcome to index')
    13 
    14 index()

    我们来分析一下装饰器的流程

     1 #代码是从上而下解释执行
     2 
     3 
     4 import time#1、只是定义一个名字而已,没有任何意义
     5 def timmer(func):#2、这就是定义了一个名字,没有意义,把他折叠合上
     6     def wrapper():#4、首先这定义的是一个函数,把他折叠上,他就是一个名字而已
     7                   #8、展开wrapper,一执行,
     8         start_time = time.time()#9执行这句
     9         func()#10、调的是最原始的index(),是第六步的index
    10         stop_time = time.time()#14、继第13步
    11         print('run time is %s' %(stop_time - start_time))#15、统计一下func()的时间,至此wrapper函数才算执行完
    12     return wrapper#5、在wrapper函数合上的情况下,执行第三部就相当于只是得到wrapper的返回值,第三部就相当于index=wrapper,把函数当做数据传递
    13 @timmer #3、他会把他正下方的这个函数名当成是参数传进来,而且这种方式是固定的,这就是装饰器的语法,这个函数的返回值在重新给index,打开折叠的index函数,看看他都执行了什么
    14 def index():#6继续往下走,到这部,这个函数就是一个定义,没意义,折叠上
    15             #11被第十步调用
    16     time.sleep(3)#12、执行这句,先睡3秒
    17     print('welcome to index')#13、然后打印这句话,紧接着在执行第十四步
    18 
    19 index()#7、index函数折叠之后,就到这部了,调用index,现在的这个index已经是wrapper了,所以现在执行的是wrapper(),那看wrapper是怎样执行的

    流程分析完了,我们想想这有什么问题?见如下代码,为什么返回的是null而不是1?倒数第二行表明了其原因!现阶段,你只要学会了这个流程,写装饰器怎么写?把闭包函数的格式套过来。装饰器就是闭包函数的一种实现方式。

     1 import time
     2 def timmer(func):
     3      def wrapper():
     4         start_time = time.time()
     5         func()#调的是index()
     6         stop_time = time.time()
     7         print('run time is %s' %(stop_time - start_time))
     8      return wrapper
     9 @timmer #他会把他正下方的这个函数名当成是参数传进来,结果在给index。index=timmer(index)
    10 def index():
    11      time.sleep(3)
    12      print('welcome to index')
    13      return 1
    14 
    15 res = index()#现在执行的index还是你之前的index么?执行的是wrapper(),所以你拿的是wrapper的返回值。而wrapper是没有返回值的。
    16 print(res)

    那有同学这样写:把return 1 放在了wrapper里面

     1 import time
     2 def timmer(func):
     3      def wrapper():
     4         start_time = time.time()
     5         func()#调的是index()
     6         stop_time = time.time()
     7         print('run time is %s' %(stop_time - start_time))
     8         return 1#把return 1 加在此处,如果这样的话,上面的func()就拿不到东西了
     9      return wrapper
    10 @timmer #他会把他正下方的这个函数名当成是参数传进来,结果在给index。index=timmer(index)
    11 def index():
    12      time.sleep(3)
    13      print('welcome to index')
    14      return 1
    15 
    16 res = index()#现在执行的index还是你之前的index么?执行的是wrapper(),所以你拿的是wrapper的返回值。而wrapper是没有返回值的。
    17 print(res)

    那该怎样修正呢?如下修正,返回结果就是1了

     1 import time
     2 def timmer(func):
     3      def wrapper():
     4         start_time = time.time()
     5         res=func()#(2)这里调的就是index(),我们已经把这个返回值func()暂存下来了res。等所有功能加载完之后,我们在把最原始函数的返回值当做wrapper函数的返回值在返回就可以。
     6         stop_time = time.time()
     7         print('run time is %s' %(stop_time - start_time))
     8         return res
     9      return wrapper
    10 @timmer #他会把他正下方的这个函数名当成是参数传进来,结果在给index。index=timmer(index)
    11 def index():
    12      time.sleep(3)
    13      print('welcome to index')
    14      return 1 #(1)因为这个返回值就要看什么时候调用index
    15 
    16 res = index()
    17 print(res)

    在考虑下,如果index换成有参函数呢?

     1 import time
     2 def timmer(func):
     3        def wrapper():
     4           start_time = time.time()
     5           res=func()
     6           stop_time = time.time()
     7           print('run time is %s' %(stop_time - start_time))
     8           return res
     9        return wrapper
    10 @timmer 
    11 def index():
    12       time.sleep(3)
    13       print('welcome to index')
    14       return 1 
    15 @timmer
    16 def foo(name):
    17     time.sleep(1)
    18     print('from foo')
    19 # res = index()
    20 # print(res)
    21 res1 = foo('egon')#res1= wrapper('egon')。相当于调用了wrapper,并传了一个参数进去.而看一下参数
    22 print(res1)
    23 输出结果:
    24 D:	oolspythonpython.exe "E:PyCharmPyCharm 2017.1helperspydevpydevd.py" --multiproc --qt-support --client 127.0.0.1 --port 47326 --file D:/python2017/20170423/s17_zc/day04/装饰器.py
    25 pydev debugger: process 4748 is connecting
    26 
    27 Connected to pydev debugger (build 171.3780.115)
    28 Traceback (most recent call last):
    29   File "E:PyCharmPyCharm 2017.1helperspydevpydevd.py", line 1578, in <module>
    30     globals = debugger.run(setup['file'], None, None, is_module)
    31   File "E:PyCharmPyCharm 2017.1helperspydevpydevd.py", line 1015, in run
    32     pydev_imports.execfile(file, globals, locals)  # execute the script
    33   File "E:PyCharmPyCharm 2017.1helperspydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    34     exec(compile(contents+"
    ", file, 'exec'), glob, loc)
    35   File "D:/python2017/20170423/s17_zc/day04/装饰器.py", line 93, in <module>
    36     res1 = foo('egon')
    37 TypeError: wrapper() takes 0 positional arguments but 1 was given
    38 
    39 Process finished with exit code 1

    上面函数报错,wrapper函数需要0个参数,但是确给了一个!原因是foo('egon')就相当于调用了wrapper,并传了一个参数进去。那这种情况如何解决呢?加一个参数就可以了,如下代码:

     1 import time
     2 def timmer(func):
     3        def wrapper(name):#加上name参数
     4           start_time = time.time()
     5           res=func(name)#加上name参数
     6           stop_time = time.time()
     7           print('run time is %s' %(stop_time - start_time))
     8           return res
     9        return wrapper
    10 @timmer #他会把他正下方的这个函数名当成是参数传进来,结果在给index。index=timmer(index)
    11 def index():
    12       time.sleep(3)
    13       print('welcome to index')
    14       return 1 #(1)因为这个返回值就要看什么时候调用index
    15 @timmer
    16 def foo(name):
    17     time.sleep(1)
    18     print('from foo')
    19 # res = index()
    20 # print(res)
    21 res1 = foo('egon')
    22 print(res1)
    23 返回结果:
    24 from foo
    25 run time is 1.0001001358032227
    26 None

    如果将如上的代码注释掉的内容

    # res = index()
    # print(res)
    释放开,执行之后还是报错如图:
     1 import time
     2 def timmer(func):
     3        def wrapper(name):
     4           start_time = time.time()
     5           res=func(name)
     6           stop_time = time.time()
     7           print('run time is %s' %(stop_time - start_time))
     8           return res
     9        return wrapper
    10 @timmer
    11 def index():
    12       time.sleep(3)
    13       print('welcome to index')
    14       return 1
    15 @timmer
    16 def foo(name):
    17     time.sleep(1)
    18     print('from foo')
    19 res = index()
    20 print(res)
    21 res1 = foo('egon')
    22 print(res1)
    23 输出结果:
    24 D:	oolspythonpython.exe "E:PyCharmPyCharm 2017.1helperspydevpydevd.py" --multiproc --qt-support --client 127.0.0.1 --port 50255 --file D:/python2017/20170423/s17_zc/day04/装饰器.py
    25 pydev debugger: process 896 is connecting
    26 
    27 Connected to pydev debugger (build 171.3780.115)
    28 Traceback (most recent call last):
    29   File "E:PyCharmPyCharm 2017.1helperspydevpydevd.py", line 1578, in <module>
    30     globals = debugger.run(setup['file'], None, None, is_module)
    31   File "E:PyCharmPyCharm 2017.1helperspydevpydevd.py", line 1015, in run
    32     pydev_imports.execfile(file, globals, locals)  # execute the script
    33   File "E:PyCharmPyCharm 2017.1helperspydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    34     exec(compile(contents+"
    ", file, 'exec'), glob, loc)
    35   File "D:/python2017/20170423/s17_zc/day04/装饰器.py", line 91, in <module>
    36     res = index()
    37 TypeError: wrapper() missing 1 required positional argument: 'name'
    38 
    39 Process finished with exit code 1

    发现将注释放开之后,上面的wrapper又不需要参数了,这就是用到了可变长的概念,可能有也可能没有,长度不固定。那怎么解决这个问题!如下利用*args和**kwargs

     1 import time
     2 def timmer(func):
     3        def wrapper(*args,**kwargs):
     4           start_time = time.time()
     5           res=func(*args,**kwargs)
     6           stop_time = time.time()
     7           print('run time is %s' %(stop_time - start_time))
     8           return res
     9        return wrapper
    10 @timmer
    11 def index():
    12       time.sleep(3)
    13       print('welcome to index')
    14       return 1
    15 @timmer
    16 def foo(name):
    17     time.sleep(1)
    18     print('from foo')
    19 res = index()
    20 print(res)
    21 res1 = foo('egon')
    22 print(res1)
    23 返回结果:
    24 welcome to index
    25 run time is 3.0
    26 1
    27 from foo
    28 run time is 1.0
    29 None

    接下来写一个装饰器,实现一个认证功能。现在定义一堆函数,在这些函数真实的功能执行之前,加上一段认证功能,只有认证通过了了,才能去执行他的一个真实的功能。

    比如对如下函数进行认证

    1 def index():
    2     print('welcome to index page')
    3 def home(name):
    4     print('%s welcome to home page' %name)
    5 index()
    6 home('egon')

    登录成功进行打印,否则提示登录错误,代码如下:

     1 def auth(func):
     2     def wrapper(*args,**kwargs):
     3         name = input('>>:')
     4         password = input('>>:')
     5         if name == 'egon' and password == '123':
     6             print('33[45mlogin successful33[0m')
     7             res = func(*args,**kwargs)
     8             return res
     9         else:
    10             print('33[45mlogin error33[0m')
    11     return wrapper
    12 @auth
    13 def index():
    14     print('welcome to index page')
    15 @auth
    16 def home(name):
    17     print('%s welcome to home page' %name)
    18 index()
    19 home('egon')
    20 返回结果:
    21 Connected to pydev debugger (build 171.3780.115)
    22 >>:egon
    23 >>:123
    24 login successful
    25 welcome to index page
    26 >>:222
    27 >>:2
    28 login error

    上面的代码存在一个问题:您输入完登录用户名和密码之后已经登录成功,可以点主页了,为什么还是让输入用户名和密码再次进行认证呢?用session保存一下,session就是一堆变量的定义,没什么特别之处。登录成功就要把登录的状态记录下来,下次再需要登录的时候直接从认证结果里面去取看有没有登录,如果已经登录了就直接认证通过,就不用再认证了。现在来模拟一下怎么实现呢?

     1 login_user={'user':None,'statue':False}
     2 #定义一个全局变量,一开始没有用户登录,所以为None,默认的状态为未登录的状态
     3 def auth(func):
     4     def wrapper(*args,**kwargs):
     5         if login_user['user'] and login_user['statue']:
     6             res = func(*args,**kwargs)
     7             return res
     8         else:
     9             name = input('>>:')
    10             password = input('>>:')
    11             if name == 'egon' and password == '123':
    12                 login_user['user'] = 'egon'
    13                 login_user['statue'] = True#记录一下状态
    14                 print('33[45mlogin successful33[0m')
    15                 res = func(*args,**kwargs)
    16                 return res
    17             else:
    18                 print('33[45mlogin error33[0m')
    19     return wrapper
    20 @auth
    21 def index():
    22     print('welcome to index page')
    23 @auth
    24 def home(name):
    25     print('%s welcome to home page' %name)
    26 index()
    27 home('egon')
    28 输出结果:
    29 >>:egon
    30 >>:123
    31 login successful
    32 welcome to index page
    33 egon welcome to home page

    想这样的一个问题,你公司的认证,来源就是一个数据库么?也有可能从ldap、文件里面取,各种各样的认证源。你得给这个认证源提供接口,让别人能够选择通过哪种方式来认证。这就涉及到有参装饰器了。之前我们使用的是无参装饰器,没有传任何参数,直接写了函数名字。对于有参装饰器怎么玩的呢?

     1 login_user={'user':None,'statue':False}
     2 def auth(driver='file'):
     3     #认证来源为文件,这是闭包函数,使driver这个参数被auth2这个函数使用
     4     def auth2(func):
     5         def wrapper(*args,**kwargs):
     6             if driver == 'file':
     7                 if login_user['user'] and login_user['statue']:
     8                     res = func(*args,**kwargs)
     9                     return res
    10                 else:
    11                     name = input('>>:')
    12                     password = input('>>:')
    13                     if name == 'egon' and password == '123':
    14                         login_user['user'] = 'egon'
    15                         login_user['statue'] = True#记录一下状态
    16                         print('33[45mlogin successful33[0m')
    17                         res = func(*args,**kwargs)
    18                         return res
    19                     else:
    20                         print('33[45mlogin error33[0m')
    21             elif driver == 'ldap':
    22                 print('========ldap的认证')
    23             elif driver == 'mysql':
    24                 print('========mysql的热证')
    25                 return func(*args,**kwargs)#如果不加这句,就无法调用最原始函数,可以不加这句试一下执行结果
    26             else:
    27                 print('========未知认证来源')
    28         return wrapper
    29     return auth2
    30 @auth('file')#这个参数还可以写成driver='file'。这句会立即去执行auth这个函数,执行的结果等于auth2,auth2不仅是auth2,
    31 # 还有个对driver的引用,碰到auth2就会把他正下方的函数当做参数传进来,得到的结果在赋值给index。index=auth2(index)===>index=wrapper
    32 
    33 def index():
    34     print('welcome to index page')
    35 @auth(driver='mysql')
    36 def home(name):
    37     print('%s welcome to home page' %name)
    38 index()#他执行的是wrapper()
    39 home('egon')#他执行的也是wrapper('egon')
    40 
    41 输出结果:
    42 >>:egon
    43 >>:123
    44 login successful
    45 welcome to index page
    46 ========mysql的热证
    47 egon welcome to home page

    装饰器补充点:

    叠加多个装饰器的使用情况:

     1 import time
     2 def timmer(func):
     3     def wrapper(*args,**kwargs):
     4         print('=====>time.wrapper')#测试是先执行timmer的wrapper,还是auth的wrapper
     5         start_time = time.time()
     6         res = func(*args,**kwargs)#执行的是auth_wrapper
     7         stop_time = time.time()
     8         print('run time is %s' %(stop_time-start_time))
     9     return wrapper
    10 login_user={'user':None,'statue':False}
    11 def auth(driver='file'):
    12 
    13     def auth2(func):
    14         def wrapper(*args,**kwargs):
    15             print('=====>auth.wrapper')#测试是先执行timmer的wrapper,还是auth的wrapper
    16             if driver == 'file':
    17                 if login_user['user'] and login_user['statue']:
    18                     res = func(*args,**kwargs)
    19                     return res
    20                 else:
    21                     name = input('>>:')
    22                     password = input('>>:')
    23                     if name == 'egon' and password == '123':
    24                         login_user['user'] = 'egon'
    25                         login_user['statue'] = True#记录一下状态
    26                         print('33[45mlogin successful33[0m')
    27                         res = func(*args,**kwargs)
    28                         return res
    29                     else:
    30                         print('33[45mlogin error33[0m')
    31             elif driver == 'ldap':
    32                 print('========ldap的认证')
    33             elif driver == 'mysql':
    34                 print('========mysql的热证')
    35                 return func(*args,**kwargs)
    36             else:
    37                 print('========未知认证来源')
    38         return wrapper
    39     return auth2
    40 @timmer#3)把正下方的函数名传进来,就相当于 index=timer(auth_wrapper),最后index=timer(wrapper)
    41 @auth('file')#2)auth2====>index=auth2(index)====>index===>auth_wrapper,所以1)中的index()就是wrapper()
    42 def index():
    43     print('welcome to index page')
    44 @auth(driver='mysql')
    45 def home(name):
    46     print('%s welcome to home page' %name)
    47 index()#1)执行index,就会去找@auth('file')
    48 #home('egon')#他执行的也是wrapper('egon')
    49 
    50 输出结果:
    51 =====>time.wrapper
    52 =====>auth.wrapper
    53 >>:egon
    54 >>:123
    55 login successful
    56 welcome to index page
    57 run time is 5.300530195236206

     对于上面的例子,当只有一个装饰器 @auth('file') ,他修饰的是他正下方对着的函数,如果在@auth('file')上面再加一个装饰器@timmer的话,他修饰的是谁呢?@timmer也是修饰他正下方的函数,他正下方的函数就是@auth('file'),这个auth拿到的结果是被修改过的index。先执行的装饰器是最上面的@timmer,在执行下面的@auth('file') .这个装饰器的执行顺序对功能调用有没有影响?是有影响的,@timmer放在auth('file')上,证明你统计的是auth('file')的时间,放在@auth('file')下,说明你统计的是index函数的时间。 auth()是为了给index加上认证功能。如下代码:

     1 import time
     2 def timmer(func):
     3     def wrapper(*args,**kwargs):#2)执行这个timmer_wrapper,统计执行时间
     4         print('=====>time.wrapper')#3)先打印这行
     5         start_time = time.time()#4)获取开始时间
     6         res = func(*args,**kwargs)#5)执行这个func,这个func执行的是auth_wrapper,auth_wrapper执行不完永远拿不到下面的结束时间,这中间一直统计的是auth执行的时间,auth里面再去调真正的index
     7         #最终,统计的是auth和auth修饰的index的时间总和
     8         stop_time = time.time()
     9         print('run time is %s' %(stop_time-start_time))
    10     return wrapper
    11 login_user={'user':None,'statue':False}
    12 def auth(driver='file'):
    13     def auth2(func):
    14         def wrapper(*args,**kwargs):
    15             print('=====>auth.wrapper')
    16             time.sleep(5)
    17             if driver == 'file':
    18                 if login_user['user'] and login_user['statue']:
    19                     res = func(*args,**kwargs)
    20                     return res
    21                 else:
    22                     name = input('>>:')
    23                     password = input('>>:')
    24                     if name == 'egon' and password == '123':
    25                         login_user['user'] = 'egon'
    26                         login_user['statue'] = True#记录一下状态
    27                         print('33[45mlogin successful33[0m')
    28                         res = func(*args,**kwargs)
    29                         return res
    30                     else:
    31                         print('33[45mlogin error33[0m')
    32             elif driver == 'ldap':
    33                 print('========ldap的认证')
    34             elif driver == 'mysql':
    35                 print('========mysql的热证')
    36                 return func(*args,**kwargs)
    37             else:
    38                 print('========未知认证来源')
    39         return wrapper
    40     return auth2
    41 @timmer
    42 @auth('file')
    43 def index():
    44     time.sleep(3)
    45     print('welcome to index page')
    46 @auth(driver='mysql')
    47 def home(name):
    48     print('%s welcome to home page' %name)
    49 index()#1)执行index,先执行timmer_wrapper()
    50 #home('egon')#他执行的也是wrapper('egon')
    51 输出结果:
    52 =====>time.wrapper
    53 =====>auth.wrapper
    54 >>:egon
    55 >>:123
    56 login successful
    57 welcome to index page
    58 run time is 11.817363023757935

    为何时间比8s还长呢?因为中途有控制台输入的过程。那如何只统计index函数的时间呢?只需要把@timmer装饰器放在@auth('file')下即可。

    第六节 迭代器

    迭代的概念:重复的过程称为迭代,每次重复一次迭代,并且每次迭代的结果是下一次迭代的初始值。如下代码只是重复,不叫迭代!

    while True:
        print('=========')  

    下面的内容才是迭代:  

    1 l = [1,2,3]
    2 count = 0
    3 while count < len(l):
    4     print('======>',l[count])
    5     count += 1

    上面为迭代列表,那元组可以进行迭代么?

    1 l = (1,2,3)
    2 count = 0
    3 while count < len(l):
    4     print('======>',l[count])
    5     count += 1

    字符串也可以:

    1 s = 'hello'
    2 count = 0
    3 while count < len(s):
    4     print('=====>',s[count])
    5     count += 1
    以上迭代的例子都是有下标的,那没有下标的呢?比如字典,集合?为什么要有迭代器:对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式。
    研究迭代器必须明白这样的概念,可迭代的对象:Python会对一些数据类型内置一些方法,内置__iter__方法的,都是可迭代的对象:

    [1,2].__iter__()#列表
    'hello'.__iter__()#字符串
    (1,2).__iter__()#元组
    {'a':1,'b':2}.__iter__()#字典
    {1,2,3}.__iter__()#集合
    f = open('a.txt','w')#文件
    f.__iter__()
    只要数据类型下面有__iter__()这种方法的,这个数据类型就被称为可迭代的对象。执行__iter__()方法得到的结果就是迭代器(对象),迭代器对象有__next_方法。
    执行如下:
    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 i = [1,2,3].__iter__()
    4 print(i)
    5 输出结果:
    6 <list_iterator object at 0x006F5B70>
    是这个列表的迭代器。

    迭代器有什么特性呢?迭代器没有索引,要想取迭代器里面的值,该怎么取呢?执行 i._next_()。如下代码不依赖于索引把元素取出来。

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 i = [1,2,3].__iter__()
    4 print(i)
    5 print(i.__next__())
    6 print(i.__next__())
    7 print(i.__next__())

    如果继续执行print(i.__next__()),会提示如下:

    Traceback (most recent call last):
      File "D:/python2017/20170423/s17_zc/day04/迭代器.py", line 36, in <module>
        print(i.__next__())
    StopIteration

    如果是字典呢?把里面的值一个一个取出来,怎么操作?

    1 i = {'a':1,'b':2,'c':3}.__iter__()
    2 print(i.__next__())
    3 print(i.__next__())
    4 print(i.__next__())
    5 输出结果:
    6 a
    7 b
    8 c

    现在想要把字典里面的全部的值都拿出来,怎么操作?以上例子对于字典、文件、集合都可以。

    1 dic = {'a':1,'b':2,'c':3}
    2 i = dic.__iter__()
    3 while True:
    4     try:
    5         key = i.__next__()
    6         print(dic[key])
    7     except StopIteration:
    8         break

    补充:统计一个数据的长度怎么统计?

    1 s = 'hello'
    2 print(s.__len__())
    3 # print(len(s))
    #len(s)就等同于s.__len__()

    以上概念要是懂了我们看下面的代码:

    1 s = {'a',3,2,4}
    2 #把这个集合变成迭代器怎么操作呢?
    3 #s.__iter__()#等同于iter(s)
    4 i = iter(s)
    5 print(next(i))
    6 print(next(i))
    7 print(next(i))
    8 print(next(i))

    如何判断一个对象是可迭代的对象,还是迭代器对象?

    1 from collections import Iterable,Iterator
    2 #导入可迭代的对象Iterable,和Iterator迭代器对象
    3 f = open('a.txt','w')
    4 f.__iter__()
    5 print(isinstance('abc',Iterable))#isinstance来判断字符串abc是不是可迭代的
    6 print(isinstance(f,Iterable))

    以上的对象是可迭代的,但是他们是迭代器么?用如下代码实现:

    1 from collections import Iterable,Iterator
    2 #导入可迭代的对象Iterable,和Iterator迭代器对象
    3 f = open('a.txt','w')
    4 f.__iter__()
    5 print(isinstance('abc',Iterator))#isinstance来判断字符串abc是不是可迭代的
    6 print(isinstance(f,Iterator))

    如上:列表、字符串、元组、集合、字典都是可迭代的对象。但是只有文件是迭代器对象,因为他有__next__方法。但是,如图字符串执行了__iter__方法,那么他的结果就是迭代器对象。可迭代对象只有__iter__方法,执行该方法得到的是迭代器对象,而迭代器对象不仅有__iter__方法,还有__next__方法。只不过对于迭代器来说这个__iter__没有意义,因为执行完返回的仍然是他本身,但是对于for循环就有意义了,他为的就是符合for循环的基本的工作原理。

    1 from collections import Iterable,Iterator
    2 #导入可迭代的对象Iterable,和Iterator迭代器对象
    3 f = open('a.txt','w')
    4 f.__iter__()
    5 print(isinstance('abc'.__iter__(),Iterator))#isinstance来判断字符串abc是不是可迭代的
    6 print(isinstance(f,Iterator))

    迭代协议:对象有__next__、__iter__方法

                     对于迭代器来说,执行__iter__方法,得到的结果仍然是他本身。

     1 f = open('a.txt','w')
     2 f.__iter__()
     3 f1 = f.__iter__()
     4 print(f)
     5 print(f1)
     6 print(f is f1)
     7 输出结果:
     8 <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'>
     9 <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'>
    10 True

     如下代码,for循环的使用(复习以前学过的):

    1 dic = {'name':'egon','age':18,'height':'180'}
    2 print(dic.items())
    3 for k,v in dic.items():
    4     print(k,v)
    5 输出结果:
    6 dict_items([('height', '180'), ('name', 'egon'), ('age', 18)])
    7 height 180
    8 name egon
    9 age 18

    思考下面代码,为何for循环会把key拿出来?

    1 dic = {'name':'egon','age':18,'height':'180'}
    2 for k in dic:#i = iter(dic) k = next(i)
    3     print(k)
    4 输出结果:
    5 height
    6 name
    7 age

    因为for循环遵循的就是迭代器协议,他会执行in 后面的对象的__iter__方法(注意:in后面的对象一定是可迭代的对象。),把他变成一个迭代器对象,然后在next,一次for循环就相当于next一次。并且帮你做try的事情,帮你捕捉异常,他就相当于如下代码:

    1 dic = {'name':'egon','age':18,'height':'180'}
    2 i = iter(dic)
    3 while True:
    4     try:
    5         k = next(i)
    6         print(k)
          #print(dic[k])取里面的value
    7 except StopIteration: 8 break

    可迭代对象一定是迭代器么?(不一定)但是迭代器一定是可迭代对象!所以从for级别,无法判断他是一个可迭代对象还是一个迭代器对象,所以,只要后面有对象,for都执行他的__iter__方法,如果他只是可迭代的对象,那我执行__iter__方法,他就是一个迭代器。如果in后面跟着的是迭代器,那我执行__iter__方法得到的是他本身。   

    迭代器的优劣:
    优点:1、提供了一种不依赖于下标的迭代方式
    2、就迭代器本身来说,更节省内存
     1 解释:为什么说迭代器更节省内存呢?
     2 例1:
     3 l=[10000,2,3,4,5]#所有值都同时在内存中
     4 
     5 i = iter(l)#这样就不会造成所有值都同时在内存里面,next一次,取一个值
     6 print(i)
     7 print(next(i))
     8 例2:
     9 将文件中内容全部放在内存中,全部展示,浪费内存
    10 f = open('a.txt',encoding='utf-8')
    11 for line in f.readlines():
    12     print(line)
    13 如果是如下写法,一行一行读出来,就会节省内存:
    14 f = open('a.txt',encoding='utf-8')
    15 print(next(f))
    16 要遍历怎么遍历呢?
    17 f = open('a.txt',encoding='utf-8')
    18 for line in f:
    19      print(line)
    20 这种时候同一时间内存只有一行,极大的节约了内存。
    缺点:1、无法获取迭代器对象的长度,直到next完为止
    2、不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退
     1 对第二种解释:
     2 l = [1000,2,3,4,5]
     3 i = iter(l)
     4 for item in i :
     5     print(item)
     6 print('===========')
     7 for item in i :
     8     print(item)
     9 输出结果:
    10 1000
    11 2
    12 3
    13 4
    14 5
    15 ===========

    注意:enumerate就是要给迭代器,他有__next__和__iter__方法。

    l = [1000,2,3,4,5]
    i = enumerate(l)
    print(next(i))
    输出结果:
    (0, 1000)#结果元组形式展示,索引和值

    第七节 生成器 

    生成器指的是生成器函数:只要函数体包含yield关键字,该函数就是生成器函数

    在举生成器函数例子之前,看一下如下代码,为什么两次执行的结果都是1呢?

    1 def foo():
    2     return 1
    3     return 2
    4     return 3
    5     return 4
    6 res1 = foo()
    7 print(res1)
    8 res2 = foo()
    9 print(res2)

    return的特性:只要函数执行到一次return,函数立马就终止。

    把上面代码改写一下:

     1 #!/usr/bin/python
     2 # -*- coding:utf-8 -*-
     3 def foo():
     4     yield 1
     5     yield 2
     6     yield 3
     7     yield 4
     8 g = foo()
     9 print(g)#返回生成器对象
      print(next(g))#取值
    10 输出结果: 11 <generator object foo at 0x0073BBA0>

    上述代码说明了yield直接把函数转成迭代器了。执行next就是触发这个迭代器。取值的时候就可以用print(next(g))。

      如下代码为何只返回了first,返回值哪里去了?

     1 #!/usr/bin/python
     2 # -*- coding:utf-8 -*-
     3 def foo():
     4     print('first')
     5     yield 1
     6     print('second')
     7     yield 2
     8     print('third')
     9     yield 3
    10     print('fourth')
    11     yield 4
    12     print('fifth')
    13 g = foo()
    14 next(g)#触发迭代器g的执行,进而触发函数的执行
    15 输出结果:
    16 first

    因为 next(g)只是触发函数执行的结果,如果执行print(next('g')),才会显示1.是yield返回的结果,只要碰到yield就会暂停执行,并且把后面的值返回来!这就是用yield把函数做成了一个迭代器。

    yield的功能:1、相当于为函数封装好__iter__方法和__next__方法。

          2、return只能返回一次值,函数就终止了。而yield能返回多次值,每次返回就会将函数暂停住。下一次next会从上一次暂停的位置往后继续执行。

    举个例子,用yield把函数做成一个生成器:

     1 def counter(n):
     2     print('start...')
     3     i = 0
     4     while i < n:
     5         yield i
     6         i+=1
     7     print('end...')
     8 g=counter(5)
     9 print(g)#返回一个生成器
    10 print(next(g))#触发迭代器,使用next,第一个next,返回start... ,i 为0 ,满足条件,遇到yield,返回0
    11 print(next(g))#第一次走到yield,返回1,然后接着走i+=1,i变为1,继续走循环,遇到yield,在返回1
    12 print(next(g))
    13 print(next(g))
    14 print(next(g))
    15 print(next(g))
    16 输出结果:
    17 StopIteration
    18 <generator object counter at 0x0077BBA0>
    19 start...
    20 0
    21 1
    22 2
    23 3
    24 4
    25 end...

    通过这个例子想要说明:不管是if循环还是for还是while循环等其他形式,只要执行过程中遇到yield,就是暂停住,把yield后面的值当做这次next的返回值返回。讲完这个例子给他讲一下应用场景:做运维的时候要知道这样的一个概念:管道 | 。管道是把左边命令的执行结果作为右面命令的输入。最常见的:tail -f a.txt |grep 'pyhton' 如何用生成器实现呢?

     1 import time
     2 def tail(filepath):
     3     with open(filepath,encoding='utf-8') as f:
     4         f.seek(0,2)
     5         while True:
     6             line = f.readline().strip()#加上strip去掉回车
     7             if line:
     8                 yield line
     9             else:
    10                 time.sleep(0.2)
    11 t = tail('a.txt')
    12 # print(t)#得到一个生成器
    13 # print(next(t))#得到他的一个值,注意得往a.txt文件里面写入内容保存才可以显示结果
    14 # for line in t:#把读到的内容遍历出来
    15 #     print(line)
    16 
    17 #下面代码实现过滤
    18 def grep(pattern,lines):
    19     for line in lines:
    20         if pattern in line:
    21             print(line)
    22 grep('python',tail('a.txt'))

    如上代码在过滤的时候也可以使用yield:

     1 import time
     2 def tail(filepath):
     3     with open(filepath,encoding='utf-8') as f:
     4         f.seek(0,2)
     5         while True:
     6             line = f.readline().strip()#加上strip去掉回车
     7             if line:
     8                 yield line
     9             else:
    10                 time.sleep(0.2)
    11 t = tail('a.txt')
    12 # print(t)#得到一个生成器
    13 # print(next(t))#得到他的一个值,注意得往a.txt文件里面写入内容保存才可以显示结果
    14 # for line in t:#把读到的内容遍历出来
    15 #     print(line)
    16 
    17 #下面代码实现过滤
    18 def grep(pattern,lines):
    19     for line in lines:
    20         if pattern in line:
    21             yield line
    22 g = grep('python',tail('a.txt'))
    23 print(g)
    24 for i in g:
    25     print(i)

    第八节 内置函数

    1、abs:取绝对值

    print(abs(-1))#取绝对值 1
    

    2、all:1)、for循环一个可循环一个可迭代对象,从可迭代对象里面依次取出他的元素,进行布尔值的判断,如果所有的布尔值都是true的话,最终返回true。2)、 如果可迭代对象为空,那么返回true

    print(all([1,2,3]))#列表是一个可迭代对象,for循环[1,2,3]然后取出第一个值进行布尔值运算,布尔值1得到的值是true,所有值都是true,最终得到的是true。all后面也可以放一个生成器在这里
    print(all(''))#放一个空的字符串,是true
    

    3、any:1)、只要有一个为true,那就为true,都为假就为假  2)、如果传的可迭代对象为空,则返回false

    print(any([0,None,'',1]))#结果为true
    print(any([0,None,'']))#结果为false
    print(any([]))#结果为false
    

    4、bin:把十进制转成二进制

    print(bin(10))
    

    5、hex:把十进制转成十六进制

    print(hex(17))
    

    6、oct:把十进制转成八进制  

    print(oct(9))
    

    7、bool:所有的数据类型都自带布尔值

    0 ,none,空 =====>false,其余的布尔值为true
    

    8、callable:可调用对象

    def func():
        pass
    print(callable(func))
    

    9、char:按照ascii码表把数字转成对应的字符

    print(chr(68))
    

    10、ord:按照ascii码表把字符转成相应的汉字

    print(ord('D'))
    

    11、工厂函数,比如list是批量产生列表的

    dict
    int
    str
    set
    list
    

    12、divmod:一般用来完成分页功能

    print(divmod(100,3))
    

    13、eval:把字符串里面的命令提取出来执行

    cmd = 'print("你瞅啥")'
    eval(cmd)

    如何取出下面字符串里面的字典

    dic = "{'a':1,'b':2}"
    d = eval(dic)
    print(type(d),d['a'])
    

    这个可以用在什么场景呢?以前往文件里面写内容都是字符,如下代码,文件里面存的是字典形式:

    1 with open('user.db','w',encoding='utf-8') as f:
    2     user_dic = {'name':'egon','password':'123'}
    3     f.write(str(user_dic))
    4 #用文件模拟数据库,现在要取出来跟用户进行比对,怎么操作呢?
    5 with open('user.db','r',encoding='utf-8') as f:
    6     dic = f.read()
    7     print(dic,type(dic))#这里是以字符串形式显示的,但是我想用的是字典,怎么操作呢?
    8     dic =eval(dic)#用eval来获取字典形式
    9     print(dic['name'])

    14、frozenset:定义不可变集合

    1 #!/usr/bin/python
    2 # -*- coding:utf-8 -*-
    3 s = {1,2}#s=set({1,2})定义可变集合
    4 s.add(3)#可变集合就是s可以往里面加东西,加了东西之后可以打印出来
    5 print(s)

    不可变集合为下面代码,s都没有add方法:

    s = frozenset({1,2})#定义不可变集合

    15、format:字符串格式化

    s = 'name:{},age:{},height:{}'.format('egon',18,'180')
    print(s)
    

    16、hash:hash是一种算法,通常用来做校验用的:

      1、只要校验的内容一致,那么哈希得到的结果永远一样 

           2、哈希不可逆,不能根据哈希值反推输入的值

           3、只要采用的哈希算法一样,那无论被校验的内容有多长,哈希得到的结果长度一样

    print(hash('asdfadsfdfdfdf'))
    print(hash('asdfadsfdfdfdf'))
    

    17、id:表示对象的身份。跟他对应的有一个叫is运算。

    x = 1
    y = x
    print(id(x),id(y))
    print(x is y)#判断x 和y是否一样,根据他们两个身份进行判断
    
    a = 1
    b = 1
    print(a == b)#等号判断的是值

    18、pow:传两个值做平方操作,传第三个值取模运算

    print(pow(10,2))
    print(pow(10,2,3))
    

    19、reversed:反转

    l = ['a',4,2,3]
    print(reversed(l))#返回结果<list_reverseiterator object at 0x00765BB0>,这是一个反转后的迭代器,所以得用for循环
    for i in reversed(l):
        print(i)

    如下返回列表:list和for一样,也遵循迭代器协议

    l = ['a',4,2,3]
    print(list(reversed(l)))  

    如下代码:

    l = ['a',4,2,3]
    print(reversed(l))#返回结果<list_reverseiterator object at 0x00765BB0>,这是一个迭代器,所以得用for循环
    for i in reversed(l):
        print(i)
    
    print(list(reversed(l)))
    返回结果:
    <list_reverseiterator object at 0x00A55BB0>
    3
    2
    4
    a
    [3, 2, 4, 'a']

    对上面代码编辑如下,返回结果一样,[ ]是因为迭代器已经走完一次:

    l = ['a',4,2,3]
    i = reversed(l)
    for x in i:
        print(x)
    print(list(i))
    返回结果:
    3
    2
    4
    a
    []
    

    20、round:保留几位小数

    print(round(3.141592653589127134,5))#代表保留5位小数
    

    21、slice:切片

    l = ['a','b','c','d','e']
    print(l[1:4])#顾头不顾尾,输出['b', 'c', 'd']
    print(l[1:4:2])#步长为2,输出结果['b', 'd']
    s = slice(1,4,2)
    print(l[s])#输出结果['b', 'd']

    22、wars:如果没有参数,和locals()一样,如果有参数他和__dic__一样效果。

    23、zip:拉链函数

    s='hello'
    l=[1,2,3,4,5]
    z = zip(s,l)
    print(z)#<zip object at 0x008653A0>打印出来的是一个zip对象,发现有__iter__和__next__方法,那么他是一个迭代器
    for i in z :
        print(i)
    #注意:s和l这两个值,就找一一能对应上的。任何一个多一个值都不影响
    输出结果:
    <zip object at 0x007753C8>
    ('h', 1)
    ('e', 2)
    ('l', 3)
    ('l', 4)
    ('o', 5)

    24、__import__:

    m = __import__('time')#这代表以字符串的形式导入一个模块
    #time的功能有sleep,那么m会不会有呢?会有的,只是输入的时候没有提示了。
    m.sleep(30)
    

      

     

      

      

      

      

      

      

     

  • 相关阅读:
    手把手教你如何逐步安装OpenStack
    掌握OpenStack部署的最佳实践 打破部署失败的魔咒
    大数据服务大比拼:AWS VS. AzureVS.谷歌
    fullcalender
    也谈---基于 HTTP 长连接的“服务(转载)
    调用页面脚本
    mssql 低版本数据库 使用高版本的命令
    行变列 pivot
    HighCharts -在包含容器尺寸发生变化时重新渲染
    ES6 import export
  • 原文地址:https://www.cnblogs.com/zhaic/p/6890865.html
Copyright © 2011-2022 走看看