Python3基础之学习笔记(五)-装饰器-迭代器和生成器-内置函数

1.装饰器

1.1装饰器简介

装饰器本质是函数,是用来装饰其他函数的,为其他函数添加附件功能

原则:

  1. 不能修改被装饰的函数的源代码
  2. 不能修改被装饰的函数的调用方式

1.2装饰器应用

实现装饰器知识储备:

  1. 函数即变量
  2. 高阶函数
  3. 嵌套函数

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

1.2.1装饰器之函数即变量

定义函数类似于定义变量,先在内存中定义好,使用时再去内存中查找

def fun1():
    print('fun1')
    fun2()
def fun2():
    print('fun2')
 
fun1()
#结果
'''
fun1
fun2
'''

1.2.2装饰器之高阶函数

a. 把一个函数名当做参数传给另一个函数
b. 返回结果包括函数名

def fun1():
    print('fun1')
def test(func):
    print(func)
    func()
    return func
print(test(fun1))
'''
结果为
<function fun1 at 0x000001F26ED93F28>
fun1
<function fun1 at 0x000001F26ED93F28>
'''

1.2.3装饰器之嵌套函数

嵌套函数是在一个函数内部定义多个函数

def fun1():
    def fun2():
        print('fun2')

1.2.4装饰器之案例解析

import time
def timer(func):
    def deco():
        start_time=time.time()
        func()#执行的是原始fun1函数
        stop_time=time.time()
        print("这个函数运行时间=%s"%(stop_time-start_time))
    return deco#返回deco函数地址
def fun1():
    time.sleep(3)
    print('Hello World')
fun1=timer(fun1)#传入fun1函数地址,将fun1函数地址变为deco函数地址
fun1()#实际执行的是deco函数
'''
结果为
Hello World
这个函数运行时间=3.0006909370422363
'''

1.2.5装饰器之实际使用

import time
def timer(func):
    def deco(*args,**kwargs):#接收参数
        start_time=time.time()
        res=func(*args,**kwargs)#获取函数返回结果
        stop_time=time.time()
        print("这个函数运行时间=%s"%(stop_time-start_time))
        return res#实现函数有返回结果功能
    return deco#返回deco函数地址
@timer #相当于fun1=timer(fun1),调用时相当于将fun1函数地址替换为deco函数地址
def fun1():
    time.sleep(3)
    print('Hello World')
@timer
def fun2(str):
    time.sleep(3)
    print(str)
fun1()
fun2("你好世界")

1.2.6装饰器之高级使用

import time
def timer(type='str'):
    def out_wrapper(func):
        def deco(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)  # 获取函数返回结果
            stop_time = time.time()
            if type=='int':
                print("这个函数运行时间=%d" % (stop_time - start_time))
            elif type=='float':
                print("这个函数运行时间=%f" % (stop_time - start_time))
            else:
                print("这个函数运行时间=%s" % (stop_time - start_time))
            return res
        return deco  # 返回deco函数地址
    return out_wrapper
@timer(type='int')#相当于先执行timer(type='int')再执行fun3=out_wrapper(fun3)
def fun3(str):
    time.sleep(3)
    print(str)
fun3('带参数的装饰器')
'''
结果为:
带参数的装饰器
这个函数运行时间=3
'''

2.迭代器与生成器

2.1列表生成式

a=[i*2 for i in range(3)]
#a=[0,2,4]

2.2生成器

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

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

#将列表生成式中的中括号改成圆括号就行了,生成器调用时才会生成数据,所以不能通过切片和下标获取
>>> a=(i*2 for i in range(3))
>>> a
<generator object <genexpr> at 0x000002D3397ACA40>
>>> for i in a:
...     print(i)
...
0
2
4

生成器只记录当前位置,可以使用下面方法获取某一个元素

In [1]: a=(i*2 for i in range(3))

In [2]: a
Out[2]: <generator object <genexpr> at 0x0000020FF1A7FD00>

In [3]: a.__next__()
Out[3]: 0

In [4]: a.__next__()
Out[4]: 2

用函数来实现生成器

斐波拉契数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到

In [1]: def fib(max):
   ...:     n,a,b=0,0,1
   ...:     while n<max:#循环max次
   ...:         print(b)
   ...:         a,b=b,a+b#(a,b)=(b,a+b)
   ...:         n=n+1
   ...:     return 'done'
   ...:
   ...:

In [2]: fib(5)
1
1
2
3
5
Out[2]: 'done'
#用函数做的生成器,当a循环完再使用__next__()会抛出StopIteration异常
In [3]: def fib(max):
   ...:     n,a,b=0,0,1
   ...:     while n<max:
   ...:         #print(b)
   ...:         yield b#yield作用是返回当前b的值,返回后(调用__next__()方法)继续执行后面的语句
   ...:         a,b=b,a+b
   ...:         n=n+1
   ...:     return 'done'
   ...:
   ...:
   ...:

In [4]: a=fib(5)

In [5]: print(a.__next__())
1

In [6]: print(a.__next__())
1

In [7]: print(a.__next__())
2
In [8]: for i in a:
   ...:     print(i)
   ...:
3
5
In [9]: print(a.__next__())
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-9-bc62b802dbf0> in <module>()
----> 1 print(a.__next__())

StopIteration:

生成器并发

import time
def consumer(name):
    print("%s 准备吃饺子啦!" %name)
    while True:
       jiaozi = yield#yield有值才会执行下面语句
       print("第%s饺子来了,被%s吃了!" %(jiaozi,name))
def producer(name):
    a= consumer('A')
    b= consumer('B')
    a.__next__()#执行生成器
    b.__next__()
    print("开始准备做饺子啦!")
    for i in range(10):
        time.sleep(1)
        print("做了1个饺子,分成两半!")
        a.send(i)#给'B'一半饺子,给yield传一个值
        b.send(i)#给‘A’一半饺子
producer("XXXX")

3.迭代器

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

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

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

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

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

>>> from collections import Iterable
>>> isinstance([], Iterable)
True

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

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

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

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

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

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

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

4.内置函数

In [1]: abs(-5)#获取绝对值
Out[1]: 5

In [2]: all([1,-5])#列表里所有元素为真,结果为真,有一个为假,结果为假,除0意外,其他值都为真
Out[2]: True

In [3]: any([1,0])#列表里只要有一个元素为真,结果为真,列表为空返回False
Out[3]: True
    
In [4]: bin(8)#将数字转换成二进制
Out[4]: '0b1000'
    
In [5]: a=ascii([1,2,'Hello World'])#将一些数据转换成可打印字符串
In [6]: print(a,type(a))
[1, 2, 'Hello World'] <class 'str'>

In [7]: bool([])#判断真假
Out[7]: False
In [8]: bool(0)
Out[8]: False
In [9]: bool(-2)
Out[9]: True
    
In [10]: b=bytearray('abc',encoding='utf-8')#可修改的二进制
In [11]: print(b[0])
97
In [12]: b[0]=98
In [13]: print(b)
bytearray(b'bbc')

In [14]: callable(abs)#判断是否可调用
Out[14]: True
In [15]: callable([])
Out[15]: False
    
In [16]: chr(98)#将ascii转换成字符
Out[16]: 'b'
In [17]: ord('b')#将字符转换成ascii
Out[17]: 98
 
#将字符串变成可执行代码
In [18]: code='print("Hello World")'
In [19]: compile(code,'','exec')
Out[19]: <code object <module> at 0x000001876578CC90, file "", line 1>
In [20]: c=compile(code,'','exec')
In [21]: exec(c)#也可以直接用exec(code)
Hello World

#查看一个对象有哪些方法
In [24]: print(dir(tuple()))
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

#返回商和余数
In [25]: divmod(5,2)
Out[25]: (2, 1)

#获取一个列表的下标和值
In [26]: l=['a','b','c']
In [27]: list(enumerate(l))
Out[27]: [(0, 'a'), (1, 'b'), (2, 'c')]

#过滤
In [28]: res=filter(lambda n:n>5,range(10))
In [29]: for i in res:
    ...:     print(i)
    ...:
6
7
8
9

#map,返回一个迭代器
In [34]: res=map(lambda n:n*2,range(5))

In [35]: for i in res:
    ...:     print(i)
    ...:
0
2
4
6
8

'''
reduce 函数可以按照给定的方法把输入参数中上序列缩减为单个的值,具体的做法如下:首先从序列中去除头两个元素并把它传递到那个二元函数中去,求出一个值,再把这个加到序列中循环求下一个值,直到最后一个值 。
'''
In [38]: import functools
In [39]: res=functools.reduce(lambda x,y:x+y,range(3))#res=0+1+2
In [40]: print(res)
3

#创建一个不可变集合
In [41]: a=frozenset(set([1,2,3]))
    
#返回一个程序所有变量字典
In [2]: print(globals())
    
#返回对象哈希值
In [4]: hash('hello')
Out[4]: 6258500955032307340

#查看帮助
In [9]: help(hex)
Help on built-in function hex in module builtins:
hex(number, /)
    Return the hexadecimal representation of an integer.
    >>> hex(12648430)
    '0xc0ffee'
    

#获取局部变量
In [10]: def test():
    ...:     loacl_var=1
    ...:     print(locals())
    ...:
In [11]: test()
{'loacl_var': 1}

#转换成八进制
In [12]: oct(10)
Out[12]: '0o12'

#2的四次方
In [13]: pow(2,4)
Out[13]: 16

#反转
In [19]: list(reversed([1,2,3]))
Out[19]: [3, 2, 1]

#保留小数
In [20]: round(1.3342,2)
Out[20]: 1.33
    
#字典排序
In [21]: a={1:2,-5:6,-7:3}
#按key排序
In [22]: print(sorted(a.items()))
[(-7, 3), (-5, 6), (1, 2)]
#按value排序
In [23]: print(sorted(a.items(),key=lambda x:x[1]))
[(1, 2), (-7, 3), (-5, 6)]

#组合
In [24]: a=[1,2,3]
In [25]: b=['a','b','c']
In [26]: for i in zip(a,b):
    ...:     print(i)
    ...:
(1, 'a')
(2, 'b')
(3, 'c')

#导入模块两种用法
In [27]: import os
In [28]: __import__('os')

没有更多推荐了,返回首页