Python - 三大器 迭代器,生层器,装饰器

Python - 三大器 迭代器,生层器,装饰器

在介绍三大器以前先来了解一下容器和可迭代对象...python

一. 容器

容器是一种把多个元素组织在一块儿的数据结构,容器中的元素能够逐个地迭代获取,能够用in, not in关键字判断元素是否包含在容器中。一般这类数据结构把全部的元素存储在内存中(也有一些特例,并非全部的元素都放在内存,好比迭代器和生成器对象)在Python中,常见的容器对象有:数组

  • list, deque...
  • set, frozensets(不可变集合)...
  • dict, defaultdict, OrderedDict, Counter...
  • tuple, namedtuple...
  • str

容器的概念就像一个盒子,能够往里面装东西.当它能够用来询问某个元素是否包含在其中时,那么这个对象就能够认为是一个容器,好比 list,set,tuples都是容器对象:数据结构

>>> assert 1 in [1, 2, 3]      # lists
>>> assert 4 not in [1, 2, 3]
>>> assert 1 in {1, 2, 3}      # sets
>>> assert 4 not in {1, 2, 3}
>>> assert 1 in (1, 2, 3)      # tuples
>>> assert 4 not in (1, 2, 3)

询问某元素是否在dict中用dict的中key:闭包

>>> d = {1: 'foo', 2: 'bar', 3: 'qux'}
>>> assert 1 in d
>>> assert 'foo' not in d  # 'foo' 不是dict中的元素
询问某substring是否在string中:
>>> s = 'foobar'
>>> assert 'b' in s
>>> assert 'x' not in s
>>> assert 'foo' in s

尽管绝大多数容器都提供了某种方式来获取其中的每个元素,但这并非容器自己提供的能力,而是可迭代对象赋予了容器这种能力,固然并非全部的容器都是可迭代的,好比:Bloom filter,虽然Bloom filter能够用来检测某个元素是否包含在容器中,可是并不能从容器中获取其中的每个值,由于Bloom filter压根就没把元素存储在容器中,而是经过一个散列函数映射成一个值保存在数组中。app

二. 可迭代对象(iterable)

大部分对象都是可迭代,只要实现了__iter__方法的对象就是可迭代的。
__iter__方法会返回迭代器(iterator)自己,例如:函数

>>> lst = [1,2,3]
>>> lst.__iter__()
<listiterator object at 0x7f97c549aa50>

Python提供一些语句和关键字用于访问可迭代对象的元素,好比for循环、列表解析、逻辑操做符等。工具

判断一个对象是不是可迭代对象:spa

>>> from collections import Iterable  # 只导入Iterable方法
>>> isinstance('abc', Iterable)     
True
>>> isinstance(1, Iterable)     
False
>>> isinstance([], Iterable)
True

这里的isinstance()函数用于判断对象类型。
可迭代对象通常都用for循环遍历元素,也就是能用for循环的对象均可称为可迭代对象。
例如,遍历列表:code

>>> lst = [1, 2, 3]
>>> for i in lst:
...   print i
...

三. 迭代器

迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引发一个Stoplteration异常,以终止迭代(只能日后走不能往前退)

实现了迭代器协议的对象(对象内部定义了一个__iter__()方法)

python中的内部工具(如for循环,sum,min,max函数等)基于迭代器协议访问对象。

使用迭代器的好处:

1)省内存,若是使用列表,计算值时会一次获取全部值,那么就会占用更多的内存。而迭代器则是一个接一个计算,只能向前,不能反复

2)使代码更通用、更简单。

3)  惰性机制

判断是不是迭代器:

>>> from collections import Iterator
>>> isinstance(d, Iterator)
False
>>> isinstance(d.iteritems(), Iterator)
True

使用next方法:

>>> iter_items = d.iteritems()
>>> iter_items.next()
('a', 1)
>>> iter_items.next()
('c', 3)
>>> iter_items.next()
('b', 2)

迭代器的原理:

1 #基于迭代器协议
 2 li = [1,2,3]
 3 diedai_l = li.__iter__()
 4 print(diedai_l.__next__())
 5 print(diedai_l.__next__())
 6 print(diedai_l.__next__())
 7 # print(diedai_l.__next__())  # 超出边界报错
 8 
 9 #下标
10 print(li[0])
11 print(li[1])
12 print(li[2])
13 # print(li[3]) # 超出边境报错
14 
15 # 用while循环模拟for循环机制
16 diedai_l = li.__iter__()
17 while True:
18     try:
19         print(diedai_l.__next__())
20     except StopIteration:
21         print("迭代完毕,循环终止")
22         break
23 
24 # for循环访问方式
25 # for循环本质就是遵循迭代器协议的访问方式,先调用diedai_l=li.__iter__方法
26 # 或者直接diedai_l=iter(l),而后依次执行diedai_l.__next__(),直到捕捉到
27 # StopItearation终止循环
28 # for循环全部的对象的本质都是同样的原理

四. 生成器

能够理解为一种数据类型,自动实现迭代器协议

  在调用生成器运行的过程当中,每次遇到yield时函数会暂停并保存当前全部的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行

  1. 表现形式:

    生成器函数 带yield的函数(一、返回值 二、保留函数的运行状态)

          next(t)  t.__next__(能够拿到数据)  t.send(能够拿到数据,能够给上一层的yield传值)

     # 用生成器函数
     # yield 至关于return控制的是函数的返回值
     # x=yield的另一个特性,接收send传过来的值,赋值给x
     def test():
         print("开始啦")
         first = yield # return 1   first = None
         print("第一次",first)
         yield 2
         print("第二次")
     t = test()
     print(test().__next__())
     res = t.__next__() # next(t)
     print(res)
     res = t.send("函数停留在first那个位置,我就是给first赋值的")
     print(res)
    
     输出结果
     开始啦
     None
     开始啦
     None
     第一次 函数停留在first那个位置,我就是给first赋值的
  2. 推导式
    列表推导式:
            [结果 for循环 if语句]
    字典推导式:
            {key:value for if}
    集合推导式
            {key for if}
    
            没有元组推导式!!!!!!!

     

  3. 生成器表达式  (结果 for if)

    print(sum(i for i in range(10000))) # 表达式通常用for循环 (i for i in range(10000))
    # 做用 节省内存,在内部已经实现了__iter__的方法

五. 装饰器

1. 定义

在不修改被修饰函数的源代码和调用方式的状况下给其添加额外功能.

开闭原则:
开放: 能够对软件添加新的功能
封闭: 不能够修改源代码

装饰器 = 高阶函数+函数嵌套+闭包

通用装饰器

def wrapper(fn): # fn是目标函数
            def inner(*args, **kwargs):
                '''执行以前'''
                ret = fn(*args, **kwargs) # 执行目标函数
                '''执行以后'''
                return ret
            return inner

        @wrapper
        def func():
            pass

        func()  # inner()
带有参数的装饰器
        def wrapper_out(参数):
            def wrapper(fn):
                def inner(*args, **kwargs):
                    '''在以前'''
                    ret = fn(*args, **kwargs)
                    '''在以后'''
                    return ret
                return inner
            return wrapper

        @wrapper_out(实参)
        同一个函数被多个装饰器装饰

 

import time #导入时间模块

def foo(func):  # func = test
    def bar(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)   # 这里就是在运行test()  赋予变量
        stop_time = time.tiem()
        print("一场LOL时间为{}").format(stop_time-start_time)
        return res  # 返回test()的值
    return bar

def test(name, age):
    time.sleep(1)
    print("哈哈")
    return "heihei"

res = test("德玛西亚", age=10)
print(ret)

六. 闭包

根据这句话,其实咱们本身就能够总结出在python语言中造成闭包的三个条件,缺一不可:

1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套

2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量

3)外部函数必须返回内嵌函数——必须返回那个内部函数

def funx():
x=5
def funy():
    nonlocal x
    x+=1
    return x
return funy

python闭包的优势:

避免使用全局变量

能够提供部分数据的隐藏

能够提供更优雅的面向对象实现

相关文章
相关标签/搜索