python学习笔记-(八)装饰器、生成器&迭代器

本节课程内容概览:

1.装饰器

2.列表生成式&迭代器&生成器

3.json&pickle数据序列化

1. 装饰器

1.1 定义:

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

1.2 装饰器原则:

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

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

1.3 实现装饰器知识储备:

1.3.1 函数即“变量”

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

变量可以指向函数


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

>>> def func():

......    print("这是一个函数")

>>> print(func)

>>> func()

<function func at 0x0000000000D2CD08>

这是一个函数

#func()是函数调用,而func是函数本身。

#要获得函数调用结果,我们可以把结果赋值给变量:

>>> a = func()

这是一个函数

#函数本身赋值给变量

>>> a = func

<function func at 0x0000000000D2CD08>

#结论:函数本身也可以赋值给变量,即:变量可以指向函数。

#猜想:是否可以通过变量直接调用函数?

>>> a=func

>>> a()

这是一个函数

#说明变量指向了func函数本身,直接调用a()和func()完全相同

1.3.2 高阶函数

高阶函数:能接收函数作为参数的函数。

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

  1. 某一函数当做参数传入另一个函数中(用处:在不修改被装饰函数源代码的情况下为其添加功能)


    1

    2

    3

    4

    5

    6

    7

    >>> def bar():

        ......print(‘in the bar‘)

    >>> def foo(func):

        ......res=func()

        ......return res

    >>> foo(bar)

    in the bar

  2. 函数的返回值包含n个函数,n>0(用处:不修改函数调用方式)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    >>>def bar():

        ......time.sleep(3)

        ......print("in the bar")

    >>> def test2(func):

        ......print(func)

        ......return func

    >>> print(test2(bar))

    >>> bar = test2(bar)

    >>> bar()

    <function bar at 0x0000000000D6CD08>

    <function bar at 0x0000000000D6CD08>

    <function bar at 0x0000000000D6CD08>

    in the bar 

高阶函数示例

  • map()

map函数会根据提供的函数对指定序列做映射。

map函数的定义:
map(function, sequence[, sequence, ...]) -> list
通过定义可以看到,这个函数的第一个参数是一个函数,剩下的参数是一个或多个序列,返回值是一个集合。
function可以理解为是一个一对一或多对一函数,map的作用是以参数序列中的每一个元素调用function函数,返回包含每次function函数返回值的list。


1

2

3

4

5

>>> def f(x):

   ...... return x*x

>>> r = map(f,[1,2,3,4,5,6,7,8,9])

>>> print(list(r))

[149162536496481]

  • reduce()

reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。效果就是:


1

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)


1

2

3

4

5

>>> from functools import reduce

>>> def add(x, y):

    ......return + y

>>> print(reduce(add, [13579]))

25

  • filter()

filter函数会对指定序列执行过滤操作。
filter函数的定义:
filter(function or None, sequence) -> list, tuple, or string
function是一个谓词函数,接受一个参数,返回布尔值True或False。
filter函数会对序列参数sequence中的每个元素调用function函数,最后返回的结果包含调用结果为True的元素。
返回值的类型和参数sequence的类型相同。


1

2

3

4

>>> def is_odd(n):

        ...return % 2 == 1

>>> print(list(filter(is_odd, [1245691015])))

[15915]

  • sorted()

对列表内容进行正向排序,即可以保留原列表,又能得到已经排序好的列表;


1

2

3

4

5

>>> a = {6:2,8:0,1:4,-5:6,99:11,4:22}

>>> print(sorted(a.items())) #按key排序

[(-56), (14), (422), (62), (80), (9911)]

>>> print(sorted(a.items(),key=lambda x:x[1])) #按value排序

[(80), (62), (14), (-56), (9911), (422)]

1.3.3 嵌套函数

定义:在一个函数体内用def去声明一个新函数


1

2

3

4

5

6

7

8

>>> def foo():         #定义函数foo()

     ...m=3            #定义变量m=3;

     ...def bar():     #在foo内定义函数bar()

         ...n=4        #定义局部变量n=4

         ...print(m+n)  #m相当于函数bar()的全局变量

     ...bar()         #foo()函数内调用函数bar()

>>> foo()             #调用foo()函数

7  

1.3.4 装饰器

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

不带参数的装饰器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#装饰器

import time

def timer(func):

    def deco():

        start_time=time.time()

        func()                    #执行形参func()

        end_time=time.time()

        print("func runing time is %s"%(end_time-start_time))

    return deco                #返回函数deco的内存地址

def test1():

    print("in the test1")

    time.sleep(1)

 

test1 = timer(test1)            #重新赋值test1  此时test1=deco的内存地址

test1()                         #执行test1

###########打印输出###########

#in the test1

#func runing time is 1.0000572204589844

带固定参数的装饰器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#装饰器

import time

def timer(func):

    def deco(name):

        start_time=time.time()

        func(name)                    #执行形参func()

        end_time=time.time()

        print("func runing time is %s"%(end_time-start_time))

    return deco                #返回函数deco的内存地址

@timer                          #test1 = timer(test1)  test1=deco

def test1(name):

    print("in the test1 name %s"%name)

    time.sleep(1)

 

test1("cc")                         #执行test1

###########打印输出###########

#in the test1 name cc

#func runing time is 1.0000572204589844

带返回值的装饰器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#装饰器

import time

def timer(func):

    def deco(*args,**kwargs):

        start_time=time.time()

        res = func(*args,**kwargs)                    #执行形参func()

        end_time=time.time()

        print("func runing time is %s"%(end_time-start_time))

        return res

    return deco                #返回函数deco的内存地址

@timer                          #test1 = timer(test1)  test1=deco

def test1(name):

    print("in the test1 name %s"%name)

    time.sleep(1)

    return "return form test1"

 

print(test1("cc"))                  #执行test1

###########打印输出###########

#in the test1 name cc

#func runing time is 1.0000572204589844

#return form test1

通过以上我们会发现一个问题,选用的装饰器只能选择统一带形参或者统一不带形参;那么问题来了,我想要用一个装饰器,带形参的能调用,不带形参的也能调用,可不可以呢?

带不固定参数的装饰器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

# 装饰器

import time

def timer(func):

    def deco(*args, **kwargs):

        start_time = time.time()

        func(*args, **kwargs)  # 执行形参func()

        end_time = time.time()

        print("func runing time is %s" % (end_time - start_time))

    return deco  # 返回函数deco的内存地址

@timer  # test1 = timer(test1)  test1=deco

def test1(name):

    print("in the test1 name %s" % name)

    time.sleep(1)

@timer

def test2():

    print("in the test2 no name")

    time.sleep(1)

test1("cc")  # 执行test1

test2()        # 执行test2

###########打印输出###########

in the test1 name cc

func runing time is 1.0010571479797363

in the test2 no name

func runing time is 1.0000572204589844

终极版装饰器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

import time

user,passwd = ‘cc‘,‘123123‘

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:

                    print("User has passed authentication!")

                    res = func(*args,**kwargs)

                    print("---after authentication")

                    return res

                else:

                    exit("Invalid username or password!")

            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()

2. 迭代器&生成器

2.1 列表生成式

列表生成式,是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]

2.2 生成器

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

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

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


1

2

3

4

5

6

>>> L = [x * for in range(10)]

>>> print(L)

[0149162536496481]

>>> g = (x * for in range(10))

>>> print(g)

<generator object <genexpr> at 0x1022ef630>

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

我们可以直接打印出list的每一个元素;而generator里的每一个元素我们可以通过next()函数获取:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

>>> g = (x * for in range(10))

>>> print(g)

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

>>> print(next(g))

0

1

4

9

16

25

36

49

64

81

Traceback (most recent call last):

  File "XXX", line 32in <module>

    print(next(g))

StopIteration

上面我们可以看到,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,我们也可以通过for循环去调取元素值:


1

2

3

4

5

6

7

8

9

10

11

12

13

>>> g = (x * for in range(10))

>>> for in g:

>>>    print(i)

0

1

4

9

16

25

36

49

64

81

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


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#斐波拉契数列

def fib(max):

    n, a, b = 001

    while n < max:

        print(b)

        a, b = b, a + b

        += 1

    return ‘done‘

 

fib(5)

###########打印输出###########

# 1

# 1

# 2

# 3

# 5

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#斐波拉契数列

def fib(max):

    n, a, b = 001

    while n < max:

        yield(b)

        a, b = b, a + b

        += 1

    return ‘done‘

 

= fib(5)

print(f)

for in f:

    print(i)

###########打印输出###########

#<generator object fib at 0x000000000110A468>

#1

#1

#2

#3

#5

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

上面我们会发现:用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

def fib(max):

    n, a, b = 001

    while n < max:

        yield b

        a, b = b, a + b

        = + 1

    return ‘done‘

= fib(6)

while True:

    try:

        = next(g)

        print(‘g:‘, x)

    except StopIteration as e:

        print(‘Generator return value:‘, e.value)

        break

####打印输出####

# g: 1

# g: 1

# g: 2

# g: 3

# g: 5

# g: 8

# Generator return value: done

生成器的特点:

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

2)只记录当前位置;

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

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

import time

def consumer(name):

    print("%s 准备吃包子啦!" %name)

    while True:

       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer(name):

    = consumer(‘A‘)

    c2 = consumer(‘B‘)

    c.__next__()

    c2.__next__()

    print("老子开始准备做包子啦!")

    for in range(10):

        time.sleep(1)

        print("做了2个包子!")

        c.send(i)

        c2.send(i)

producer("cc")

2.3 迭代器

3.json&pickle数据序列化

时间: 2024-10-12 12:13:11

python学习笔记-(八)装饰器、生成器&迭代器的相关文章

Python学习之路-装饰器&生成器&正则表达式

装饰器 通俗的讲,装饰器就是在不改变源代码基础上,给源代码增加新功能. 不改变函数的源代码.调用方式.返回值等,给函数增加新功能. 经典案例:登录装饰器, def login_decorator(func):     def inner():         if USER_TEMP["status"] == False:             print("\033[31;1m用户未登录,请先登录\033[0m")             login_atm()

python学习笔记(五):装饰器、生成器、内置函数、json

这周学习了装饰器和生成器,写下博客,记录一下装饰器和生成器相关的内容. 一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面每个函数都加一个功能,用来统计每个函数的运行时间是多少,找出来运行比较慢的函数,来优化代码,就需要添加一个新的功能,来统计程序的运行时间,那这样的话,就得修改每个函数了,需要改代码,但是代码特别多,改完了公司倒闭了,这时候装饰

python学习笔记:装饰器2

python的装饰器本质是函数,为了不改变装饰目标函数内部代码而增加额外功能而存在 直接举例: import datetime def func_name(func):#定义一个装饰函数,接受一个函数对象作为参数(也就是被装饰的函数) def wrap():#包装函数 print("Function name:%s"%(func.__name__)) func() #执行目标函数 return wrap #返回包装函数 @func_name #等于 func_time = func_n

Python学习笔记012——装饰器

1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函数,函数装饰类,类装饰函数,类装饰类(两者不是一一对应关系,其实我也不知道他们之间是什么样的对应关系) 一般而言,主要应用的是函数装饰函数 1.3 装饰器本质 本质上,decorator就是一个返回函数的高阶函数. 在面向对象(OOP)的设计模式中,decorator被称为装饰模式.OOP

python学习笔记之装饰器(语法糖)

什么是装饰器 装饰器的知识点铺垫(函数即变量,高阶函数,嵌套函数) 不带参数的装饰器示例 带参数的装饰器示例 作业 一.什么是装饰器 本质上,装饰器就是返回一个函数的高阶函数.装饰器就是一个函数 装饰器的原则: 不修改被装饰对象的源代码 不修改被装饰对象的调用方式 二.装饰器涉及的知识点 函数即变量 高阶函数 嵌套函数 函数即变量: 在python中,一个变量首先被定义,分配内存空间,然后再使用. 以x=1,这个简单的赋值语句为例子.首先在内存中分配一个空间,x指向该内存空间,该内存空间内存入"

python学习笔记之——装饰器及对象

1.反射之__import__ 我们知道import语句是用来导入外部模块的,当然还有from...import...也可以,但是其实import实际上是使用builtin函数__import__来工作的.        在一些程序中,我们可以动态地去调用函数,如果我们知道模块的名称(字符串)的时候,我们可以很方便的使用动态调用. __import__(module_name[, globals[, locals[, fromlist]]]) #可选参数默认为globals(),locals()

Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化

本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用.概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能. 先定义一个基本的装饰器: ########## 基本装饰器 ########## def orter(func):    #定义装饰器     de

python学习笔记八——正则表达式

1.元字符 []-常用来指定一个字符集:[abc];[a-z] -元字符在字符集中不起作用:[akm$] -补集匹配不在区间范围内的字符:[^5] ^-匹配行首 $-匹配行尾 \-后可加不同字符以表示不同意义,也可用于取消所有元字符 \d 匹配任何十进制数,相当于[0-9] \D 匹配任何非数字字符,相当于[^0-9] \s 匹配任何空白字符,相当于[\t\n\r\f\v] \S 匹配任何非空白字符 \w 匹配任何字母数字字符 \W 匹配任何非字母数字字符 *-匹配前一个字符零次或多次 +-至少

python学习笔记4--装饰器、生成器、迭代器、匿名函数、内置方法、数据序列话

一.装饰器 1.意义:当需要给程序中某些函数新增某项功能时,为了避免直接修改函数源代码和函数调用方式,所以引入装饰器. 2.定义:装饰器用于装饰其他函数,就是为其他函数提供附加功能. 3.原则: 1)不修改被装饰的函数的源代码 2)不修改被装饰的函数的调用方式 4.装饰器储备知识: 1)函数即变量 2)高阶函数 a.把函数当做参数传递给另一个函数(在不修改被修饰函数源代码的情况下为该函数添加功能) b.返回值中包含函数名(在不修改被修饰的函数的调用方式的情况下为该函数添加功能) 3)嵌套函数:在

Python初探第二篇-装饰器和迭代器,生成器

一,装饰器 1,概念 装饰器就是给已有的模块添加新的功能,如登录验证功能,运行时间功能等.本身可以是任意可调用对象,被装饰者也可以是任意可调用对象. 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能 2,理论基础 要想实现装饰器的功能,我们需要三个理论基础:函数闭包+函数嵌套+高阶函数.我们通过为如下模块加入统计运行时间的装饰器来讲解如何使用 import time def test_func(): fo