• 闭包、装饰器decorator、迭代器与生成器、面向过程编程、三元表达式、列表解析与生成器表达式


    一、装饰器

    一、装饰器的知识储备

      不想修改函数的调用方式,但是还想在原来的函数前后添加功能

      1、可变长参数  :*args和**kwargs

    1 def index(name,age):
    2     print(name,age)
    3 
    4 def wrapper(*args,**kwargs):
    5     #即args=(1,2,3,4,5),kwargs={'x':1,'y':3}
    6     index(*args,**kwargs)
    7     #index(1,2,3,4,5,y=2,x=5)

      2、函数对象:被当做数据传递

        1、函数可以当做参数传给另外一个函数
        2、一个函数的返回值,也可以是一个函数(打破函数的层级关系)
            def f1():
                def f2():
                    print('f2')
                return f2  ##打破函数的层级关系
            f=f1()
            f()

      3、名称空间和作用域

        1、名称空间:
            分类:分三种
                内置名称空间:Python解释器启动则生效,关闭时失效
                全局名称空间:执行Python文件时生效
    
                内置名称空间:调用函数时,临时生效;函数调用结束失效
             加载顺序:先内置,在全局,最后有可能产生局部
             查找名字的顺序:先局部,再全局,最后内置
        2、作用域
            分类:分两种
                全局作用域:全局存活,全局有效
                局部作用域:临时存活,局部有效
        强调:作用关系在函数定义阶段已经固定,与调用位置无关

    二、闭包函数

      1、定义

    1、定义在函数内部的函数
    2、包含对外部作用域名字的引用,而不是对全局作用域名字的引用
       那么该内部函数称之为闭包函数
    

      2、实例

     1 x = 1
     2 def f1():
     3     x=111111111111
     4     def f2():  #f2是闭关函数
     5         print(x)
     6     return f2  ##获取返回值
     7 func=f1()
     8 # func()
     9 
    10 def  foo():
    11     x=1988193190112131
    12     func()
    13 foo()
    View Code

      3、应用:延迟计算/惰性计算(爬网页)

    1 def get(url):
    2     return requests.get(url).text
    3 # print(get('https://www.toutiao.com/'))
    4 print(get('https://www.python.org'))
    方式一
     1 import  requests  #需要pip3 install request
     2 def index(url):
     3     # url='https://www.python.org'
     4     def get():
     5         return requests.get(url).text
     6     return get
     7 python_web=index('https://www.python.org')
     8 baidu_web=index('https://www.baidu.com')
     9 python_web()
    10 baidu_web()
    优化
    def get(url): #url='http://www.baidu.com'
    # url='http://www.baidu.com'
    def inner():
    return urlopen(url).read()
    return inner

    baidu=get('http://www.baidu.com')
    print(baidu)
    res=baidu()
    baidu()
    def index(url):
        # url='https://www.python.org'
        def warpper():
            return requests.get(url).text
        return warpper
    python_web=index('https://www.python.org')
    print(python_web.__closure__[0])  ##closure 闭包  ##能看到内存地址就不要使用ID
    

     三、装饰器

    装饰器就是闭包函数的一种应用场景

      1、为何要用装饰器

    开放封闭原则:对修改封闭,对扩展开放

      2、装饰器的定义和原则

    装饰器本身可以是任意可以调用对象,被装饰的对象本身也可以是任意可调用对象
    定义:本质是函数,(装饰其他函数),就是为其他函数添加附加功能
       在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
    原则:1、不能修改被装饰的函数的源代码
             2、不能修改被装饰的函数的调用方式
    

      添加统计执行时间的功能

    1 import time
    2 def index():
    3     start=time.time()
    4     time.sleep(3)
    5     print('welcome to index')
    6     stop=time.time()
    7     print('run time is :[%s}' %(stop-start))
    8 index()
    修改源代码
     1 import time
     2 def index():
     3     time.sleep(3)
     4     print('welcome to index')
     5 # index()
     6 
     7 def wrapper(func):
     8     start=time.time()
     9     func()
    10     stop=time.time()
    11     print('run time is %s' %(stop-start))
    12 #wrapper(index)  ##注意index一定不能加() ,因为使用的是内存地址
    13 index=wrapper(index)
    不修改源代码,修改调用方式

      3、装饰的定义和调用

     使用装饰器添加统计执行时间的功能,不修改原代码,不修改调用方式

     1 import time
     2 def timmer(func):
     3     # func=index
     4     def wrapper():
     5         start=time.time()
     6         func()
     7         stop=time.time()
     8         print('run time is [%s]' %(stop-start))
     9     return wrapper
    10 
    11 @timmer #等价于index=timmer(index)  #@装饰器名,会将正下方函数名作为参数传给装饰器,然后重新赋值给函数名
    12 def index():
    13     time.sleep(3)
    14     print('welcome to index')
    15 # index=timmer(index)  ##实践一:重新赋值,然后调用
    16 # index()
    17 
    18 @timmer #等价于home=timmer(home)
    19 def home():
    20     time.sleep(3)
    21     print('welcome %s to home' %name)
    22 index()
    23 home()
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/9/23
     5 ##有参和无参函数都能使用装饰器(*args,**kwargs)
     6 import time
     7 def timmer(func):
     8     # func=index
     9     def wrapper(*args,**kwargs):
    10         start=time.time()
    11         res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
    12         stop=time.time()
    13         print('run time is %s' %(stop-start))
    14         return res ##有无返回值,均可处理
    15     return wrapper
    16 @timmer #等价于index=timmer(index)  #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
    17 def index():
    18     time.sleep(3)
    19     print('welcome to index')
    20     return 123
    21 # index()
    22 
    23 @timmer #等价于home=timmer(home)
    24 def home(name):
    25     time.sleep(3)
    26     print('welcome to home')
    27 #有返回值
    28 res=index()  #即res=wrapper
    29 print(res)
    30 home('wzs')  #即wrapper('wzs')
    被装饰对象有参数,参数类型和数量不固定
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/9/23
     5 ##eval 将字符串里面的命令提取出来,执行一下
     6 #字符串转成字典
     7 # dic='{"name":"alex","password":"alex123"}'
     8 # d=eval(dic)
     9 # print(type(d))
    10 
    11 ##从文件取用户信息进行认证
    12 # with open('db.txt',encoding='utf-8') as f:
    13 #     data=f.read()
    14 #     dic=eval(data)
    15 #     print(dic['name'])
    16 
    17 ##保存用户登录状态
    18 current_user={'user':None,'current_status':False}
    19 def auth(func):
    20     def wrapper(*args,**kwargs):
    21         if current_user['user'] and current_user['current_status']:
    22             return func(*args,**kwargs)
    23         name=input('please input your name:').strip()
    24         password=input('please input your password:').strip()
    25 
    26         ##用户的认证来源有多种:文件,数据库等等
    27         with open('db.txt', encoding='utf-8') as f:
    28             user_dic = eval(f.read())
    29         # if name == user_dic['name'] and password == user_dic['password']:
    30         if name in user_dic and password == user_dic[name]:
    31             res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
    32             current_user['user'] = name ##登录成功记录下来
    33             current_user['current_status'] == True
    34             return res ##有无返回值,均可处理
    35         else:
    36             print('user or password is wrong')
    37     return wrapper
    38 @auth #等价于index=timmer(index)  #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
    39 def index():
    40     print('welcome to index')
    41     return 123
    42 # index()
    43 
    44 @auth #等价于home=timmer(home)
    45 def home(name):
    46     print('welcome to home')
    47 #有返回值
    48 res=index()  #即res=wrapper
    49 print(res)
    有认证功能的装饰
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/9/23
     5 ####使用装饰器
     6 import time
     7 from functools import wraps  ##引用Python自带的装饰器
     8 current_user={'user':None,'current_status':False}
     9 def auth(auth_type='file'):
    10     def deco(func):
    11         def wrapper(*args,**kwargs):
    12             if auth_type == 'file':
    13                 if current_user['user']:
    14                     return func(*args,**kwargs)
    15                 name=input('please input your name:').strip()
    16                 password=input('please input your password:').strip()
    17 
    18                 ##用户的认证来源有多种:文件,数据库等等
    19                 with open('db.txt', encoding='utf-8') as f:
    20                     user_dic = eval(f.read())
    21                 # if name == user_dic['name'] and password == user_dic['password']:
    22                 if name in user_dic and password == user_dic[name]:
    23                     res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
    24                     current_user['user'] = name ##登录成功记录下来
    25                     current_user['current_status'] = True
    26                     return res ##有无返回值,均可处理
    27                 else:
    28                     print('user or password is wrong')
    29             elif auth_type == "mysql":
    30                 print('mysql')
    31             elif auth_type == 'ldap':
    32                 print('ldap')
    33             else:
    34                 print('not valid auth_type')
    35         return wrapper
    36     return deco
    37 def timmer(func):
    38     # func=index
    39     @wraps(func)  ##利用Python的自带的装饰器(可以查到注释信息)
    40     def wrapper():
    41         start=time.time()
    42         func()
    43         stop=time.time()
    44         print('run time is %s' %(stop-start))
    45     return wrapper
    46 ##装饰器是有先后顺序的,装饰器装饰的是正下方的函数
    47 ##上面装饰器先生效,下面的后生效;但是先执行下面(函数正上方的装饰器)
    48 @timmer #index=timmer(wrapper)
    49 @auth() # @deco #index=deco(index) #index=wrapper
    50 def index():
    51     '''这是函数'''
    52     time.sleep(3)
    53     print('welcome to index')
    54 # index()
    55 
    56 @timmer #等价于home=timmer(home)
    57 @auth()
    58 def home():
    59     time.sleep(3)
    60     print('welcome to home')
    61 # index()
    62 # home()
    63 print(index.__doc__) ##加上装饰器后默认是返回None ;调用系统自带的装饰器from functools import wraps ,引用@wraps后,可以查看函数的注释信息
    64 # print(help(index))  ##查看函数注释信息
    显示被装饰对象的注释信息
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/9/23
     5 
     6 current_user={'user':None,'current_status':False}
     7 def auth(auth_type='file'): ##给装饰器传参数,最多三层(已经满足所有需求,一般情况下,直接调用别人的有参装饰器)
     8     def deco(func):
     9         def wrapper(*args,**kwargs):
    10             if auth_type == 'file':
    11                 if current_user['user']:
    12                     return func(*args,**kwargs)
    13                 name=input('please input your name:').strip()
    14                 password=input('please input your password:').strip()
    15 
    16                 ##用户的认证来源有多种:文件,数据库等等
    17                 with open('db.txt', encoding='utf-8') as f:
    18                     user_dic = eval(f.read())
    19                 # if name == user_dic['name'] and password == user_dic['password']:
    20                 if name in user_dic and password == user_dic[name]:
    21                     res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
    22                     current_user['user'] = name ##登录成功记录下来
    23                     current_user['current_status'] = True
    24                     return res ##有无返回值,均可处理
    25                 else:
    26                     print('user or password is wrong')
    27             elif auth_type == "mysql":
    28                 print('mysql')
    29             elif auth_type == 'ldap':
    30                 print('ldap')
    31             else:
    32                 print('not valid auth_type')
    33         return wrapper
    34     return deco
    35 @auth(auth_type='mysql')#等价于@deco #index=deco(index)  #index=inner #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
    36 def index():
    37     print('welcome to index')
    38     return 123
    39 # index()
    40 
    41 @auth(auth_type='file') #等价于home=timmer(home)
    42 def home(name):
    43     print('welcome %s to home' %name)
    44 #有返回值
    45 res=index()  #即res=wrapper
    46 print(res)
    47 home('alex')
    有参数的装饰器
    {"alex":"alex123","egon":"egon123","wzs":"wzs123"}
    db.txt

      装饰器最多三层函数,三层几乎满足所有的需求了

      显示装饰器装饰的函数名称

    
    
    import functools
    def wapper(func):
    # 帮助我们设置函数的元信息
    @functools.wraps(func)
    def inner(*args, **kwargs):
    return func(*args, **kwargs)
    return inner

    @wapper
    def f1():
    pass


    @wapper
    def f2():
    pass

    print(f1.__name__)
    print(f2.__name__)
     

      4、练习题

      一:编写函数,(函数执行的时间是随机的)

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 import time
     7 def timmer(func):
     8     def wrapper(*args,**kwargs):
     9         start = time.time()
    10         func(*args,**kwargs)
    11         stop = time.time()
    12         print('execution time is %s' %(start))
    13 
    14     return wrapper
    15 @timmer
    16 def exec():
    17     print('what are you doing?')
    18 exec()
    View Code

      二:编写装饰器,为函数加上统计时间的功能

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 import time
     7 def timmer(func):
     8     def wrapper(*args,**kwargs):
     9         start = time.time()
    10         func(*args,**kwargs)
    11         stop = time.time()
    12         print('execution time is %s' %(start))
    13 
    14     return wrapper
    15 @timmer
    16 def exec():
    17     print('what are you doing?')
    18 exec()
    View Code

      三:编写装饰器,为函数加上认证的功能

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 def auth(func):
     7     def wrapper(*args,**kwargs):
     8         name = input('please your name>>:').strip()
     9         password = input('please your password>>:').strip()
    10         if name == 'wzs' and password == 'wzs123':
    11             func(*args,**kwargs)
    12     return wrapper
    13 @auth
    14 def login(name):
    15     print('%s 欢迎登录' %(name))
    16 login('wzs')
    View Code

      四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
    注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 current_user={'user':None,'current_status':False}
     7 def auth(func):
     8     def wrapper(*args,**kwargs):
     9         if current_user['user'] and current_user['current_status']:
    10             return func(*args,**kwargs)
    11         name=input('please input your name:').strip()
    12         password=input('please input your password:').strip()
    13 
    14         ##用户的认证来源有多种:文件,数据库等等
    15         with open('db.txt', encoding='utf-8') as f:
    16             user_dic = eval(f.read())
    17         # if name == user_dic['name'] and password == user_dic['password']:
    18         if name in user_dic and password == user_dic[name]:
    19             res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
    20             current_user['user'] = name ##登录成功记录下来
    21             current_user['current_status'] == True
    22             return res ##有无返回值,均可处理
    23         else:
    24             print('user or password is wrong')
    25     return wrapper
    26 @auth #等价于index=timmer(index)  #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
    27 def index():
    28     print('welcome to index')
    29     return 123
    30 # index()
    31 
    32 @auth #等价于home=timmer(home)
    33 def home(name):
    34     print('welcome to home')
    35 #有返回值
    36 res=index()  #即res=wrapper
    37 print(res)
    View Code

      五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 import time,random
     7 user={'user':None,'login_time':None,'timeout':0.000005,}
     8 def timmer(func):
     9     def wrapper(*args,**kwargs):
    10         exe_start = time.time()
    11         res = func(*args,**kwargs)
    12         exe_stop = time.time()
    13         print('%s' %(exe_stop - exe_start))
    14         return res
    15     return wrapper
    16 
    17 def auth(func):
    18     def wrapper(*args,**kwargs):
    19         if user['user']:
    20             timeout = time.time() - user['login_time']
    21             if timeout < user['timeout']:
    22                 return func(*args,**kwargs)
    23         name = input('your name>>:').strip()
    24         password = input('your password>>:').strip()
    25         if name == 'wzs' and password == 'wzs123':
    26             user['user'] = name
    27             user['login_time'] = time.time()
    28             res = func(*args,**kwargs)
    29             return res
    30     return wrapper
    31 
    32 @auth
    33 def index():
    34     time.sleep(random.randrange(3))
    35     print('welcome to index')
    36 @auth
    37 def home(name):
    38     time.sleep(random.randrange(3))
    39     print('welcome %s to home' %name)
    40 
    41 index()
    42 home('wzs')
    View Code

      六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 import requests
     7 def index(url):
     8     def wrapper():
     9         return requests.get(url).text
    10     return wrapper
    11 
    12 index_web = index('https://www.python.org')
    13 print(index_web())
    View Code

      七:为题目五编写装饰器,实现缓存网页内容的功能:
    具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中

    扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 import requests,os
     7 cache_file = 'cache.txt'
     8 def make_cache(func):
     9     def wrapper(*args,**kwargs):
    10         if not os.path.exists(cache_file):
    11             with open(cache_file,'w'):pass
    12         if os.path.getsize(cache_file):
    13             with open(cache_file,'r',encoding='utf-8') as f:
    14                 res = f.read()
    15         else:
    16             res = func(*args,**kwargs)
    17             with open(cache_file,'w',encoding='utf-8') as f:
    18                 f.write(res)
    19         return res
    20     return wrapper
    21 @make_cache
    22 def get(url):
    23     return requests.get(url).text
    24 
    25 get('https://www.python.org')
    View Code

      八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 route_dic={}
     7 
     8 def make_route(name):
     9     def deco(func):
    10         route_dic[name]=func
    11     return deco
    12 @make_route('select')
    13 def func1():
    14     print('select')
    15 
    16 @make_route('insert')
    17 def func2():
    18     print('insert')
    19 
    20 @make_route('update')
    21 def func3():
    22     print('update')
    23 
    24 @make_route('delete')
    25 def func4():
    26     print('delete')
    27 
    28 print(route_dic)
    View Code

      九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
    注意:时间格式的获取
    import time
    time.strftime('%Y-%m-%d %X')

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # __author__ = "wzs"
     4 #2017/10/7
     5 
     6 import time,os
     7 def auth(logfile):
     8     def deco(func):
     9         if not os.path.exists(logfile):
    10             with open(logfile,'w',encoding='utf-8') as f:pass
    11         def wrapper(*args,**kwargs):
    12             res = func(*args,**kwargs)
    13             with open(logfile,'a',encoding='utf-8') as f:
    14                 f.write('%s %s run'%(time.strftime('%Y-%m-%d %X'),func.__name__))
    15         return wrapper
    16     return deco
    17 @auth('access.log')
    18 def index():
    19     print('this is my index')
    20 
    21 index()
    View Code

    二、迭代器、生成器、面向过程

      一、 迭代器

      1、迭代的概念

    迭代:迭代是个重复的过程,每次重复都是基于上一次的结果来的(软件版本的迭代)

      2、为何要用迭代器?

    1 l=['a','b','c']
    2 n=0
    3 while n < len(l):
    4     print(len(n))
    5     n += 1
    对于序列类型,如字符串,列表,元组,可以使用基于索引的迭代取值方式
    对于没有索引的类型,如字典、集合、文件,这种方式不再适用,于是我们必须找出一种不依赖于索引的取值方式,这就是迭代器找找

      3、什么是可迭代对象?什么是迭代器对象?

    可迭代对象:只要对象内置有__iter__方法,obj.__iter__ 例如:字符串,列表,元组,字典,集合
    1 'hello'.__iter__()
    2 [1,2].__iter__()
    3 (1,2).__iter__()
    4 {'a':1}.__iter__()
    5 {1,2,3}.__iter__()
    迭代器对象:对象既有内置有__iter__方法,又内置有__next__,如文件对象
    可迭代对象通过.__iter__方法,得到的结果就是迭代器对象
    文件既是可迭代对象,又是迭代器对象 例如:文件
    1 open('a.txt','w').__iter__()
    2 open('a.txt','w').__next__()
     注意:迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象

      4、迭代器对象的应用 

      next(iter_dic)这个方法和iter_dic.__next__()方法一样,推荐用next(iter_dic)这个

    1 dic={'name':'alex','age':29,'sex':'male'}
    2 iter_dic=dic.__iter__()
    3 print(iter_dic.__next__())
    4 print(iter_dic.__next__())
    5 print(iter_dic.__next__()) ##等价于print(next(iter_dic))
    6 # print(iter_dic.__next__())  ##当没有值了,继续取值会报错

      有了迭代器对象取值,所有类型的数据都可以使用(不依赖索引取值)

    1 dic={'name':'alex','age':29,'sex':'male'}
    2 iter_dic=dic.__iter__()
    3 while True:  ###可以使用try ....except....使用手工捕捉异常,避免程序崩溃
    4     try:
    5         k=next(iter_dic)
    6         print(dic[k])
    7     except StopIteration:
    8         break

      使用for循环,for循环会自己处理异常

    #相当于iter_dic=dic.iter__()
    for k in dic:
        print(dic[k])

      for循环的工作原理

    for 循环的工作原理
        1、执行in后对象的dic.__iter__()方法
        2、执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
        3、重复过程2,知道捕捉到异常StopIteration
    

      5、迭代器的优缺点

        优点:
    1、提供一种统一的迭代取值方式,该方式不再依赖于索引
    2、更节省内存
    缺点:
    1、无法统计长度
    2、一次性的,只能往后走,不能往前退,无法获取指定位置的值

      应用场景:
      for循环

      6、判断可迭代对象和迭代器的方法

        1、方法一:判断内部是不是实现了__next__方法
    '__iter__' in dir(str)#如果__iter__在这个方法里面,就是可迭代的
        2、方法二:

        Iterable 判断是不是可迭代对象;Iterator 判断是不是迭代器

    from collections import Iterable  
    from collections import Iterator
    
    #比如给一个字符串
    s='abc'
    print(isinstance(s,Iterable))#isinstance判断类型的
    print(isinstance(s,Iterator))

      判断range函数和map函数

    map1=map(abs,[1,-2,3,-4])
    print(isinstance(map1,Iterable))
    print(isinstance(map1,Iterator))#map方法自带迭代器
    
    s=range(100)#是一个可迭代的,但是不是迭代器
    print(isinstance(s,Iterable))
    print(isinstance(s,Iterator))

      二、生成器

      1、生成器的定义

    定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行该函数体代码,会得到一个结果,该结果就是生成器对象
    本质:生成器本质就是迭代器
     1 def fun():
     2     print('first')
     3     yield 1,2,3
     4     print('second')
     5     yield 2
     6     print('third')
     7     yield 3
     8 
     9 g=fun()
    10 # print(next(g))
    11 for i in g:
    12     print(i)
    范例:yield

      2、yield的功能

        1、提供了一种自定义迭代器的方式
        2、对比return,可以返回多次值,挂起函数的运行状态
    

      自定义功能,可以生成无穷多个值,因为同一时间在内部中只有一个值(节约资源)

    1 def my_range(start,stop,step=1):
    2     while start < stop:
    3         yield start
    4         start += step
    5 
    6 for i in my_range(1,1000000,2):
    7     print(i)
    使用迭代器,实现range功能
        1、send功能:

      1、初始化(None),和next效果一样;2、传值

    def init(func):
        def wrapper(*args, **kwargs):
            g = func(*args, **kwargs)
            next(g)
            return g
        return wrapper
    
    @init
    def eat(name):
    
        food_list = []
        print('%s 开动啦' %name)
        while 1:
            food = yield food_list
            food_list.append(food)
            print('%s 开始吃 %s' %(name, food))
    
    g = eat('wzs')
    # g.send(None)
    g.send('糖醋里脊')
    解决多次初始化问题——装饰器
        2、yield的表达式形式应用
     1 def eater(name):
     2     food_list=[]
     3     print('%s 开动啦' %name)
     4     while True:
     5         food = yield food_list ##将返回值保存在一个列表中
     6         food_list.append(food)
     7         print('%s 开始吃 %s' %(name,food))
     8 
     9 g=eater('alex')
    10 g.send(None) ##相当于next(g)
    11 g.send('骨头')  ##next()功能和传值的功能
    12 g.send('包子')  ##可以多次传值
    13 print(g.send("饺子"))  ###打印返回值
    send应用
     1 def f1():
     2     while True:
     3         x=yield
     4         print(x)
     5 g=f1()
     6 next(g) #初始化
     7 g.send(12)
     8 g.send(12)
     9 g.send(12)
    10 # g.close()  ##只能传值到这个位置,在执行下面的传值,就报错
    11 g.send(12)
    12 g.send(12)
    无限传值
     1 def eater(name):
     2     print('%s 说:我开动啦' %name)
     3     food_list = []
     4     while True:
     5         food = yield food_list
     6         food_list.append(food)
     7         print('%s eat %s' %(name,food))
     8 
     9 def producer():
    10     alex_g = eater('alex')
    11     #第一阶段:初始化
    12     next(alex_g)
    13     #第二阶段:
    14     while True:
    15         food = input('>>:').strip()
    16         if not food:continue
    17         print(alex_g.send(food))
    18 producer()
    多个函数来回切换(传值),下次传值在上次暂停的地点继续

      3、yield from

    def func():
        # for i in 'AB':
        #     yield i
        yield from 'AB' #AB就相当于上面的for循环,把循环简化了
        # yield from [1,2,3]
    
    g = func()
    # print(g)  #生成器
    print(list(g))

      4、实现:tail -f access.log | grep '404'

    tail -f access.log | grep '404'
    1 #!/usr/bin/env python
    2 # -*- coding:utf-8 -*-
    3 # __author__ = "wzs"
    4 #2017/9/28
    5 with open('access.log','a') as f:
    6     f.write('pythonxxx19xxxxJHHH404GG
    ')
    向access.log追加内容

      三、面向过程编程

    面向过程绝对不是函数编程那么简单,对象过程是一种变成思路、思想,而变成思路是不依赖于具体语言的或语法的
    核心是过程二字,过程即解决问题的步骤,基于面向过程去设计程序就像在设计一条工业流水线,是一种机械式的思维方式
    r是后面的特殊符号转换字符串

      1、定义

    面向过程的核心是过程,过程指的是解决问题的步骤:即先干什么再干什么。

      2、优缺点

    优点:复杂的问题流程化,进行简单化

    缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身

      3、应用

    扩展性要求不高的场景,典型案例例如:Linux内核,git,httpd(程序实现的流程图)

      4、范例:实现grep -rl 'root' /etc的效果,从/etc开始递归抓取文件中含有root的文件,并打印文件绝对路径,命令效果如下

    [root@iZ94ao17ezcZ ~]# grep -rl 'root' /etc
    /etc/passwd
    /etc/rc4.d/K30postfix
    /etc/rc4.d/K87restorecond
    /etc/rc4.d/K85mdmonitor
    /etc/rc4.d/S64mysql
    /etc/rc4.d/K92ip6tables
     1 import os
     2 def init(func):
     3     def inner(*args,**kwargs):
     4         g=func(*args,**kwargs)
     5         next(g)
     6         return g
     7     return inner
     8 #第一阶段:找到所有文件的绝对路径
     9 def search(filepath,target): #找到一个文件路径就往下个阶段传一次
    10     g = os.walk(filepath)    #得到文件路径的生成器
    11     for dirname, _, files in g:  #拼接出想要文件的绝对路径
    12         for file in files:
    13             abs_file_path = r'%s\%s' % (dirname, file)
    14             target.send(abs_file_path)
    15 
    16 #第二阶段:打开文件
    17 @init
    18 def opener(target):
    19     while True:
    20         abs_file_path=yield
    21         with open(abs_file_path,'rb') as f:
    22             target.send((f,abs_file_path))
    23 #第三阶段:循环读出每一行内容
    24 @init
    25 def cat(target):
    26     while True:
    27         f,abs_file_path=yield
    28         for line in f:
    29             res=target.send((line,abs_file_path))
    30             if res:
    31                 break
    32 #第四阶段:过滤
    33 @init
    34 def grep(pattern,target):
    35     tag=False
    36     pattern = pattern.encode('utf-8')
    37     while True:
    38         line,abs_file_path=yield tag
    39         tag=False
    40         if pattern in line:
    41             target.send(abs_file_path)
    42             tag=True
    43 #第五阶段:打印该行属于的文件名
    44 @init
    45 def printer():
    46     while True:
    47         abs_file_path=yield
    48         print(abs_file_path)
    49 search(r'G:dataPyCharm_Projects19day4a',opener(cat(grep('你好',printer()))))
    实现方法

    三、三元表达式、列表解析、生成器表达式

      一、三元表达式

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    # __author__ = "wzs"
    #2017/9/24
    
    # name=input('>>:')
    # if name == 'bingbing':
    #     print('I love you!')
    # else:
    #     print('Goodbye!')
    
    name=input('>>:')
    #满足条件的返回结果放在最左边,不满足则放在最右边
    print('I love you' if name == 'wzs' else 'Goodbye')

      二、列表解析(列表推倒式)

       1、范例:当产egg的数量大于3时,将超过3的部分放入仓库中

    1 egg_list=[]
    2 for i in range(10):
    3     if i > 3:
    4         res='egg %s' %i
    5         egg_list.append(res)
    6 
    7 print(egg_list)
    常规写法
    1 l=['egg%s' %i for i in range(10) if i > 3]
    2 print(l)
    列表推倒式

      2、语法

    1 [expression for item1 in iterable1 if condition1
    2 for item2 in iterable2 if condition2
    3 ...
    4 for itemN in iterableN if conditionN
    5 ]

      相当于

    1 res=[]
    2 for item1 in iterable1:
    3     if condition1:
    4         for item2 in iterable2:
    5             if condition2
    6                 ...
    7                 for itemN in iterableN:
    8                     if conditionN:
    9                         res.append(expression)

      3、优点:方便,改变了编程习惯,可称之为声明式编程

      三、生成器表达式

      1、语法

      将列表推导式的[ ]换成( ),就是生成器表达式

      2、范例:

    g=('egg %s' %i for i in range(10) if i > 3)
    # print(g) #生成器
    print(next(g)) #取值
    print(list(g)) #生成器是迭代器对象 因而可以转成列表  输出列表中的元素
    for i in g:
    print(i)

      3、优点:省内存,一次在内存中只产生一个值

      四、声明式编程练习题

      1、将names=['egon','alex_sb','wupeiqi','yuanhao']中的名字全部变成大写

    1 names=['egon','alex_sb','wupeiqi','yuanhao']
    2 names=[name.upper() for name in names]
    3 print(names)
    列表推导式

      2、将names=['egon','alex_sb','wupeiqi','yuanhao']中以sb结尾的名字过滤掉,然后保存剩下的名字长度

    1 names=['egon','alex_sb','wupeiqi','yuanhao']
    2 names=[len(name) for name in names if not name.endswith('sb')]
    3 print(names)
    列表推导式

      3、求文件test中最长的行的长度(长度按字符个数算,需要使用max函数)

      读取文件的每一行内容,然后计算出每行字符的数量,最后使用max函数取出最长一行字符的数量

    1 with open('test',encoding='utf-8') as f:
    2     print(max(len(line) for line in f))
    生成器表达式

      4、求文件test中总共包含的字符个数?思考为何在第一次之后的n次sum求和得到的结果为0?(需要使用sum函数)

      每次必须重新打开文件或seek到文件开头,因为迭代完一次就结束了

    1 with open('test',encoding='utf-8') as f:
    2     print(sum(len(line) for line in f)) #第一次计算出所有行总的字符串
    3     print(sum(len(line) for line in f)) #得出的结果是0:因为第一次已将生成器的值取完,再去取,所有结果为0
    4     print(sum(len(line) for line in f))
    生成器表达式

      5、思考题

    1 with open('a.txt') as f:
    2     g=(len(line) for line in f)
    3 print(sum(g)) #为何报错? 
    ####正确的方式
    1
    with open('test') as f: 2 # g=(sum(len(line) for line in f)) 3 g=(len(line) for line in f) 4 print(sum(g))

      6、文件shopping.txt内容如下

    求总共花了多少钱?
    打印出所有商品的信息,格式为[{'name':'xxx','price':333,'count':3},...]
    求单价大于10000的商品信息,格式同上
    

     a.txt文件内容如下

    mouse 100.00 2
    computer 4999.00 1
    keyboard 300.00 1
    mobile 3000.00 2
    Mac 12000 1

      1问:sum

    1 with open('a.txt',encoding='utf-8') as f:
    2     info=[line.split() for line in f]
    3     cost=sum(float(unit_price)*int(count) for _,unit_price,count in info)
    4     print(cost)
    1问 总花费

      2问:打印出所有商品的信息

    1 with open('a.txt',encoding='utf-8') as f:
    2     info=[{
    3         'name':line.split()[0],
    4         'price':line.split()[1],
    5         'count':line.split()[2],
    6     } for line in f]
    7     print(info)
    列表推导式

      3问:打印单价大于10000的商品信息

    1 with open('a.txt',encoding='utf-8') as f:
    2     info=[{
    3         'name':line.split()[0],
    4         'price':line.split()[1],
    5         'count':line.split()[2],
    6     } for line in f if float(line.split()[1]) > 10000]
    7     print(info)
    列表推导式
  • 相关阅读:
    TMainMenu 类[三] 手动建立菜单(5) : 给菜单项添加事件
    TMainMenu 类[二] 成员列表
    TMainMenu 类[三] 手动建立菜单(4) : 添加分割线与隐藏多余的分割线
    初学 Delphi 嵌入汇编[30] 寄存器表
    TMainMenu 类[三] 手动建立菜单(6) : 更换菜单
    TMainMenu 类[三] 手动建立菜单(7) : 指定快捷键
    关于网络编程(服务端)的一些笔记 roen的专栏 博客频道 CSDN.NET
    关于 多进程epoll 与 “惊群”问题
    乱谈服务器编程 MrDB 博客园
    再谈select, iocp, epoll,kqueue及各种I/O复用机制 Shallway 博客频道 CSDN.NET
  • 原文地址:https://www.cnblogs.com/happy-king/p/7589328.html
Copyright © 2020-2023  润新知