据廖雪峰python3教程----python学习第十天

简介:

列表生成式(List Comprehensions)



列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11))

1
2
>>>  list ( range ( 1 , 11 ))
[ 1 2 3 4 5 6 7 8 9 10 ]

生成[1x1,2x2,3x3,...,10x10] :

1
2
3
>>> L = []
>>>  for  in  range ( 1 , 11 ):
      L.append(x * x)

    

1
2
>>> L
[ 1 4 9 16 25 36 49 64 81 100 ]


另一种简化的写法:

1
2
>>> [x * for  in  range ( 1 , 11 )]
[ 1 4 9 16 25 36 49 64 81 100 ]

写列表生成式时,把要生成的元素 x*x 放到前面,后面跟for循环,就可以把list创建出来:

1
2
>>> [x * for  in  range ( 1 , 11 if  x % 2 = = 0 ]
[ 4 16 36 64 100 ]
1
2
>>> [m + for  in  'ABC'  for  in  'XYZ' ]
[ 'AX' 'AY' 'AZ' 'BX' 'BY' 'BZ' 'CX' 'CY' 'CZ' ]

列出当前目录下的文件:

1
2
3
>>>  import  os
>>> [d  for  in  os.listdir( '.' )]
[ 'DLLs' 'Doc' 'include' 'Lib' 'libs' 'LICENSE.txt' 'NEWS.txt' 'python.exe' 'pythonw.exe' 'README.txt' 'Scripts' 'students' 'tcl' 'Tools' ]


1
2
3
4
5
6
7
>>> d = { 'x' : 'A' , 'y' : 'B' , 'z' : 'C' }
>>>  for  k,v  in  d.items():
      print (k, '=' ,v)
      
=  A
=  C
=  B
1
2
>>> [k + '=' + for  k,v  in  d.items()]
[ 'x=A' 'z=C' 'y=B' ]


把一个list 中的字符窜变成小写

1
2
3
>>> l = [ 'Aadss' , 'Bsad' , 'Casd' , 'Dasd' ]
>>> [s.lower()  for  in  l]
[ 'aadss' 'bsad' 'casd' 'dasd' ]

1
2
3
4
5
6
7
8
9
10
11
12
L1  =  [ 'Hello' 'World' 18 'Apple' None ]
# 期待输出: ['hello', 'world', 'apple']
print (L2)
 
 
>>> L2 = [s.lower()  for  in  L1  if  isinstance (s, str )]
>>> L2
[ 'hello' 'world' '18' 'apple' ]
>>> [ isinstance (s, str and  s.lower()  or  for  in  l1]
[ 'hello' 'world' '18' 'apple' None ]
>>> [s.lower()  if  isinstance (s, str else  for  in  l1]
[ 'hello' 'world' '18' 'apple' None ]

生成器


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

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


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

1
2
3
4
5
6
>>> L = [x * for  in  range ( 10 )]
>>> L
[ 0 1 4 9 16 25 36 49 64 81 ]
>>> g = (x * for  in  range ( 10 ))>>> 
g
<generator  object  <genexpr> at  0x02C9FC10 >


创建 L 和 G 的区别仅在于最外层的 【】 和 () ,L 是一个 list ,而 G 是一个 generator。

要打印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
>>>  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  "<pyshell#53>" , line  1 in  <module>
       next (g)
StopIteration


当计算到最后一个元素时,跑出 StopIteration 错误。


当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> g = (x * for  in  range ( 10 ))
>>>  for  in  g:
      print (n)
          
0
1
4
9
16
25
36
49
64
81



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

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

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

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>>  def  fib( max ):
      n,a,b = 0 , 0 , 1
      while  n< max :
          print (b)
           a,b = b,a + b
          n = n + 1
      return  'done'
      
>>> fib( 6 )
1
1
2
3
5
8
'done'


要把 上面的 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 = 0 , 0 , 1
       while  n< max :          
                  yield  b   
                  a,b = b,a + b          
                  n = n + 1     
       return  'done'
       
>>> f  =  fib( 6 )
>>> f<generator  object  fib at  0x02C9FD28
>>>>  for  in  f:
      print (n)
 
 
1
1
2
3
5
8


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


举个简单的例子,定义一个generator,依次返回数字1,3,5:

1
2
3
4
5
6
7
>>>  def  odd():
      print ( 1 )
      yield  1
      print ( 2 )
      yield  3
      print ( 3 )
      yield  5

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> o = odd()
>>>  next (o)
1
1
>>>  next (odd())
1
1
>>>  next (o)
2
3
>>>  next (o)
3
5
>>>  next (o)Traceback (most recent call last):  
File  "<pyshell#104>" , line  1 in  <module>
     next (o)
StopIteration

可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(o)就报错。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> g = fib( 6 )
>>>  while  True :
      try :          
          x = 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


迭代器


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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
>>>  from  collections  import  Iterable
>>>  isinstance ([],Iterable)
True
>>>  isinstance ({},Iterable)
True
>>>  isinstance ( 'abc' ,Iterable)
True
>>>  isinstance ((x  for  in  range ( 10 )),Iterable)
True
>>>  isinstance ( 100 ,Iterable)
False



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

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

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

1
2
3
4
5
6
7
8
9
>>>  from  collections  import  Iterator 
>>>  isinstance ((x  for  in  range ( 10 )),Iterator)
True
>>>  isinstance ([],Iterator)
False
>>>  isinstance ({},Iterator)
False
>>>  isinstance ( 'asd' ,Iterator)
False


生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator。把listdictstrIterable变成Iterator可以使用iter()函数:

1
2
3
4
>>>  isinstance ( iter ([]),Iterator)
True
>>>  isinstance ( iter ({}),Iterator)
True


为什么list、dict、str、等数据类型不是Iterator?

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

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



高阶函数


一个最简单的高阶函数:

1
2
3
4
5
>>>  def  add(x,y,f):     
             return  f(x) + f(y)
             
>>> add( - 5 , 6 , abs )
11


map()/ reduce()


map()函数接受两个参数,一个是函数,一个是Iterable,map 将传入的函数依次作用到序列的每个元素,并把结果作为新的 Iterator 返回。


我们要把函数 f(x)= x2,要把这个函数作用在一个list[1,2,3,4,5,6,7,8,9]上,就可以用map()实现如下:

1
2
3
4
5
>>> r = map (f,[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ])
>>>  next (r)
1
>>>  list (r)
[ 4 9 16 25 36 49 64 81 ]
1
2
>>>  list ( map ( str ,[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]))
[ '1' '2' '3' '4' '5' '6' '7' '8' '9' ]



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

 

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


计算一个序列的和,就可以用到reduce实现:

1
2
3
>>>  from  functools  import  reduce
>>>  def  add(x,y):     
         return  x + y
1
2
>>>  reduce (add,[ 1 , 3 , 5 , 7 , 9 ])
25


当然也可以用python内建函数sum(),没必要用reduce。

1
2
>>>  sum ([ 1 , 3 , 5 , 7 , 9 ])
25


如果把序列[1,3,5,7,9]变换成整数13579.reduce就可以派上用场:

1
2
3
>>>  from  functools  import  reduce
>>>  def  fn(x,y):
      return  x * 10 + y
1
2
>>>  reduce (fn,[ 1 , 3 , 5 , 7 , 9 ])
13579


filter -----> Python内建的filter()函数用于过滤序列。


filter()也接受一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

eg:在一个list中,删掉偶数,只保留奇数:

1
2
>>>  def  is_odd(n):
      return  n % 2 = = 1
1
2
>>>  list ( filter (is_odd,[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]))
[ 1 3 5 7 9 ]

删除字符串中的空字符:

1
2
>>>  def  not_empty(s):
      return  and  s.strip()
1
2
>>>  list ( filter (not_empty,[ 'A' ,' ',' B ',None,' C ','    ']))
[ 'A' 'B' 'C' ]



回数是指从左向右读和从右向左读都是一样的数,例如12321909。请利用filter()滤掉非回数:

1
2
3
4
5
6
7
8
9
10
>>>  print ( list ( filter ( lambda  n: str (n)  = =  str (n)[:: - 1 ],  range ( 1 2000 ))))
#先把数字转换为字符串,然后翻转字符串,最后比较
[ 1 2 3 4 5 6 7 8 9 11 22 33 44 55 66 77 88 99 101
111 121 131 141 151 161 171 181 191 202 212 222 232 242 ,
252 262 272 282 292 303 313 323 333 343 353 363 373 383 ,
393 404 414 424 434 444 454 464 474 484 494 505 515 525 ,
535 545 555 565 575 585 595 606 616 626 636 646 656 666 ,
676 686 696 707 717 727 737 747 757 767 777 787 797 808 ,
818 828 838 848 858 868 878 888 898 909 919 929 939 949 ,
959 969 979 989 999 1001 1111 1221 1331 1441 1551 1661 1771 1881 1991 ]




本文转自 nw01f 51CTO博客,原文链接:http://blog.51cto.com/dearch/1761661,如需转载请自行联系原作者
相关文章
|
7月前
|
存储 Java 数据处理
(numpy)Python做数据处理必备框架!(一):认识numpy;从概念层面开始学习ndarray数组:形状、数组转置、数值范围、矩阵...
Numpy是什么? numpy是Python中科学计算的基础包。 它是一个Python库,提供多维数组对象、各种派生对象(例如掩码数组和矩阵)以及用于对数组进行快速操作的各种方法,包括数学、逻辑、形状操作、排序、选择、I/0 、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等等。 Numpy能做什么? numpy的部分功能如下: ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组 用于对整组数据进行快速运算的标准数学函数(无需编写循环)。 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。 线性代数、随机数生成以及傅里叶变换功能。 用于集成由C、C++
583 1
|
7月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
429 1
|
7月前
|
算法 Java Docker
(Python基础)新时代语言!一起学习Python吧!(三):IF条件判断和match匹配;Python中的循环:for...in、while循环;循环操作关键字;Python函数使用方法
IF 条件判断 使用if语句,对条件进行判断 true则执行代码块缩进语句 false则不执行代码块缩进语句,如果有else 或 elif 则进入相应的规则中执行
1190 1
|
7月前
|
索引 Python
Python 列表切片赋值教程:掌握 “移花接木” 式列表修改技巧
本文通过生动的“嫁接”比喻,讲解Python列表切片赋值操作。切片可修改原列表内容,实现头部、尾部或中间元素替换,支持不等长赋值,灵活实现列表结构更新。
332 1
|
7月前
|
存储 Java 索引
(Python基础)新时代语言!一起学习Python吧!(二):字符编码由来;Python字符串、字符串格式化;list集合和tuple元组区别
字符编码 我们要清楚,计算机最开始的表达都是由二进制而来 我们要想通过二进制来表示我们熟知的字符看看以下的变化 例如: 1 的二进制编码为 0000 0001 我们通过A这个字符,让其在计算机内部存储(现如今,A 字符在地址通常表示为65) 现在拿A举例: 在计算机内部 A字符,它本身表示为 65这个数,在计算机底层会转为二进制码 也意味着A字符在底层表示为 1000001 通过这样的字符表示进行转换,逐步发展为拥有127个字符的编码存储到计算机中,这个编码表也被称为ASCII编码。 但随时代变迁,ASCII编码逐渐暴露短板,全球有上百种语言,光是ASCII编码并不能够满足需求
317 4
|
C语言 Python
Python学习:内建属性、内建函数的教程
本文介绍了Python中的内建属性和内建函数。内建属性包括`__init__`、`__new__`、`__class__`等,通过`dir()`函数可以查看类的所有内建属性。内建函数如`range`、`map`、`filter`、`reduce`和`sorted`等,分别用于生成序列、映射操作、过滤操作、累积计算和排序。其中,`reduce`在Python 3中需从`functools`模块导入。示例代码展示了这些特性和函数的具体用法及注意事项。
375 2
|
存储 算法 API
Python学习五:函数、参数(必选、可选、可变)、变量、lambda表达式、内置函数总结、案例
这篇文章是关于Python函数、参数、变量、lambda表达式、内置函数的详细总结,包含了基础知识点和相关作业练习。
274 0
|
API Python
Python学习日记(二:函数和逻辑操作)
Python中的函数和逻辑操作至关重要。函数包括可变和不可变参数。
225 2
|
存储 Python Windows
【Python学习篇】Python实验小练习——函数(十)
【Python学习篇】Python实验小练习——函数(十)
195 1

推荐镜像

更多