python迭代器、装饰器、生成器、描述器、上下文管理器

本文介绍了Python编程中的几个核心概念:迭代器的实现,包括__iter__和__getitem__方法;装饰器的工作原理,包括无参数和带参数的装饰器,以及类装饰器的实现;闭包的概念和应用,强调了nonlocal关键字的作用;生成器的创建和使用,如生成器表达式和生成器函数,以及send()、close()方法;描述器的概念,展示了__get__、__set__和__delete__方法的用法;最后讲解了上下文管理器的工作流程,包括自定义上下文管理器和使用contextlib库。
摘要由CSDN通过智能技术生成

迭代器:


"""
---------------------------------__getitem__、__iter__方法:遍历操作-----------------------------
__iter__方法的优先级高于__getitem__方法
"""
## 方式一:
# class Person:
#     def __init__(self):
#         self.result = 1
#
#     def __getitem__(self, item):
#         self.result += 1
#         if self.result >= 6:
#             raise StopIteration('停止遍历')
#         return self.result
#
# p = Person()
# for i in p:
#     print(i)


## 方式二(迭代器详述):https://blog.csdn.net/world_in_world/article/details/127755621


## 方式三:
# class Person:
#     def __init__(self):
#         self.age = 1
#
#     def __iter__(self):
#         print('xxx')  # 没有走进该方法
#         self.age = 1
#         return self
#
#     def __next__(self):
#         print('yyy')
#         self.age += 1
#         if self.age >= 6:
#             raise StopIteration('Stop')
#         return self.age
#
# p = Person()
# # pt = iter(p, 4)  # 错误,TypeError: iter(v, w): v must be callable
# pt = iter(p.__next__, 4)
# for i in pt:
#     print(i)


## 方式四:
# class Person:
#     def __init__(self):
#         self.age = 1
#
#     def __iter__(self):
#         print('xxx')  # 没有走进该方法
#         self.age = 1
#         return self
#
#     def __call__(self):
#         print('yyy')
#         self.age += 1
#         if self.age >= 6:
#             raise StopIteration('Stop')
#         return self.age
#
# p = Person()
# pt = iter(p, 4)
# for i in pt:
#     print(i)


# # 实例
# class MyList(object):
#     """自定义的一个可迭代对象"""
#     def __init__(self):
#         self.items = []
#
#     def add(self, val):
#         self.items.append(val)
#
#     def __iter__(self):
#         myiterator = MyIterator(self)
#         return myiterator
#
# class MyIterator(object):
#     """自定义的供上面可迭代对象使用的一个迭代器"""
#     def __init__(self, mylist):
#         self.mylist = mylist
#         # current用来记录当前访问到的位置
#         self.current = 0
#
#     def __next__(self):
#         if self.current < len(self.mylist.items):
#             item = self.mylist.items[self.current]
#             self.current += 1
#             return item
#         else:
#             raise StopIteration
#
#     def __iter__(self):
#         return self
#
# if __name__ == '__main__':
#     mylist = MyList()
#     mylist.add(1)
#     mylist.add(2)
#     mylist.add(3)
#     mylist.add(4)
#     mylist.add(5)
#     for num in mylist:
#         print(num)

装饰器:


"""
闭包结构:在函数嵌套的前提下,即外层函数 + 内层函数,内层函数引用了外层函数的变量或参数,外层函数将内层函数的引用作为返回值进行返回————内层函数 + 所引用的外层变量或参数,称为‘闭包’
好文参考:https://www.cnblogs.com/yume-zbh/p/16022511.html
"""
# def test1():
#     a = 10
#     def test2():
#         print(a)
#     return test2
# newfunc = test1()
# newfunc()



"""
闭包应用场景
"""
# def line_config(content, length):
#     print('-'*(length // 2) + content + '-'*(length // 2))
# line_config('闭包', 40)
# line_config('闭包', 40)
# line_config('闭包', 40)


# def line_config(content, length):
#     def line():
#         print('-'*(length // 2) + content + '-'*(length // 2))
#     return line
# line = line_config('闭包', 40)
# line()
# line()
# line()



"""
注意事项:
1、闭包中,如果要修改引用的外层变量,需要使用 nonlocal 变量进行声明,否则当作是闭包内新定义的变量
2、当闭包内引用了一个后期会发生变化的变量时,一定要注意
"""
# def test():
#     num = 10
#     def test2():
#         # num = 666  # 定义了一个新变量num,而不是修改外层变量num
#         nonlocal num
#         num = 999  # 修改外层变量num
#         print(num)
#     print(num)
#     test2()
#     print(num)
#     return test2
# result = test()


# # 函数什么时候才会确定内部变量标识对应的值:当函数被调用的时候才会真正确定内部变量对应的值,之前都是以普通的变量标识名称存在
# def test():
#     a = 1
#     def test2():
#         print(a)
#     a = 2
#     return test2
# newfunc = test()
# newfunc()  # 打印结果是2
#
# def t1():
#     li = []
#     for i in range(1, 4):
#         def t2(num):
#             def t3():
#                 print(num)
#             return t3
#         li.append(t2(i))
#     return li
#
# b = t1()
# print(b)
# b[0]()
# b[1]()
# b[2]()



"""
一、装饰器:在函数名以及函数体不改变的前提下,给一个函数附加一些额外代码,符合‘开放封闭原则’:已经写好的代码,尽可能不要修改,如果想要新增功能,在原先代码基础上单独进行扩展

二、装饰器的执行时间是碰到就立即执行

--------------------未带参数时--------------------
三、个人书写装饰器的步骤:
    1、先确定原功能函数:
    def fss():
        print('发说说!')
    2、再写装饰器的调用:
    fss = checklogin(fss)
    fss()
    3、后写装饰器:
    def checklogin(func):  # checklogin对func进行装饰
        def inner():
            print('登陆验证……')  # 装饰的具体功能
            func()  # 原功能
        return inner
    4、最后注释 fss = checklogin(fss),在原功能函数上添加语法糖 @checklogin

四、对于以下代码,装饰器的程序执行流程:先执行@checklogin(fss = checklogin(fss)),即调用外层函数checklogin,,返回内层函数inner的引用,再执行fss(),即调用内层函数inner
def checklogin(func):
    def inner():
        print('登陆验证……')
        func()
    return inner
@checklogin
def fss():
    print('发说说!')
# fss = checklogin(fss)
fss()
"""
"""
对有参函数进行装饰
"""
# # ------------------带参数(原功能函数带参数,且函数inner也带参数)------------------
# def checklogin(func):
#     def inner(*args):
#         print('登陆验证……'*args[0])
#         func(args[1])
#     return inner
# @checklogin
# def fss(num):
#     print('发说说!'*num)
# # fss = checklogin(fss)  # 在该位置写此程序,等价于在原功能函数上添加@checklogin
# fss(2, 3)
#
#
# # ------------------带参数(只有原功能函数带参数)------------------
# def checklogin(func):
#     def inner(num):
#         print('登陆验证……')
#         func(num)
#     return inner
# @checklogin
# def fss(num):
#     print('发说说!'*num)
# fss(2)
#
#
# # ------------------带参数(只有函数inner带参数)------------------
# def checklogin(func):
#     def inner(num):
#         print('登陆验证……'*num)
#         func()
#     return inner
# @checklogin
# def fss():
#     print('发说说!')
# fss(2)



"""
装饰器的叠加:从上到下装饰,从下到上执行。
当扫描到@zsq_line,把下面整体当作被装饰函数,继续扫描,又扫描到@zsq_star,把下面整体当作被装饰函数,继续扫描,发现不是装饰器了,则其先装饰
"""
# def zsq_line(func):
#     def inner1():
#         print('----------------------')
#         func()
#         print('zsq_line')
#     return inner1
#
# def zsq_star(func):
#     def inner2():
#         print('**********************')
#         func()
#         print('zsq_star')
#     return inner2
#
# @zsq_line
# @zsq_star
# def print_content():
#     print('小样儿')
#
# # 等同于print_content = zsq_line(zsq_star(print_content))
# print_content()



"""
对有返回值的函数进行装饰:无论什么场景,保证函数返回值一致
"""
# def pnum(num, num2, num3):
#     print(num, num2, num3)
#     return num + num2 + num3
#
# def pnum2(num):
#     print(num)
#
# res1 = pnum(123, 222, num3=666)
# res2 = pnum2(999)
# print(res1, res2)  # 看打印什么


# def zsq(func):
#     def inner(*args, **kwargs):
#         print('-'*30)
#         func(*args, **kwargs)
#     return inner
#
# @zsq
# def pnum(num, num2, num3):
#     print(num, num2, num3)
#     return num + num2 + num3
#
# @zsq
# def pnum2(num):
#     print(num)
#
# res1 = pnum(123, 222, num3=666)
# res2 = pnum2(999)
# print(res1, res2)


# def zsq(func):
#     def inner(*args, **kwargs):
#         print('-'*30)
#         res = func(*args, **kwargs)
#         return res
#     return inner
#
# @zsq
# def pnum(num, num2, num3):
#     print(num, num2, num3)
#     return num + num2 + num3
#
# @zsq
# def pnum2(num):
#     print(num)
#
# res1 = pnum(123, 222, num3=666)
# res2 = pnum2(999)
# print(res1, res2)



"""
带有参数的装饰器
"""
# def zsq(func, char):
#     def inner():
#         print('-'*30)
#         func()
#     return inner
#
# @zsq  # 错误
# @zsq(f1)  # 错误
# def f1():
#     print('666')
# f1()


# def getzsq(char):
#     def zsq(func):
#         def inner():
#             print(char*30)
#             func()
#         return inner
#     return zsq
#
# @getzsq('*')
# def f1():
#     print(666)
# f1()



"""
应用场景
"""
# def fss():
#     print('发说说!')
#
# def ftp():
#     print('发图片!')
#
# def checklogin(func):
#     print('登陆验证……')
#     func()
#
# start = 1
# if start == 1:
#     checklogin(fss)
# else:
#     checklogin(ftp)


# def checklogin(func):
#     def inner(num):
#         print('登陆验证……'*num)
#         func(num)
#     return inner
#
# @checklogin
# def fss():
#     print('发说说!')
#
# # fss = checklogin(fss)
# fss(2)


# def logging(level):
#     def wrapper(func):
#         def inner_wrapper(*args, **kwargs):
#             # print("[{level}]: enter function {func}()".format(level=level, func=func.__name__))
#             print("[{}]: enter function {}()".format(level, func.__name__))
#             return func(*args, **kwargs)
#         return inner_wrapper
#     return wrapper
#
# @logging(level='INFO')
# def say(something):
#     print("say {}!".format(something))
#
# # 如果不使用@语法,则需要使用
# # say = logging(level='INFO')(say)
# @logging(level='DEBUG')
# def do(something):
#     print("do {}...".format(something))
#
# if __name__ == '__main__':
#     say('hello')
#     do("my work")



"""
不带参数的类装饰器,看我倒推
"""
# def check(func):
#     def inner():
#         print('登陆验证')
#         func()
#     return inner
#
# @check
# def fss():
#     print('发说说')
#
# fss()


# 对于@check,假设check是一个类,而@check 等同于 fss=check(fss),我们定义一个类……,
# 执行check(fss)会生成一个实例对象,所以左边的fss是由类check实例化出的对象,
# 由于实例对象传入了参数,所以类内需实现__init__方法,
# 执行fss()表示调用实例对象,所以类内需实现__call__方法,
# class check:
#     def __init__(self, func):
#         self.f = func
#
#     def __call__(self, *args, **kwargs):
#         print('登陆验证')  # 新装饰的具体功能
#         self.f()  # 原功能
#
# @check
# def fss():
#     print('发说说')
#
# fss()


# # 实例
# class Logging:
#     def __init__(self, func):
#         self.func = func
#
#     def __call__(self, *args, **kwargs):
#         print("[DEBUG]: enter function {func}()".format(
#             func=self.func.__name__))
#         return self.func(*args, **kwargs)
#
# @Logging
# def say(something):
#     print("say {}!".format(something))
#
# say('木木')



"""
带参数的类装饰器,倒推类似
"""
class Logging:
    def __init__(self, level='INFO'):
        self.level = level

    def __call__(self, func):  # 接收原功能函数
        def wrapper(*args, **kwargs):
            print("[{level}]: enter function {func}()".format(
                level=self.level,
                func=func.__name__))
            func(*args, **kwargs)
        return wrapper

@Logging(level='INFO')  # 等同于say = Logging(level='INFO')(say)
def say(something):
    print("say {}!".format(something))

# say = Logging(level='INFO')(say)
say('木木')

生成器:


"""
生成器是一种特殊的迭代器(迭代器不一定是生成器)
生成器创建方式:1、生成器表达式
             2、生成器函数
参考:https://blog.csdn.net/world_in_world/article/details/128560927?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22128560927%22%2C%22source%22%3A%22world_in_world%22%7D
"""

"""
生成器表达式(可以误称为元组推导式)
"""
# l = (i for i in range(1, 100000) if i % 2 == 0)
# print(l)
# print(next(l))
# print(next(l))
# print(l.__next__())
# print(l.__next__())
# for i in l[10:15]:  # 错误,生成器对象没有下标
#     print(i)



"""
生成器函数
yield可以阻断当前的函数执行,当使用next函数或者__next__方法时都会让函数继续执行,然后当执行到下一个yield语句时又会被暂停
"""
# def test():
#     print('xxx')
#     yield 1
#     print('a')
#
#     yield 2
#     print('b')
#
#     yield
#     print('c')
#
# g = test()  # 产生一个生成器对象
# print(g)
# print(next(g))
# print(next(g))
# print(g.__next__())
# print(g.__next__())


# def test():
#     for i in range(1, 9):
#         yield i
#
# g = test()
# print(g)
# print(next(g))
# print(next(g))
# print(g.__next__())
# print(g.__next__())



"""
send()函数:send()有一个参数,指定的是上一个yield语句的返回值,g.send()既可以启动生成器,也可以额外的给yield语句传值,第一次调用g.send(None)
"""
# def test():
#     print('xxx')
#     res1 = yield 1
#     print(res1)
#
#     res2 = yield 2
#     print(res2)
#
# g = test()
# print(g.__next__())
# print(g.__next__())


# def test():
#     print('xxx')
#     res1 = yield 1
#     print(res1)
#
#     res2 = yield 2
#     print(res2)
#
# g = test()
# print(g.__next__())
# print(g.send('666'))


# def test():
#     print('xxx')
#     res1 = yield 1
#     print(res1)
#
#     res2 = yield 2
#     print(res2)
#
# g = test()
# print(g.send(None))  # 第一次调用send(),需传入None,硬性规定
# print(g.__next__())



"""
关闭生成器:close()函数
"""
# def test():
#     yield 1
#     print('a')
#
#     yield 2
#     print('b')
#
#     yield 3
#     print('c')
#
# g = test()
# print(g.__next__())
# print(g.__next__())
# g.close()
# print(g.__next__())



"""
注意:
1、如果碰到return,程序会直接终止,抛出StopIteration异常提示
2、生成器只会遍历一次,想要再遍历一次需再生成一个生成器对象
"""
# def test():
#     yield 1
#     print('a')
#
#     yield 2
#     print('b')
#
#     return 10
#
#     yield 3
#     print('c')
#
# g = test()
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())


# def test():
#     yield 1
#     print('a')
#
#     yield 2
#     print('b')
#
#     yield 3
#     print('c')
#
# g = test()
# for i in g:
#     print(i)  # c打印出来的同时,不会抛出StopIteration异常提示
# print('-'*40)
# # g = test()
# for i in g:  # 未生成一个新的生成器对象,再遍历一次,无返回结果
#     print(i)

描述器:


"""
---------------------------------__get__、__set__、__delete__方法:描述器------------------------------
只要实现了三个方法中任意一个方法的类实例化出的对象就可称为描述器;一般通过实例对象操作描述器对象,而不通过类;描述器只在新式类中生效,在经典类中无法生效
"""
## 定义方式一:
# class Person(object):
#     def getage(self):
#         print('-----------getage')
#         return self.__age
#
#     def setage(self, value):
#         print('-----------setage')
#         self.__age = value
#
#     def delage(self):
#         print('-----------delage')
#         del self.__age
#
#     age = property(getage, setage, delage, '这是个描述器')  # age是一个描述器,当然也是一个类属性
#
# p = Person()
# help(Person)  # 可以看到 Data descriptors defined here:
# p.age = 18
# print(p.age)
# del p.age
# print(Person.age)  # 类操作描述器,描述器无法生效
# Person.age = 18
# del Person.age


## 定义方式二:
# class Age:
#     def __get__(self, instance, owner):
#         print('get')
#
#     def __set__(self, instance, value):
#         print('set')
#
#     def __delete__(self, instance):
#         print('delete')
#
# class Person:
#     age = Age()
#
# p = Person()
# p.age = 18
# print(p.age)
# del p.age
# print(Person.age)  # 类操作描述器,描述器局部生效
# Person.age = 18
# del Person.age


## 描述器与实例属性重名时,操作优先级
## 资料描述器:至少实现了__get__、__set__方法
## 非资料描述器:仅仅实现了__get__方法
## 资料描述器 > 实例属性 > 非资料描述器
# class Age:
#     def __get__(self, instance, owner):
#         print('get')
#
#     def __set__(self, instance, value):
#         print('set')
#
#     def __delete__(self, instance):
#         print('delete')
#
# class Person:
#     age = Age()
#     def __init__(self):
#         self.age = 18
#
# p = Person()
# p.age = 18
# print(p.__dict__)


## 不同Age实例共享同一age,数据存储应用Person实例
class Age:
    def __get__(self, instance, owner):
        print('get', self, instance, owner)
        return self.v
        # return instance.v

    def __set__(self, instance, value):
        print('set', self, instance, value)
        self.v = value
        # instance.v = value

    def __delete__(self, instance):
        print('delete', instance)

class Person:
    age = Age()

p1 = Person()
p1.age = 18
print(p1.age)
p2 = Person()
p2.age = 10
print(p2.age)
print(p1.age)

上下文管理器:


"""
语法:
with context_expression as target:
    with-body

执行逻辑:
1、识别到关键字with,执行上下文表达式context_expression,返回一个上下文管理器对象
2、自动调用上下文管理器对象的__enter__方法,如果写了as target语句,则把__enter__方法的返回值赋值给target
3、执行语句体
4、自动执行上下文管理器对象的__exit__方法

注意事项:
1、上下文表达式必须要返回一个”上下文管理器对象“
2、上下文管理器对象是实现了”上下文协议“的对象
3、上下文协议规定某一对象必须实现__enter__、__exit__两个方法
"""


"""
应用场景示例:
文件读取操作正常步骤:
1、打开文件:f = open('xxx', 'r')
2、读取文件:f.read()
3、关闭文件:f.close()
而我们想保证不管文件操作有没有异常都要关闭文件,则需这样操作:
try:
    1、打开文件
    2、读取文件
finally:
    3、关闭文件

以上步骤过于繁琐,于是有了此方案:
with open(file) as f:
    2、读取文件
注意:此时上下文管理器对象的__enter__方法的返回值是文件对象并赋值给f
"""


"""
自定义上下文管理器
"""
# class Test:
#     def __enter__(self):
#         print('enter')
#         # return 'xxx'
#
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print(self, exc_type, exc_val, exc_tb)
#         print('exit')
#
# with Test() as x:
#     print('body', x)  # 此时x为None


# class Test:
#     def __enter__(self):
#         print('enter')
#
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print(self, exc_type, exc_val, exc_tb)
#         print('exit')
#         return True  # 返回True异常内部消耗,程序正常运行;返回False或None或注释掉异常外抛,程序崩溃
#
# with Test():
#     1/0


# class Test:
#     def __enter__(self):
#         print('enter')
#         return self
#
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print(self, exc_type, exc_val, exc_tb)
#         import traceback
#         print(traceback.extract_tb(exc_tb))  # 想主动打印异常追踪
#         print('exit')
#         return True
#
# with Test() as x:
#     1/0


"""
使用装饰器,让一个生成器变成一个上下文管理器
"""
# import contextlib
# @contextlib.contextmanager
# def test():
#     print(1)
#     yield  # yield前的部分为上文,yield后的部分为下文,yield返回的状态值赋值给x
#     # yield 'xxx'
#     print(2)
#
# with test() as x:
#     print(3, x)
# # 执行顺序print(1),yield,print(3, x),print(2)


# import contextlib
# @contextlib.contextmanager
# def test():
#     try:
#         yield
#     except Exception as e:
#         print('error', e)
#
# with test():
#     1/0
# # 执行顺序try,yield,1/0,except


"""
contextlib.closing函数可以让一个拥有close方法但不是上下文管理器的对象变成上下文管理器
"""
import contextlib
class Test:
    def start(self):
        print('上文手动调用')

    def close(self):
        print('下文自动调用')

with contextlib.closing(Test()) as t_obj:
    t_obj.start()
    print('111')


"""
操作多个文件
"""
# with open('xxx', 'wb') as from_file:
#     with open('yyy', 'wb') as to_file:
#         from_content = from_file.read()
#         to_file.write(from_content)


# with open('xxx', 'wb') as from_file, open('yyy', 'wb') as to_file:
#     from_content = from_file.read()
#     to_file.write(from_content)


"""
操作单个文件
"""
# with open('file.txt', 'w', encoding='gbk') as f:
#     print(f)
#     f.write('这是一条测试')
# 
# 
# class Open:
#     def __init__(self, filename):
#         self.filename = filename
# 
#     def __enter__(self):
#         self.f = open(self.filename, 'w', encoding='gbk')
#         return self.f
# 
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         self.f.close()
# 
# with Open('file.txt') as p:
#     print(p)
#     p.write('这是一条测试')

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值