zoukankan      html  css  js  c++  java
  • LF 第三章 装饰器和迭代器相关

    名称空间

    顾名思义就是存放名字的地方,比如,若变量x=1,1存放在内存里,那x存在哪里?名称空间就是存放名字x与1绑定关系的地方

    x:内存地址                               1所在的内存

    名称空间共3种,分别如下:

    locals:是函数内的名称空间,包括局部变量和形参

    globals:全局变量,函数定义所在模块的名字空间

    builtins:内置模块的名字空间

    作用域的查找空间

    作用域的查找顺序

    LEGB

    L:locals :函数的名字空间,包括局部变量和形参

    E:enclosing 相邻的上一级 外部嵌套函数的名字空间

    G:globls 全局变量,函数定义所在的模块名字空间

    B:builtins 内置模块的名字空间

    闭包

    举例:

    def func():
        n = 10
        def func2():
            print("n=",n)
        return func2
    
    f = func()
    f()

    从理论上说,当f = func()时候,func已经关闭,那么n = 10这个内部局部变量就应该释放了,但是f()仍能够打印出10,这是为什么呢?

    这就是闭包的概念

    整改代码发生的现象就是一个闭包

    f2是放在f里面,原来是根本拿不到f2,如果要执行只能在f里面执行

    但是现在 f返回了f2名称 相当于在外部拿到了里面的函数。

    即 func如果返回了内部的一个东西,并且还在使用中,那么他的内存空间不会释放的。

    我们在外部可以执行内部的函数,并且可以用内部函数作用域里面的所有值,这就是闭包

    原来f2放在func里面,在外面是不知道f2存在,只能在外面执行,但是把内层函数名称返回,在外部拿到了里面的函数,那其实func返回内部东西,还在使用中,内存空间没被释放。效果:我们在外部可以执行内部函数,并且可以用他内部函数作用域里的所有的值。

    装饰器

    代码有两个原则

    开放-封闭原则:开放 对现有功能的扩展开放  封闭:已实现的功能代码块不应该被修改

    不改变调用方式

    在符合开放封闭原则的情况下,给代码加新功能

    # -*- coding:utf-8 -*-
    def login(func):
        def inner():
            _username = '111'
            _password = '222'
            global user_status
            if user_status == False:
                username = input("user:")
                password = input("pasword:")
    
                if username == _username and password == _password:
                    print("welcom login...")
                    user_status = True
                else:
                    print("wrong!")
            if user_status == True:
                func()
        return inner
    
    def home():
        print("---首页----")
    #home = login(home())
    @login
    def america():
        print("----欧美----")
    
    def japan():
        print("----日本----")
    @login
    def henan():
        print("----河南----")
    
    user_status = False
    
    home()
    america()
    henan()

    个人理解:通过高阶嵌套函数,将原来的代码块进行包装

    home = login(home()) 此home非旧home, 

    如果遇到传参情况,为了方便装饰器能用多个代码块上,则需要传入非固定参数 *args **args,注意返回方法同样用**
    # -*- coding:utf-8 -*-
    def login(func):
        def inner(*args,**kwargs):
            _username = '111'
            _password = '222'
            global user_status
            if user_status == False:
                username = input("user:")
                password = input("pasword:")
    
                if username == _username and password == _password:
                    print("welcom login...")
                    user_status = True
                else:
                    print("wrong!")
            if user_status == True:
                func(*args,**kwargs)
        return inner
    
    def home():
        print("---首页----")
    #home = login(home())
    @login
    def america():
        print("----欧美----")
    
    def japan():
        print("----日本----")
    @login
    def henan(style):
        print("----河南----")
    
    user_status = False
    
    home()
    america()
    henan('3p')

    如果装饰器带参数,那么需要再套一层函数

    # -*- coding:utf-8 -*-
    def login(auth_type):
        def outer(func):
            def inner(*args,**kwargs):
                _username = '111'
                _password = '222'
                global user_status
                if user_status == False:
                    username = input("user:")
                    password = input("pasword:")
    
                    if username == _username and password == _password:
                        print("welcom login...")
                        user_status = True
                    else:
                        print("wrong!")
                if user_status == True:
                    func(*args,**kwargs)
            return inner
        return outer
    def home():
        print("---首页----")
    #home = login(home())
    def america():
        print("----欧美----")
    
    def japan():
        print("----日本----")
    @login('qq')
    def henan(style):
        print("----河南----")
    
    user_status = False
    
    home()
    america()
    henan('3p')

    银角大王的解释我觉得很容易懂

    @login
    def henan():
        pass
    
    #在这里 @ 相当于把下面的函数henan当做一个参数,传给了login这个方法,那么
    
    @login('qq')
    def henan():
        pass
    #这里 就相当于将函数henan当做参数,传给了login('qq')这个执行后的return的函数

    装饰器需要重点复习

    列表生成

    a = [2,3,4,5,6,7,8,9]
    b = a.copy()
    c=a.copy()
    for i in range(len(a)):
        a[i]+=1
    print(a)
    
    #列表生成式
    b = [i+1 for i in b ]
    print(b)
    #高级一点例子
    
    c = [i if i<6 else i*i for i in a]
    print(c)

    继续用银角大王的总结:

    for i in a 做一个循环,前面相当于循环缩进下面得每一个i 每循环一次前面都会执行一次,结果会当做元素挨个存放,这时候,a 就可以循环任何东西,列表元组字典字符串等等。

    这个只能写到列表里和元组里

     生成器

     假设一个场景,我需要从一个列表中取数据,而这个列表可能长度是10或者100万,这样的话难道要预先生成一个100万长度的列表吗?不会的,因为非常占用内存空间

    解决办法:生成器

    如果我知道一个列表的规律,那么我就可以制定一个规则,当我需要什么值时候,我再通过规则去生成这个值,这样就避免了空间浪费。

    a = (i for i in range(5))
    >>> < generator object<genexpr> at 0xkasjdfljals>
    #这就是一个生成器generato
    #如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:
    next(a)
    #1.只能往后输出,不能回头
    #2.超出边界,报错
    #生成器保存的是一个算法,超出边界就会跑出stopIteration错误

      


    生成器调用方式
    用next()一个一个调很不现实,一般用for循环调

    a = (i for i in range(5))
    for i in a3:
      print(i)

    与next区别,超过范围不报错,直接跳出循环

    这个会报错

    while True:
        next(a3)
    range(100) <<底层就是生成器 python2里打印,python3里就是> range(0,100) python2里替代range的:xrange()

    斐波那契数列

    小注意点:

    a = 1,b = 2
    a,b= b,a+b

    此时a和b是多少?答案是 2,和3

    为什么呢 ?不知道

    函数调用

    def fib(max):
      n,a,b = 0,0,1
      while n < max:
        yield b #通过函数生成了一个生成器 这个语法相当于 :出现了yield,就相当于将这个函数变成了生成器 函数执行到这里就返回了(冻结,函数没有结束) 通过next(f) 函数才能继续往下走。。把函数的执行过程冻结在这一步,并且把b的值返回给外面的next()
        a,b = b,a+b
        n = n+1
    return 'done'
    print(fib(15))
    f = fib(15)
    >><generator ...>

    变成了一个生成器

    print(next(f))
    ...
    0 0 1 2 3 5..

    刚开始执行时候,f = fib(15) python将他变成一个生成器
    只有next(f) 从函数开始,到yield结束
    下一次next(f) ,则从上一次yield后面开始,执行到这一次yield之前。
    好处是,函数执行-等结果
    如果这样 函数执行一小会儿,把函数执行过程中的某个状态,返回出来。原来只能到结束,现在可以函数执行过程中返回到外部,多次

    总结:
    1。函数内加了yield 函数名加括号,函数根本不执行,只是生成了一个生成器对象
    2.yield把函数的执行过程冻结在这一步(没有结束)
    3。并且把b的值返回给外面的next()

    for i in a:
    循环这个生成器,不用next方法,不会报错
    while...
    用next方法,会报错

    range(10) python2 :[0,1,2,3,4,5,6,7,8,9]
    python3:range(0,10)
    python2中有个方法跟python3中range一样:xrange

    生成器的创建方式
    1.类似列表生成式    []>>>()    最复杂的方式只能写一个三元运算
    2.函数生成器

    def range2(n):
        count = 0
        while count < n:
            print(count)
            count += 1
    range2(10)        

    next(f) 就等于 f.__next__()

    如果这样

    def range2(n):
        count =0
        while count<n 
            count+=1
            yield count
            print(----)
        return x >>>>>会报错                                

    总结:
    python2
      range = list
      xrange = 生成器generator
    python3
      range = 生成器generator
      xrange 没有

    yield vs return
      return 返回并终止function
      yield 返回数据,并冻结当前的执行过程

      next 唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield


    1.函数有了yield之后,函数名加()就得到了一个生成器,生成器就必须next(开始执行,如果终结了还能唤醒
    2 return在生成器里代表生成器的终止,直接报错


    如果需要中断,range.send("xxx") 传给yield
    sign = yield asef
    通过判断sign 可以break可以return退出

    迭代器
    理解:迭代一次=循环一次

    可以直接作用于for循环的数据类型
    一类是集合类型:list tuple dict set str
    一类是生成器,包裹开yield的generator function
    可以直接作用于for循环的对象统称为可迭代对象 Iterable()注意这是可迭代对象 Able
    可以使用.isinstance()判断一个对象是否是Iterable对象 isinstance('abc',Iterable)>>>>True

    一切皆对象

    :::可以被next()调用并且返回下一个值的对象成为迭代器Iterator 这个是迭代器 Tor
    (生成器 是 迭代器的一种)
    迭代器都是可迭代对象
    可迭代对象不都是迭代器
    集合类就不是
    如何将可迭代对象转化为迭代器?
    通过iter方法
    isinstance('abc',Iterator)>>>>False
    str = iter('abc')
    这样 str 就是迭代器,可以使用next()方法,

    str.__next__()>>
    'a'
    'b'
    'c'
    traceback....

    迭代器对象是一个数据流,迭代器对象可以被next()函数调用并不断返回下一个数据,知道没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序的序列,但我们却不知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以迭代器的对象都是惰性的,只有在需要返回下一个数据时他才会计算
    迭代器甚至可以表示一个无限大的数据流,列入全体自然数,而list永远不可能存储所有自然数。。
    总结:迭代器和可迭代

    总结:
    凡是可以for循环的 都是可迭代对象 iterable
    凡是可作用于next()的 都是Iterator对象 迭代器对象
    集合数据类型 list tuple dict str 是可迭代对象,但不是迭代器,可以通过iter()获得一个迭代器对象
    Python3的for循环本质上就是通过不断调用next()函数来实现的

  • 相关阅读:
    你应该掌握的——树和二叉树
    nyist oj 63(二叉树)
    非递归遍历二叉树的四种策略先序、中序、后序和层序
    学习的四种境界
    nyist oj 467 (中缀式变后缀式)
    二叉平衡树
    nyist OJ 35 (表达式求值)
    线索二叉树
    二叉树的三种遍历方法(递归和非递归)
    算法学习之路
  • 原文地址:https://www.cnblogs.com/alexstraze/p/9274343.html
Copyright © 2011-2022 走看看