3.29 python函数2(生成器&列表表达式&生成器表达式&匿名函数&闭包&装饰器) 学习笔记

正文:

1 生成器

1)生成器:

  • 生成器定义

    • 生成器与迭代器可以看成是一种。生成器的本质就是迭代器
    • 唯一区别:生成器是我们自己用python代码构建的数据结构。迭代器都是提供的,或者转化得来的。
  • 获取生成器的三种方式:

    • 生成器函数
    • 生成器表达式
    • python内部提供的一些生成器
  • 生成器函数获取生成器:

    # 函数
    def func1():
        print(111)
        print(222)
        return 3
    ret = func1()
    print(ret)
    #
    # 生成器函数
    def func2():
        print(111)
        print(222)
        yield 3
        a = 1
        b = 2
        c = a + b
        print(c)
        yield 4
    ret = func2()
    # print(ret)
    print(next(ret))
    print(next(ret))
    print(next(ret))
    # 一个next 对应一个yield
    
    '''
    return and yield
    '''
    # return ;函数中只存在一个return结束函数,并且给函数的执行者返回值。
    # yield:只要函数中有yield那么它就是生成器函数而不是函数了。
    # 生成器函数中可以存在多个yield,yield不会结束生成器函数,一个yield对应一个next。
    
    # 吃包子问题解析生成器
    def func11():
        l1 = []
        for i in range(1,5001):
            l1.append(f'{i}号包子')
        return l1
    ret = func11()
    print(ret)
    
    def gen_func22():
        for i in range(1,5001):
            yield f'{i}号包子'
    ret = gen_func()
    for i in range(200):
        print(next(ret))
    
    for i in range(200):
        print(next(ret))
    
    '''
    yield from
    '''
    def func111():
        l1 = [1, 2, 3, 4, 5]
        yield l1
    ret = func111()
    print(next(ret))
    
    def func222():
        l1 = [1, 2, 3, 4, 5]
        yield from l1
        '''
        yield 1
        yield 2
        yield 3
        yield 4
        yield 5
        '''
    #     将l1这个列表变成了迭代器返回。
    ret = func222()
    print(next(ret))
    print(next(ret))
    print(next(ret))
    print(next(ret))
    print(next(ret))
    
    # 多个yield
    def func():
        lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配']
        lst2 = ['馒头', '花卷', '豆包', '大饼']
        yield from lst1
        yield from lst2
    g = func()
    for i in range(8):
        print(next(g))
    

2 生成器表达式、列表推导式

1)列表推导式

  • 基本结构
l1 = [i for i in range(1,11)]
l2 = [i if i>5 else 0 for i in range(10)]
  • 列表推导式优缺点:
    • 缺点
      • 列表推导式只能构建比较复杂并且有规律的列表。
      • 超过三层循环才能构建成功的,就不建议用列表推导式。
      • 查找错误(debug模式)不行。
    • 优点
      • 一行构建,简单。

2)生成器表达式

  • 与列表推导式写法几乎相同:(i for i in range(10))

  • 列表推导式和生成器表达式区别:

    • 写法:[] ()
    • iterable可迭代对象 和 iterator 迭代器的区别
  • 字典推导式:

    lst1 = ['jay', 'jj', 'meet']
    lst2 = ['周杰伦','林俊杰','元宝']
    dic = { lst2[i]: lst1[i] for i in range(len(lst1))}
    print(dic)
    
  • 集合推导式:

    print({i for i in range(1,11)})
    

3 内置函数

python提供了68个内置函数

1)比较重要

all() # 可迭代对象中,全都是True才是True

any() # 可迭代对象中,一个是True就是True

bytes() # 将数转换为二进制数

callable() # 判断该对象是否可调用(如字符串不可被调用,函数可被调用,func())

complex(实, 虚) # 复数,实+虚j

eval() # i)将字符串表达式作为代码执行。ii)将数据字符串转换为数据原本的数据类型。iii)一次input赋值给多个变量 a, b = eval(input())

exec() # 与eval()基本相同,可以对代码块字符串进行相关操作

format()

frozenset() # 不可变集合(不能添加和删除)

globals() # 所有全局变量

hash() # 获取哈希值

help() # 查看帮助

id() # 获取内存地址

input()

int()

iter() # 生成迭代器

locals() # 获取全部局部变量(字典)

next() # 返回迭代器的下一个项目

bin() # 将十进制转换位二进制并返回

oct() # 将十进制转换位八进制并返回

hex() # 将十进制转换为十六进制并返回

ord() # 输入字符找字符编码位置

chr() # 输入位置数字找对应字符

pow(x, y) # 求x**y次幂,三个参数时为x**y % 第三个参数

divmod(除数, 被除数) # divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。

round(小数, 位数) # 保留浮点数的小数位数

repr() # 返回一个对象的 string 格式。

2)非常重要

abs() # 绝对值

enumerate() # enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

filter() # 列表推导式的筛选模式,列表推导式返回列表,filter()返回迭代器

"""
filter(function or None, iterable) --> filter object

Return an iterator yielding those items of iterable for which function(item)
is true. If function is None, return the items that are true.
"""
l1 = [2, 3, 4, 1, 6, 7, 8]
print([i for i in l1 if i > 3])  # 返回的是列表
ret = filter(lambda x: x > 3,l1)  # 返回的是迭代器

map() # 列表推导式的循环模式,列表推导式返回列表,map()返回迭代器

"""
map(func, *iterables) --> map object

Make an iterator that computes the function using arguments from
each of the iterables.  Stops when the shortest iterable is exhausted.
"""
l1 = [1, 4, 9, 16, 25]
print([i**2 for i in range(1,6)])  # 返回的是列表
ret = map(lambda x: x**2,range(1,6))  # 返回的是迭代器

max() # max(*args, key=None),key是函数名,表示对可迭代对象进行key函数操作后进行max操作

min() # 比较键值对时默认按照键比较,可加key函数名

open()

range()

print() # print(self, *args, sep=’ ‘, end=’\n’, file=None)

len()

list()

dict()

str()

float()

reversed() # 对列表进行翻转获取一个迭代器,list.reverse()方法对原列表进行翻转

set()

sorted() # 对列表进行排序并生成新列表,list.sort()方法对原列表进行排序,也有key参数,还有reverse参数设置反转排序

sum()

tuple()

type()

zip() # 用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

dir() # 不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。

reduce() # 已经不是一个内置函数,转化为python3中是一个模块的方法

from functools import reduce
def func(x,y):
    '''
    第一次:x  y  : 11  2     x + y =     记录: 13
    第二次:x = 13   y  = 3    x +  y =   记录: 16
    第三次  x = 16   y = 4 .......
    '''
    return x + y

l = reduce(func,[11,2,3,4])
print(l)

3)挺重要

classmethod() # 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。

delattr() # 删除属性。delattr(x, ‘foobar’) 相等于 del x.foobar。

getattr() # 用于返回一个对象属性值。

hasattr() # 用于判断对象是否包含对应的属性。

issubclass()

isinstance() # isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。type() 不会认为子类是一种父类类型,不考虑继承关系。isinstance() 会认为子类是一种父类类型,考虑继承关系。

object()

property() # 在新式类中返回属性值。

setattr()

staticmethod() # 返回函数的静态方法。可以实现实例化使用 C().f(),当然也可以不实例化调用该方法 C.f()

super()

4 匿名函数

一句话函数,比较简单的函数。lambda funcname: function

5 闭包

1)定义

内层函数对外层函数非全局变量的引用,就会形成闭包。

'''
eg:例如:整个历史中的某个商品的平均收盘价。什么叫平局收盘价呢?就是从这个商品一出现开始,每天记录当天价格,
        然后计算他的平均值:平均值要考虑直至目前为止所有的价格。

比如大众推出了一款新车:小白轿车。

第一天价格为:100000元,平均收盘价:100000元

第二天价格为:110000元,平均收盘价:(100000 + 110000)/2 元

第三天价格为:120000元,平均收盘价:(100000 + 110000 + 120000)/3 元

'''
# 方案一:
# l1 = []  # 全局变量 数据不安全
# def make_averager(new_value):
#     l1.append(new_value)
#     total = sum(l1)
#     averager = total/len(l1)
#     return averager
# print(make_averager(100000))

# 方案二: 数据安全,l1不能是全局变量。
# 每次执行的时候,l1列表都会重新赋值成[]
# li = []
# def make_averager(new_value):
#     l1 = []
#     l1.append(new_value)
#     total = sum(l1)
#     averager = total/len(l1)
#     return averager
# print(make_averager(100000))
# print(make_averager(110000))

# 方案三: 闭包

def make_averager():
    l1 = []
    def averager(new_value):
        l1.append(new_value)
        print(l1)
        total = sum(l1)
        return total/len(l1)
    return averager
avg = make_averager()  # averager
print(avg(100000))
print(avg(110000))

2)特点

  • 被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系,自由变量不会在内存中消失
  • 闭包现象只能存在与嵌套函数中。

3)作用

保证数据的安全。

4)判断

# 如何判断一个嵌套函数是不是闭包
# 1,闭包只能存在嵌套函数中。
# 2, 内层函数对外层函数非全局变量的引用(使用),就会形成闭包。
# 例一:
# def wrapper():
#     a = 1
#     def inner():
#         print(a)
#     return inner
# ret = wrapper()
# 闭包
# 
# # 例二:不是闭包
# a = 2
# def wrapper():
#     def inner():
#         print(a)
#     return inner
# ret = wrapper()

# # 例三:
#   也是闭包!
# def wrapper(a,b):
#     def inner():
#         print(a)
#         print(b)
#     return inner
# a = 2
# b = 3
# ret = wrapper(a,b)

# 如何代码判断闭包?
# print(ret.__code__.co_freevars)  # ('a', 'b')

6 装饰器

1)开放封闭原则

  • 开放:对代码的拓展是开放的。
  • 封闭:对源码的修改是封闭的。

2)装饰器定义

  • 完全遵循开放封闭原则。

  • 在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。

  • # 装饰器:装饰,装修,房子就可以住,如果装修,不影响你住,而且体验更加,让你生活中增加了很多功能:洗澡,看电视,沙发。
    # 器:工具。
    # 开放封闭原则:
    # 开放:对代码的拓展开放的, 更新地图,加新枪,等等。
    # 封闭:对源码的修改是封闭的。闪躲用q。就是一个功能,一个函数。 别人赤手空拳打你,用机枪扫你,扔雷.....这个功能不会改变。
    
    # 装饰器:完全遵循开放封闭原则。
    # 装饰器: 在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。
    # 装饰器就是一个函数。
    
    
    # 版本一: 大壮 写一些代码测试一下index函数的执行效率。
    import time
    # def index():
    #     '''有很多代码.....'''
    #     time.sleep(2) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录博客园首页')
    #
    # def dariy():
    #     '''有很多代码.....'''
    #     time.sleep(3) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录日记页面')
    
    # print(time.time())  # 格林威治时间。
    # print(111)
    # time.sleep(3)
    # print(222)
    # 版本一有问题: 如果测试别人的代码,必须重新赋值粘贴。
    # start_time = time.time()
    # index()
    # end_time = time.time()
    # print(end_time-start_time)
    #
    # start_time = time.time()
    # dariy()
    # end_time = time.time()
    # print(end_time-start_time)
    #
    
    # 版本二:利用函数,解决代码重复使用的问题
    # import time
    # def index():
    #     '''有很多代码.....'''
    #     time.sleep(2) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录博客园首页')
    # # index()
    # def dariy():
    #     '''有很多代码.....'''
    #     time.sleep(3) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录日记页面')
    #
    # def timmer(f):  # f= index
    #     start_time = time.time()
    #     f()  # index()
    #     end_time = time.time()
    #     print(f'测试本函数的执行效率{end_time-start_time}')
    # timmer(index)
    
    # 版本二还是有问题: 原来index函数源码没有变化,给原函数添加了一个新的功能测试原函数的执行效率的功能。
    # 满足开放封闭原则么?原函数的调用方式改变了。
    
    
    # 版本三:不能改变原函数的调用方式。
    # import time
    # def index():
    #     '''有很多代码.....'''
    #     time.sleep(2) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录博客园首页')
    #
    # def timmer(f):  # f = index  (funciton index123)
    #     def inner():  # inner :(funciton inner123)
    #         start_time = time.time()
    #         f()  # index() (funciton index123)
    #         end_time = time.time()
    #         print(f'测试本函数的执行效率{end_time-start_time}')
    #     return inner  # (funciton inner123)
    # timmer(index)  # index()
    # ret = timmer(index)  # inner
    # ret()  # inner()
    # index = timmer(index)  # inner (funciton inner123)
    # index()  # inner()
    # def func():
    #     print('in func')
    #
    # def func1():
    #     print('in func1')
    #
    # # func()
    # # func1()
    # func()
    # func = 666
    # func(0)
    
    # 版本四:具体研究:
    # import time
    # def index():
    #     '''有很多代码.....'''
    #     time.sleep(2) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录博客园首页')
    #
    # def timmer(f):
    #     f = index
    #     # f = <function index at 0x0000023BA3E8A268>
    #     def inner():
    #         start_time = time.time()
    #         f()
    #         end_time = time.time()
    #         print(f'测试本函数的执行效率{end_time-start_time}')
    #     return inner
    #
    # index = timmer(index)
    # index()
    
    # 版本五:python做了一个优化;提出了一个语法糖的概念。 标准版的装饰器
    # import time
    # # timmer装饰器
    # def timmer(f):
    #     def inner():
    #         start_time = time.time()
    #         f()
    #         end_time = time.time()
    #         print(f'测试本函数的执行效率{end_time-start_time}')
    #     return inner
    #
    # # @timmer # index = timmer(index)
    # def index():
    #     '''有很多代码.....'''
    #     time.sleep(0.6) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录博客园首页')
    #     return 666
    # ret = index()
    # print(ret)
    
    # def dariy():
    #     '''有很多代码.....'''
    #     time.sleep(3) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录日记页面')
    # dariy()
    # # index = timmer(index)
    # # index()
    # # dariy = timmer(dariy)  @timmer
    # dariy()
    
    
    # # 版本六: 被装饰函数带返回值
    #
    # import time
    # # timmer装饰器
    # def timmer(f):
    #     # f = index
    #     def inner():
    #         start_time = time.time()
    #         # print(f'这是个f():{f()}!!!') # index()
    #         r = f()
    #         end_time = time.time()
    #         print(f'测试本函数的执行效率{end_time-start_time}')
    #         return r
    #     return inner
    #
    # @timmer # index = timmer(index)
    # def index():
    #     '''有很多代码.....'''
    #     time.sleep(0.6) # 模拟的网络延迟或者代码效率
    #     print('欢迎登录博客园首页')
    #     return 666
    # # 加上装饰器不应该改变原函数的返回值,所以666 应该返回给我下面的ret,
    # # 但是下面的这个ret实际接收的是inner函数的返回值,而666返回给的是装饰器里面的
    # # f() 也就是 r,我们现在要解决的问题就是将r给inner的返回值。
    # ret = index()  # inner()
    # print(ret)
    
    
    # 版本八: 被装饰函数带返回值
    
    import time
    # timmer装饰器
    # def timmer(f):
    #     # f = index
    #     def inner(*args,**kwargs):
    #         #  函数的定义:* 聚合  args = ('李舒淇',18)
    #         start_time = time.time()
    #         # print(f'这是个f():{f()}!!!') # index()
    #         r = f(*args,**kwargs)
    #         # 函数的执行:* 打散:f(*args) --> f(*('李舒淇',18))  --> f('李舒淇',18)
    #         end_time = time.time()
    #         print(f'测试本函数的执行效率{end_time-start_time}')
    #         return r
    #     return inner
    #
    # @timmer # index = timmer(index)
    # def index(name):
    #     '''有很多代码.....'''
    #     time.sleep(0.6) # 模拟的网络延迟或者代码效率
    #     print(f'欢迎{name}登录博客园首页')
    #     return 666
    # index('纳钦')  # inner('纳钦')
    
    # @timmer
    # def dariy(name,age):
    #     '''有很多代码.....'''
    #     time.sleep(0.5) # 模拟的网络延迟或者代码效率
    #     print(f'欢迎{age}岁{name}登录日记页面')
    # dariy('李舒淇',18)  # inner('李舒淇',18)
    
    
    # 标准版的装饰器;
    
    # def wrapper(f):
    #     def inner(*args,**kwargs):
    #         '''添加额外的功能:执行被装饰函数之前的操作'''
    #         ret = f(*args,**kwargs)
    #         '''添加额外的功能:执行被装饰函数之后的操作'''
    #         return ret
    #     return inner
    

3)装饰器的应用

# 装饰器的应用:登录认证

def login():
    pass

def register():
    pass


status_dict = {
    'username': None,
    'status': False,
}

def auth(f):
    '''
    你的装饰器完成:访问被装饰函数之前,写一个三次登录认证的功能。
    登录成功:让其访问被装饰得函数,登录没有成功,不让访问。
    :param f:
    :return:
    '''
    def inner(*args,**kwargs):
        '''访问函数之前的操作,功能'''
        if status_dict['status']:
            ret = f(*args,**kwargs)
            '''访问函数之后的操作,功能'''
            return ret
        else:
            username = input('请输入用户名').strip()
            password = input('请输入密码').strip()
            if username == 'taibai' and password == '123':
                print('登录成功')
                status_dict['username'] = username
                status_dict['status'] = True
                ret = f(*args, **kwargs)
                return ret
            else:
                print('登录失败')
    return inner
@auth  # article = auth(article)
def article():
    print('欢迎访问文章页面')
@auth
def comment():
    print('欢迎访问评论页面')
@auth
def dariy():
    print('欢迎访问日记页面')

article()  # inner()
comment()  #inner()
dariy()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值