zoukankan      html  css  js  c++  java
  • Python 迭代器&生成器&装饰器

    1.内置参数

        Built-in Functions    
    abs() dict() help() min() setattr()
    all() dir() hex() next() slice()
    any() divmod() id() object() sorted()
    ascii() enumerate() input() oct() staticmethod()
    bin() eval() int() open() str()
    bool() exec() isinstance() ord() sum()
    bytrarray() filter() issubclass() pow() super()
    bytes() float() iter() print() tuple()
    callable() format() len() property() type()
    chr() frozenset() list() range() vars()
    classmethod() getattr() locals() repr() zip()
    compile() globals() map() reversed() __import__()
    complex() hasattr() max() round()  
    delattr() hash() memoryview() set()  

    内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii 

    2.迭代器&生成器

    列表生成式,是Python内置的一种极其强大的生成list的表达式。

    如果要生成一个list [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9] 可以用 range(1 , 10):

    1
    2
    #print(list(range(1,10)))
    [123456789]

    如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?

    1
    2
    3
    4
    5
    6
    = []
    for in range(1,10):
        l.append(i*i)
    print(l)
    ####打印输出####
    #[1, 4, 9, 16, 25, 36, 49, 64, 81]

    而列表生成式则可以用一行语句代替循环生成上面的list:

    1
    2
    >>> print([x*for in range(1,10)])
    [149162536496481]

    for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

    1
    2
    >>> print([x*for in range(1,10if %2 ==0])
    [4163664]
    >>>[ i*2 for i in range(10)]
    [0,1,4,6,8,10,12,14,16,18]
    等于
    >>>a=[]
    >>>for i in range(10):
    .  .  .    a.append(i*2)
    >>>a
    [0,1,4,6,8,10,12,14,16,18]
    

     小程序

    str1 = ""
    for i in iter(input,""):    # 循环接收 input输入的内容
        str1 += i
    
    print(str1)

    生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    >>>l = [x*x for x in range(10)]
    >>>l
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>>g = (x*x for x in range(10))
    >>>g
    <generator object <genexpr> at 0x1022ef630>
    View Code

    创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

    我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

    如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    9
    >>> next(g)
    16
    >>> next(g)
    25
    >>> next(g)
    36
    >>> next(g)
    49
    >>> next(g)
    64
    >>> next(g)
    81
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

    generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

    比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    1, 1, 2, 3, 5, 8, 13, 21, 34, ...

      

    def fib(max):
       n,a,b=0,0,1
       while n < max:
          print(b)
          a,b=b,a+b
          n = n+1
       return 'done'
    

    上面的函数可以输出斐波那契数列的前N个数:

    >>>fib(10)
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    done
    

    生成器的特点:

    1)生成器只有在调用时才会生成相应的数据;

    2)只记录当前位置;

    3)只有一个__next__()方法;

    还可通过yield实现在单线程的情况下实现并发运算的效果:

    import time
    def consumer(name):
        print("%s 准备吃包子!" %name)
        while True:
            baozi = yield
            print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
    c = consumer("ChenRonghua")
    c.__next__()
    
    def produceer(name):
        c = consumer("a")
        c2 = consumer("b")
        c.__next__()
        c2.__next__()
        print("老子开始准备做包子啦!")
        for i in range(10):
            time.sleep(1)
            print("做了1个包子,分两半!")
            c.send(i)
            c2.send(i)
    produceer("alex")
    

      迭代器

    我们已经知道,可以直接作用于for循环的数据类型有以下几种:

    一类是集合数据类型,如listtupledictsetstr等;

    一类是generator,包括生成器和带yield的generator function。

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

    可以使用isinstance()判断一个对象是否是Iterable对象:

    >>>from collections import Iterable
    >>>isinstance([],Iterable)
    True
    >>>isinstance({},Iterable)
    True
    >>>isinstance('abc',Iterable)
    True
    >>> isinstance((x for x in range(10)), Iterable)
    True
    >>> isinstance(100, Iterable)
    False
    

      

    凡是可作用于for循环的对象都是Iterable类型;

    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    Python的for循环本质上就是通过不断调用next()函数实现的,例如:

    for x in [1,2,3,4,5]:
    pass
    

    实际上完全等价于:

    # 首先获得Iterator对象:
    it = iter([1, 2, 3, 4, 5])
    # 循环:
    while True:
        try:
            # 获得下一个值:
            x = next(it)
        except StopIteration:
            # 遇到StopIteration就退出循环
            break
    

      

    3.装饰器

    定义: 

      本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能 

    装饰器原则:

      1)  不能修改被装饰函数的源代码; 

      2)  不能修改被装饰函数的调用方式;

      实现装饰器知识储备:

    函数即“变量”

      定义一个函数相当于把函数体赋值给了函数名 

    1.函数调用顺序

      其他高级语言类似,python不允许在函数未声明之前,对其进行引用或者调用

    错误示范:

     1 def foo():
     2     print('in the foo')
     3     bar()
     4 foo()
     5 
     6 报错:
     7 in the foo
     8 Traceback (most recent call last):
     9   File "<pyshell#13>", line 1, in <module>
    10     foo()
    11   File "<pyshell#12>", line 3, in foo
    12     bar()
    13 NameError: global name 'bar' is not defined
    14 
    15 def foo():
    16     print('foo')
    17     bar()
    18 foo()
    19 def bar()
    20     print('bar')
    21 报错:NameError: global name 'bar' is not defined
    View Code

    正确示范:(注意,python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分)

    def foo()
        print('in the foo')
        bar()
    def bar():
        print('in the bar')
    foo()
    
    def bar():
        print('in the bar')
    def foo():
        print('in the foo')
        bar()
    foo()
    View Code

    2.高阶函数

    满足下列条件之一就可成函数为高阶函数

      1.某一函数当做参数传入另一个函数中

      2.函数的返回值包含n个函数,n>0

    高阶函数示范:

    def bar():
        print('in the bar')
    def foo(func):
        res=func()
        return res
    foo(bar)
    View Code

     高阶函数的牛逼之处:

    def foo(func):
        return func
    print('function body is %s' %(foo(bar)))
    print('function name is %s' %(foo(bar).func_name))
    foo(bar)()
    #foo(bar)() 等同于bar=foo(bar)然后bar()
    bar = foo(bar)
    bar()
    View Code

    3.内嵌函数和变量作用域

    定义:在一个函数体内创建另一个函数,这种函数就叫内嵌函数

    嵌套函数:

    def foo():
        def bar():
            print('in the bar')
        bar()
    foo()

    局部作用域和全局做用域的访问顺序

    x = 0
    def grandpa():
        def dad():
            x = 2
            def son():
                x=3
                print(x)
            son()
        dad()
    grandpa()
    View Code

    4.高阶函数+内嵌函数=》装饰器

    函数参数固定

    def decorartor(func):
        def wrapper(n):
            print('starting')
            func(n)
            print('stopping')
        return wrapper
    
    def test(n):
        print('in the test arg is %s' %n)
    decorartor(test)('alex')
    View Code

    函数参数不固定

    def decorartor(func):
        def wrapper(*args,**kwargs):
            print('starting')
            func(*args,**kwargs)
            print('stopping')
        return wrapper
    
    def test(n,x=1):
        print('in the test arg is %s' %n)
    decorartor(test)('alex',x=2222)
    View Code

    1.无参装饰器

    import time
    def decorator(func):
        def wrapper(*args,**kwargs):
            start_time=time.time()
            func(*args,**kwargs)
            stop_time=time.time()
            print("%s" %(stop_time-start_time))
        return wrapper
    
    @decorator
    def test(list_test):
        for i in list_test:
            time.sleep(0.1)
            print('-'*20,i)
    
    #decorator(test)(range(10))
    test(range(10))
    View Code

    2.有参装饰器

    import time
    def timer(timeout=0):
        def decorator(func):
            def wrapper(*args,**kwargs):
                start=time.time()
                func(*args,**kwargs)
                stop=time.time()
                print('run time is %s ' %(stop-start))
                print(timeout)
            return wrapper
        return decorator
    @timer(2)
    def test(list_test):
        for i in list_test:
            time.sleep(0.1)
            print ('-'*20,i)
      
    #timer(timeout=10)(test)(range(10))
    test(range(10))
    View Code

    3.终极装饰器

    user,passwd = 'alex','abc123'
    def auth(auth_type):
        print('auth func:',auth_type)
        def outer_wrapper(func):
            def wrapper(*args,**kwargs):
                print("wrapper func args:",*args,**kwargs)
                if auth_type=="local":
                    username = input("Username:").strip()
                    password = input("Password:").strip()
                    if user == username and passwd == password:
                        res = func(*args,**kwargs)
                        print("---after authentication")
                        return res
                    else:
                        exit("33[31;1mInvalid username or password33[0m")
                elif auth_type == "ldap":
                    print('搞毛线ldap,不会......')
    
            return wrapper
        return outer_wrapper
    
    def index():
        print("welcome to index page")
    @auth(auth_type="local")    #home = wrapper()
    def home():
        print("welcome to home page")
        return "from home"
    @auth(auth_type="ldap")
    def bbs():
        print("welcome to bbs page")
    
    index()
    print(home())#wrapper()
    bbs()
    View Code
  • 相关阅读:
    MySQL日期函数与日期转换格式化函数大全
    外设驱动库开发笔记19:BMP280压力温度传感器驱动
    外设驱动库开发笔记18:MS5837压力变送器驱动
    通讯接口应用笔记1:RS485通讯上下拉电阻的选择
    外设驱动库开发笔记17:MS5803压力变送器驱动
    外设驱动库开发笔记16:MS5536C压力变送器驱动
    Elasticserach学习笔记之Elasticsearch查询慢和集群慢查询日志配置
    Linux学习笔记之curl模拟get/post/delete/put请求
    ELK学习笔记之elasticsearch中 refresh 和flush区别
    Prometheus学习笔记之Prometheus是如何定义告警级别的
  • 原文地址:https://www.cnblogs.com/smile1/p/5769488.html
Copyright © 2011-2022 走看看