闭包、装饰器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、实例
x = 1
def f1():
    x=111111111111
    def f2():  #f2是闭关函数
        print(x)
    return f2  ##获取返回值
func=f1()
# func()

def  foo():
    x=1988193190112131
    func()
foo()
  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'))

优化

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()

被装饰对象有参数,参数类型和数量不固定

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/9/23
##有参和无参函数都能使用装饰器(*args,**kwargs)
import time
def timmer(func):
    # func=index
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
        stop=time.time()
        print('run time is %s' %(stop-start))
        return res ##有无返回值,均可处理
    return wrapper
@timmer #等价于index=timmer(index)  #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
def index():
    time.sleep(3)
    print('welcome to index')
    return 123
# index()

@timmer #等价于home=timmer(home)
def home(name):
    time.sleep(3)
    print('welcome to home')
#有返回值
res=index()  #即res=wrapper
print(res)
home('wzs')  #即wrapper('wzs')

有认证功能的装饰

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/9/23
##eval 将字符串里面的命令提取出来,执行一下
#字符串转成字典
# dic='{"name":"alex","password":"alex123"}'
# d=eval(dic)
# print(type(d))

##从文件取用户信息进行认证
# with open('db.txt',encoding='utf-8') as f:
#     data=f.read()
#     dic=eval(data)
#     print(dic['name'])

##保存用户登录状态
current_user={'user':None,'current_status':False}
def auth(func):
    def wrapper(*args,**kwargs):
        if current_user['user'] and current_user['current_status']:
            return func(*args,**kwargs)
        name=input('please input your name:').strip()
        password=input('please input your password:').strip()

        ##用户的认证来源有多种:文件,数据库等等
        with open('db.txt', encoding='utf-8') as f:
            user_dic = eval(f.read())
        # if name == user_dic['name'] and password == user_dic['password']:
        if name in user_dic and password == user_dic[name]:
            res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
            current_user['user'] = name ##登录成功记录下来
            current_user['current_status'] == True
            return res ##有无返回值,均可处理
        else:
            print('user or password is wrong')
    return wrapper
@auth #等价于index=timmer(index)  #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
def index():
    print('welcome to index')
    return 123
# index()

@auth #等价于home=timmer(home)
def home(name):
    print('welcome to home')
#有返回值
res=index()  #即res=wrapper
print(res)

显示被装饰对象的注释信息

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/9/23
####使用装饰器
import time
from functools import wraps  ##引用Python自带的装饰器
current_user={'user':None,'current_status':False}
def auth(auth_type='file'):
    def deco(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                if current_user['user']:
                    return func(*args,**kwargs)
                name=input('please input your name:').strip()
                password=input('please input your password:').strip()

                ##用户的认证来源有多种:文件,数据库等等
                with open('db.txt', encoding='utf-8') as f:
                    user_dic = eval(f.read())
                # if name == user_dic['name'] and password == user_dic['password']:
                if name in user_dic and password == user_dic[name]:
                    res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
                    current_user['user'] = name ##登录成功记录下来
                    current_user['current_status'] = True
                    return res ##有无返回值,均可处理
                else:
                    print('user or password is wrong')
            elif auth_type == "mysql":
                print('mysql')
            elif auth_type == 'ldap':
                print('ldap')
            else:
                print('not valid auth_type')
        return wrapper
    return deco
def timmer(func):
    # func=index
    @wraps(func)  ##利用Python的自带的装饰器(可以查到注释信息)
    def wrapper():
        start=time.time()
        func()
        stop=time.time()
        print('run time is %s' %(stop-start))
    return wrapper
##装饰器是有先后顺序的,装饰器装饰的是正下方的函数
##上面装饰器先生效,下面的后生效;但是先执行下面(函数正上方的装饰器)
@timmer #index=timmer(wrapper)
@auth() # @deco #index=deco(index) #index=wrapper
def index():
    '''这是函数'''
    time.sleep(3)
    print('welcome to index')
# index()

@timmer #等价于home=timmer(home)
@auth()
def home():
    time.sleep(3)
    print('welcome to home')
# index()
# home()
print(index.__doc__) ##加上装饰器后默认是返回None ;调用系统自带的装饰器from functools import wraps ,引用@wraps后,可以查看函数的注释信息
# print(help(index))  ##查看函数注释信息

有参数的装饰器

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/9/23

current_user={'user':None,'current_status':False}
def auth(auth_type='file'): ##给装饰器传参数,最多三层(已经满足所有需求,一般情况下,直接调用别人的有参装饰器)
    def deco(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                if current_user['user']:
                    return func(*args,**kwargs)
                name=input('please input your name:').strip()
                password=input('please input your password:').strip()

                ##用户的认证来源有多种:文件,数据库等等
                with open('db.txt', encoding='utf-8') as f:
                    user_dic = eval(f.read())
                # if name == user_dic['name'] and password == user_dic['password']:
                if name in user_dic and password == user_dic[name]:
                    res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
                    current_user['user'] = name ##登录成功记录下来
                    current_user['current_status'] = True
                    return res ##有无返回值,均可处理
                else:
                    print('user or password is wrong')
            elif auth_type == "mysql":
                print('mysql')
            elif auth_type == 'ldap':
                print('ldap')
            else:
                print('not valid auth_type')
        return wrapper
    return deco
@auth(auth_type='mysql')#等价于@deco #index=deco(index)  #index=inner #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
def index():
    print('welcome to index')
    return 123
# index()

@auth(auth_type='file') #等价于home=timmer(home)
def home(name):
    print('welcome %s to home' %name)
#有返回值
res=index()  #即res=wrapper
print(res)
home('alex')

db.txt

{"alex":"alex123","egon":"egon123","wzs":"wzs123"}

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

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

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、类装饰器
def add_attribute(name):
    # 增加类的属性
    def wrapper(cls):
        cls.NAME = name
        return cls
    return wrapper

@add_attribute("Tom")
class Person:
    age = 18


print(Person.NAME, Person.age)

  5、练习题

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        func(*args,**kwargs)
        stop = time.time()
        print('execution time is %s' %(start))

    return wrapper
@timmer
def exec():
    print('what are you doing?')
exec()

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        func(*args,**kwargs)
        stop = time.time()
        print('execution time is %s' %(start))

    return wrapper
@timmer
def exec():
    print('what are you doing?')
exec()

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

def auth(func):
    def wrapper(*args,**kwargs):
        name = input('please your name>>:').strip()
        password = input('please your password>>:').strip()
        if name == 'wzs' and password == 'wzs123':
            func(*args,**kwargs)
    return wrapper
@auth
def login(name):
    print('%s 欢迎登录' %(name))
login('wzs')

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

current_user={'user':None,'current_status':False}
def auth(func):
    def wrapper(*args,**kwargs):
        if current_user['user'] and current_user['current_status']:
            return func(*args,**kwargs)
        name=input('please input your name:').strip()
        password=input('please input your password:').strip()

        ##用户的认证来源有多种:文件,数据库等等
        with open('db.txt', encoding='utf-8') as f:
            user_dic = eval(f.read())
        # if name == user_dic['name'] and password == user_dic['password']:
        if name in user_dic and password == user_dic[name]:
            res=func(*args,**kwargs) #有无返回值,均可处理:有返回值,是相应的返回值,没有返回值是None
            current_user['user'] = name ##登录成功记录下来
            current_user['current_status'] == True
            return res ##有无返回值,均可处理
        else:
            print('user or password is wrong')
    return wrapper
@auth #等价于index=timmer(index)  #@装饰器名,会将下面函数名作为参数传给装饰器,然后重新赋值给函数名
def index():
    print('welcome to index')
    return 123
# index()

@auth #等价于home=timmer(home)
def home(name):
    print('welcome to home')
#有返回值
res=index()  #即res=wrapper
print(res)

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

import time,random
user={'user':None,'login_time':None,'timeout':0.000005,}
def timmer(func):
    def wrapper(*args,**kwargs):
        exe_start = time.time()
        res = func(*args,**kwargs)
        exe_stop = time.time()
        print('%s' %(exe_stop - exe_start))
        return res
    return wrapper

def auth(func):
    def wrapper(*args,**kwargs):
        if user['user']:
            timeout = time.time() - user['login_time']
            if timeout < user['timeout']:
                return func(*args,**kwargs)
        name = input('your name>>:').strip()
        password = input('your password>>:').strip()
        if name == 'wzs' and password == 'wzs123':
            user['user'] = name
            user['login_time'] = time.time()
            res = func(*args,**kwargs)
            return res
    return wrapper

@auth
def index():
    time.sleep(random.randrange(3))
    print('welcome to index')
@auth
def home(name):
    time.sleep(random.randrange(3))
    print('welcome %s to home' %name)

index()
home('wzs')

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

import requests
def index(url):
    def wrapper():
        return requests.get(url).text
    return wrapper

index_web = index('https://www.python.org')
print(index_web())

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

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

import requests,os
cache_file = 'cache.txt'
def make_cache(func):
    def wrapper(*args,**kwargs):
        if not os.path.exists(cache_file):
            with open(cache_file,'w'):pass
        if os.path.getsize(cache_file):
            with open(cache_file,'r',encoding='utf-8') as f:
                res = f.read()
        else:
            res = func(*args,**kwargs)
            with open(cache_file,'w',encoding='utf-8') as f:
                f.write(res)
        return res
    return wrapper
@make_cache
def get(url):
    return requests.get(url).text

get('https://www.python.org')

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

route_dic={}

def make_route(name):
    def deco(func):
        route_dic[name]=func
    return deco
@make_route('select')
def func1():
    print('select')

@make_route('insert')
def func2():
    print('insert')

@make_route('update')
def func3():
    print('update')

@make_route('delete')
def func4():
    print('delete')

print(route_dic)

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/10/7

import time,os
def auth(logfile):
    def deco(func):
        if not os.path.exists(logfile):
            with open(logfile,'w',encoding='utf-8') as f:pass
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            with open(logfile,'a',encoding='utf-8') as f:
                f.write('%s %s run'%(time.strftime('%Y-%m-%d %X'),func.__name__))
        return wrapper
    return deco
@auth('access.log')
def index():
    print('this is my index')

index()

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

  一) 迭代器

  迭代是Python最强大的功能之一,是访问集合元素的一种方式

  迭代器是一个可以记住遍历的位置的对象。

  迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

  迭代器有两个基本的方法:iter() 或__iter__() 和 next()或__next__()

  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

  StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)

  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))

  二)生成器

  使用了 yield 的函数被称为生成器(generator)

  生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

  1、生成器的定义
定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行该函数体代码,会得到一个结果,该结果就是生成器对象
本质:生成器本质就是迭代器
def fun():
    print('first')
    yield 1,2,3
    print('second')
    yield 2
    print('third')
    yield 3

g=fun()
# print(next(g))
for i in g:
    print(i)

范例:yield

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

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

使用迭代器,实现range功能

def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start += step

for i in my_range(1,1000000,2):
    print(i)
    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的表达式形式应用

send应用

def eater(name):
    food_list=[]
    print('%s 开动啦' %name)
    while True:
        food = yield food_list ##将返回值保存在一个列表中
        food_list.append(food)
        print('%s 开始吃 %s' %(name,food))

g=eater('alex')
g.send(None) ##相当于next(g)
g.send('骨头')  ##next()功能和传值的功能
g.send('包子')  ##可以多次传值
print(g.send("饺子"))  ###打印返回值

无限传值

def f1():
    while True:
        x=yield
        print(x)
g=f1()
next(g) #初始化
g.send(12)
g.send(12)
g.send(12)
# g.close()  ##只能传值到这个位置,在执行下面的传值,就报错
g.send(12)
g.send(12)

多个函数来回切换(传值),下次传值在上次暂停的地点继续

def eater(name):
    print('%s 说:我开动啦' %name)
    food_list = []
    while True:
        food = yield food_list
        food_list.append(food)
        print('%s eat %s' %(name,food))

def producer():
    alex_g = eater('alex')
    #第一阶段:初始化
    next(alex_g)
    #第二阶段:
    while True:
        food = input('>>:').strip()
        if not food:continue
        print(alex_g.send(food))
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、实现:向access.log追加内容
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "wzs"
#2017/9/28
with open('access.log','a') as f:
    f.write('pythonxxx19xxxxJHHH404GG\n')

  三)面向过程编程

面向过程绝对不是函数编程那么简单,对象过程是一种变成思路、思想,而变成思路是不依赖于具体语言的或语法的。
核心是过程二字,过程即解决问题的步骤,基于面向过程去设计程序就像在设计一条工业流水线,是一种机械式的思维方式
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:\data\PyCharm_Project\s19\day4\a',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)

  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)

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值