函数—函数进阶

Posted wqq0723

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数—函数进阶相关的知识,希望对你有一定的参考价值。

                                      函数—函数进阶(二)

  •  函数—函数进阶—列表生成式

 1 #列表回顾
 2 name = [2,5,7,9,4]
 3 print(name)
 4 for i in name:
 5     print(i)
 6 #结果为:
 7 # [2, 5, 7, 9, 4]
 8 # 2
 9 # 5
10 # 7
11 # 9
12 # 4
13 
14 #枚举
15 for index,i in enumerate(name):
16     print(index,i)
17 #结果为:
18 # 0 2
19 # 1 5
20 # 2 7
21 # 3 9
22 # 4 4
23 
24 
25 #问题:把列表里的每个值加1
26 #二逼青年版
27 a = [0,1,2,3,4,5,6,7,8,9]
28 print(a)               #结果为:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
29 b = []
30 for i in a:b.append(i+1)
31 print(b)                 #结果为:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
32 a = b             #将b列表赋值给a列表
33 print(a)               #结果为:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
34 
35 #普通青年版
36 a = [0,1,2,3,4,5,6,7,8,9]
37 print(a)               #结果为:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
38 for index,i in enumerate(a):        #通过索引值增加
39     a[index] += 1
40 print(a)               #结果为:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
41 
42 #文艺青年版
43 a = [0,1,2,3,4,5,6,7,8,9]
44 print(a)               #结果为:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
45 a = map(lambda x:x+1,a)
46 print(a)              #结果为:<map object at 0x000001853C723FD0>
47 for i in a:
48    print(i)           #结果为:1,2,3,4,5,6,7,8,9,10
49 
50 
51 #装逼青年版(列表生成式)
52 a = list(range(10))
53 print(a)               #结果为:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
54 a = [i+1 for i in a]        #列表生成式
55 print(a)              #结果为:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
56 
57 a = [i for i in a]
58 print(a)              #结果为:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
59 
60 a = [i*i for i in a]
61 print(a)              #结果为:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
62 
63 #三元运算
64 b = list(range(10))
65 print(b)               #结果为:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
66 b = [i if i < 5 else i*i for i in b]
67 print(b)              #结果为:[0, 1, 2, 3, 4, 25, 36, 49, 64, 81]
68 
69 
70 #既可以循环元组,字典,还可以循环字符串
71 c = alexli
72 c = [i for i in c]
73 print(c)             #结果为:[‘a‘, ‘l‘, ‘e‘, ‘x‘, ‘l‘, ‘i‘]
74 
75 #字符串可以相加
76 c = alexli
77 c = [i+w for i in c]
78 print(c)             #结果为:[‘aw‘, ‘lw‘, ‘ew‘, ‘xw‘, ‘lw‘, ‘iw‘]
79 
80 #字符串可以相乘
81 c = alexli
82 c = [i*2 for i in c]
83 print(c)             #结果为:[‘aa‘, ‘ll‘, ‘ee‘, ‘xx‘, ‘ll‘, ‘ii‘]

 

  •  函数—函数进阶—生成器

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

       如果列表元素可以按照某种算法推算出来,可以在循环的过程中不断推算出后续的元素。这样就不必创建完整的list,从而节省大量的空间。

      在Python中,这种一边循环一边计算的机制,称为生成器:generator。

      

 1 #创建一个包含1000个元素的列表
 2 a = [i for i in range(1000)]
 3 print(a)
 4 
 5 #生成器(把一个列表生成式的[]改成(),就创建了一个generator )
 6 a2 = (i for i in range(1000))
 7 print(a2)                     #结果为:<generator object <genexpr> at 0x000002B27DF5A048>
 8 print(next(a2))               #结果为:0
 9 print(next(a2))               #结果为:1
10 print(next(a2))               #结果为:2
11 print(next(a2))               #结果为:3
12 print(next(a2))               #结果为:4
13 print(next(a2))               #结果为:5
14 print(next(a2))               #结果为:6
15 print(next(a2))               #结果为:7
16 print(next(a2))               #结果为:8
17 #停止
18 print(a2)                     #结果为:<generator object <genexpr> at 0x0000018F10C2A048>
19 #继续
20 print(next(a2))               #结果为:9
21 print(next(a2))               #结果为:10
22 print(next(a2))               #结果为:11
23 print(next(a2))               #结果为:12
24 
25 #小结:
26 #使用next(a2)方法
27 #一个个的打印,可以打印1000个,不占用内存空间。
28 # 这种方法只能够向前,不能够后退。
29 #到最后的时候,会报错
30 
31 a = (i for i in range(5))
32 print(next(a))          #结果为:0
33 print(next(a))          #结果为:1
34 print(next(a))          #结果为:2
35 print(next(a))          #结果为:3
36 print(next(a))          #结果为:4
37 print(next(a))          #结果为:StopIteration

 

  •  函数—函数进阶—斐波那契

1 #这种不断调用next(a)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象
2 #for 循环
3 a = (i for i in range(10))
4 for i in a:
5     print(i)                 #结果为:0  1  2  3  4  5  6  7  8  9
6 
7 #while 语句
8 while True:
9     print(next(a))          #结果为:0  1  2  3  4  5  6  7  8  9    但是会报错
 1 #range就是生成器的原理生成的
 2 ‘‘‘
 3 range在Python3与Python2中range的区别:
 4 Python3(生成器):
 5 E:Python>python3
 6 Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.19
 7 14 64 bit (AMD64)] on win32
 8 Type "help", "copyright", "credits" or "license" for more informa
 9 tion.
10 >>> range(100)
11 range(0, 100)      不会占用内存
12 
13 Python2:
14 E:Python>python2
15 Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.
16 1500 64 bit (AMD64)] on win32
17 Type "help", "copyright", "credits" or "license" for more informa
18 tion.
19 >>> range(10)
20 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
21 
22 在Python2中,如何用生成器方式表示range:
23 E:Python>python2
24 Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit
25 (AMD64)] on win32
26 Type "help", "copyright", "credits" or "license" for more information.
27 >>> xrange(1000000)
28 xrange(1000000)
29 
30 总结:Python2中的xrange(100000)等价于Python3中的range(100000)
31 ‘‘‘
 1 #著名的斐波拉契数列(Fibonacci):除第一个和第二个数外,任意一个数都可由前两个数相加得到:
 2 #1, 1, 2, 3, 5, 8, 13, 21, 34, ...
 3 #斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
 4 
 5 a,b = 1,2
 6 print(a)               #结果为:1
 7 print(b)               #结果为:2
 8 
 9 #斐波那契数列
10 def fib(max):
11     n, a, b = 0, 0, 1              #n=0 a=0 b=1
12     while n < max:
13         print(b)
14         a, b = b, a+b              #将b的值赋值给a,同时将a+b的值赋值给b
15         n = n + 1
16     return done
17 fib(15)                            #结果为:1 1 2 3 5 8 13 21 34 55 89 144 233 377 610
18 
19 # 赋值语句:  a, b = b, a + b
20 # 相当于:
21 # t = a + b
22 # a = b
23 # b = t
24 
25 
26 #生成器(yield)
27 def fib(max):
28     n, a, b = 0, 0, 1
29     while n < max:
30         print(before yield)
31         yield b                        #yield的作用:把函数的执行过程冻结在这一步并且把b的值返回给外面的next()方法
32         print(b)
33         a, b = b, a+b
34         n = n + 1
35     return done
36 
37 f = fib(15)                            #将功能转换成一个“生成器”
38 next(f)
39 next(f)
40 next(f)
41 next(f)
42 #结果为:
43 # before yield
44 # 1
45 # before yield
46 # 1
47 # before yield
48 # 2
49 # before yield
50 
51 #小结:
52 # yield 把函数的执行过程冻结在了这一步
53 # 此时可以把 b 的值,返回给外面的 next() 方法
54 # 函数名添加(),内部代码不执行,只是生成一个生成器对象

 

  •  函数—函数进阶—生成器调用方法

 

 1 #生成器
 2 a = (i for i in range(10))
 3 print(a)                      #结果为:<generator object <genexpr> at 0x0000022D719CA408>
 4 print(next(a))                #结果为:0
 5 print(next(a))                #结果为:1
 6 print(next(a))                #结果为:2
 7 print(next(a))                #结果为:3
 8 print(next(a))                #结果为:4
 9 print(next(a))                #结果为:5
10 
11 #while
12 a = (i for i in range(10))
13 while True:
14     print(next(a))
15 
16 #for 循环
17 a = (i for i in range(10))
18 for i in a:
19     print(i)
20 ‘‘‘
21 总结:
22 Python2:
23    range = list
24    xrange = 生成器
25    
26 Python3:
27    range = 生成器
28    xrange   没有
29 ‘‘‘

 

 

 

  •  函数—函数进阶—函数写生成器

 1 ‘‘‘
 2 生成器的创建方式:
 3   1、列表 生成 式 ()  只能写一个三元运算
 4   2、函数
 5 ‘‘‘
 6 #函数
 7 def range2(n):
 8     count = 0
 9     while count < n:
10         print(count)
11         count += 1
12 range2(10)                        #函数内部执行
13 
14 
15 #将函数变为生成器
16 def range2(n):
17     count = 0
18     while count < n:
19         print(count,count)
20         count += 1
21         yield count     #类似return, yield 使程序冻结,next 解冻
22 range2(10)               #因为 yield 没有返回结果
23 print(range2(10))                   #结果为:<generator object range2 at 0x0000024840A7A408>
24 new_range = range2(10)
25 r1 = next(new_range)                #结果为:count 0
26 print(r1)                           #结果为:1
27 print(干点别的事...)            #结果为:干点别的事...
28 r2 = next(new_range)                #结果为:count 2
29 print(r2)                           #结果为:2
30 
31 # 除了使用next()方法外,还可以使用new_range.__next__()
32 new_range.__next__()                #结果为:count 2
33 
34 ‘‘‘
35 小结
36 yield vs return
37 return 返回并且中止function
38 yield 返回数据并且冻结当前的执行过程
39 next 唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield
40 ‘‘‘
41 ‘‘‘
42 生成器:
43 之前的函数从调用起,就必须等待执行结果结束,并返回计算值
44 生成器可以把函数整个运行过程中的结果,返回至外面
45 yield,是暂停的意思
46 ‘‘‘

 

 

  •  函数—函数进阶—生成器send方法

 1 # def range2(n):
 2 #     count = 0
 3 #     while count < n:
 4 #         print(‘count‘,count)
 5 #         count += 1
 6 #         yield count          #类似于return,yield使程序冻结,next才解冻
 7 #     print(‘-------‘)
 8 #     return 333333
 9 #
10 # new_range = range2(3)
11 #
12 # n1 = next(new_range)
13 # n2 = next(new_range)
14 # n3 = next(new_range)
15 # n4 = next(new_range)
16 # print(n3)
17 # print(n4)
18 
19 ‘‘‘
20 函数有了yield之后:
21  1、函数名称加(),就得到了一个生成器
22  2、return 在生成器里代表生成器的终止,直接报错
23 ‘‘‘
24 
25 def range2(n):
26     count = 0
27     while count < n:
28         print(count,count)
29         count += 1
30         sign = yield count               #类似于return,yield使程序冻结,next才解冻
31         if sign == stop:
32              print(--sign,sign)
33              break
34     return 333333              #函数中有了yield 就不会被执行了
35     
36 new_range = range2(3)
37 n1 = next(new_range)
38 
39 new_range.send(stop)
40 
41 #send方法的作用:
42 #1、唤醒并继续执行,next方法只能唤醒
43 #2、发送一个信息到生成器内部

 

  •  函数—函数进阶—迭代器

 

 1 ‘‘‘
 2 我们已经知道,可以直接作用于for循环的数据类型有以下几种:
 3 
 4 一类是集合数据类型,如list、tuple、dict、set、str等;
 5 
 6 一类是generator,包括生成器和带yield的generator function。
 7 
 8 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
 9 ‘‘‘
10 #可以使用isinstance()判断一个对象是否是Iterable对象
11 from collections import Iterable
12 print(isinstance(abc,Iterable))           #结果为:True
13 print(isinstance(100,Iterable))              #结果为:False
14 print(isinstance([],Iterable))               #结果为:True
15 print(isinstance({ },Iterable))              #结果为:True
16 print(isinstance((x for x in range(10)),Iterable))      #结果为:True
17 
18 #生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
19 #可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
20 
21 #可以使用isinstance()判断一个对象是否是Iterator对象:
22 from collections import Iterator
23 print(isinstance((x for x in range(10)), Iterator))             #结果为:True
24 print(isinstance([], Iterator))                           #结果为:False
25 print(isinstance({}, Iterator))                           #结果为:False
26 print(isinstance(abc, Iterator))                       #结果为:False
27 
28 #生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
29 
30 #但是可以把list、dict、str等Iterable变成Iterator,使用iter()函数:
31 print(isinstance(iter([]), Iterator))                      #结果为:True
32 print(isinstance(iter(abc), Iterator))                  #结果为:True
33 
34 ‘‘‘
35 那么,为什么list、dict、str等数据类型不是Iterator?
36 
37 因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
38 可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据。
39 所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
40 Iterator甚至可以表示一个无限大的数据流,例如,全体自然数。而使用list是永远不可能存储全体自然数的。
41 
42 在当前的阶段,generator与Iterator基本是一致的。
43 
44 小结:
45 1、凡是可作用于for循环的对象都是Iterable类型
46 2、凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列
47 3、集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
48 4、Python3的for循环本质上就是通过不断调用next()函数实现的,例如:
49 
50 for x in [1, 2, 3, 4, 5]:
51     pass
52 等价于:
53 it = iter([1, 2, 3, 4, 5])
54 
55 # 循环
56 while True:
57     try:
58         x = next(it)
59     except StopIteration:
60         break
61 ‘‘‘

 

以上是关于函数—函数进阶的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段8——声明函数

python进阶第1篇 函数入门

八 函数进阶

JavaScript函数函数进阶作用域及预解析

在 Visual Studio 中创建构造函数的代码片段或快捷方式

使用从循环内的代码片段中提取的函数避免代码冗余/计算开销