Python高级特性

Python高级特性  切片  迭代  列表生成式  生成器

一、切片

  切片:数据的分段切割。如下定义一个列表然后获取前五位数据。

  格式:对象[起始位置:需要读取的数量:间隔]

 1 >>> olist = list(range(10))
 2 >>>
 3 >>> olist
 4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 5 >>> olist[0:5]
 6 [0, 1, 2, 3, 4]
 7 >>>
 8 >>> olist[0:5:2]
 9 [0, 2, 4]
10 >>>

  定义并且声明一个olist列表对象,然后通过切片返回一个新的列表对象。其实位置默认是0,并且可以省略。如olist[:5]。间隔默认是1。

  range是一个系统函数,返回一个特定的有序的自然数,默认从零开始。

 1  1 >>> help('range')
 2  2 Help on class range in module builtins:
 3  3 
 4  4 class range(object)
 5  5  |  range(stop) -> range object
 6  6  |  range(start, stop[, step]) -> range object
 7  7  |
 8  8  |  Return an object that produces a sequence of integers from start (inclusive)
 9  9  |  to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
10 10  |  start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
11 11  |  These are exactly the valid indices for a list of 4 elements.
12 12  |  When step is given, it specifies the increment (or decrement).
13 13  |

  对于列表而言支持反向读取,如olist[-1],获取最后一条数据。那么对于切片slice而言是否支持???

1 >>> olist = list(range(10))
2 >>> olist[-2: -1]
3 [8]
4 >>> olist[-8: -1]
5 [2, 3, 4, 5, 6, 7, 8]
6 >>>
7 >>> olist[-1]
8 9
9 >>>

   从测试结果来看是支持反向切片。但是反向之后切记最后一位角标是-1。

  之上的测试是对列表List进行的,那么我接下来看下对于String和tuple是否也适用!!!

1 >>> oTuple = (1,2,3,4,5,6)
2 >>> oTuple[0:5:2]
3 (1, 3, 5)
4 >>>
5 >>>
6 >>> str = 'abcdefg'
7 >>> str[0:5:2]
8 'ace'
9 >>>

   从执行结果来看和我们的猜想是完全一致的。到这里可能有人会问了那么既然元组和列表及字符串都可以这么用,那么集合set和字典dict那???其实是不可以的,因为对于集合和dict而言是没有下标的。

 1 >>> oset = set([1,2,3])
 2 >>> oset
 3 {1, 2, 3}
 4 >>>
 5 >>> oset[0:2]
 6 Traceback (most recent call last):
 7   File "<stdin>", line 1, in <module>
 8 TypeError: 'set' object is not subscriptable
 9 >>>
10 >>> odict = {'a:1','b:2','c:3'}
11 >>> odict[0:2]
12 Traceback (most recent call last):
13   File "<stdin>", line 1, in <module>
14 TypeError: 'set' object is not subscriptable
15 >>>

 二、迭代

  迭代其实就是对集合<List, Tuple, dict, set等>的遍历。这里仅仅是列举了一些常见的集合,其实这里只要是Iterable的子类都可以使用迭代器来实现遍历。判断如下: 

 1 >>> oSet = set([1,3,4,5,])
 2 >>> oSet
 3 {1, 3, 4, 5}
 4 >>> for item in oSet:
 5 ...     print(item)
 6 ...
 7 1
 8 3
 9 4
10 5
11 >>> isinstance(oSet, Iterable)
12 True
13 >>> index = 2
14 >>>
15 >>> isinstance(index, Iterable)
16 False
17 >>>

   上述采用的是系统函数isinstance()完成对对象的判断,判断给对象是否是Iterable的子类。按照规定只要是Iterable的子类就可以直接使用for循环实现迭代。

  在使用isinstance方法时候判断是否是Iterable子类的时候,请记住请优先执行导入Iterable操作,默认isinstance方法是在collections类中。故而执行应该在文件头部增加from collections import Iterable。

  这里重点讲解下迭代器如何在迭代中获取index角标和dict遍历。

1 >>> olist = ['A','B','C','E']
2 >>> for index, item in enumerate(olist):
3 ...  print(index, ' : ', item)
4 ...
5 0  :  A
6 1  :  B
7 2  :  C
8 3  :  E
9 >>>

  该出使用的系统方法enumerate(),该方法可以实现把集合变成角标-元素。

  字典集合遍历方式一获取key:

 1 >>> oDict = {'a:1','b:2','c:3'}
 2 >>>
 3 >>> oDict
 4 {'b:2', 'a:1', 'c:3'}
 5 >>>
 6 >>> for item in oDict:
 7 ...     print(item)
 8 ...
 9 b:2
10 a:1
11 c:3
12 >>>

  字典集合遍历方式二获取value:

 1 >>> oDict = {'a':1,'b':2,'c':3}
 2 >>> oDict
 3 {'a': 1, 'b': 2, 'c': 3}
 4 >>> for value in oDict.values():
 5 ...     print(value)
 6 ...
 7 1
 8 2
 9 3
10 >>>

  字典集合遍历方式三获取key-value:

1 >>> oDict = {'a':1,'b':2,'c':3}
2 >>> oDict
3 {'a': 1, 'b': 2, 'c': 3}
4 >>> for k, v in oDict.items():
5 ...     print(k, " = ", v)
6 ...
7 a  =  1
8 b  =  2
9 c  =  3

三、列表生成式

  列表生成式:顾名思义就是生成对应的列表。场景如定义一个自然数1-100放入到指定的集合等。使用方式就是使用系统函数range,前边已经关于这个方法有过说明,这里就直接跳过。

  range仅仅是获取有序的自然数,假如我们需求有天发生了变化,如获取1-100的平分数,然后放到指定集合,当下range就有点尴尬了。不过好在Python为我们做了这样的定制开发。一起走进代码。

1 >>> oList = list(range(1,5))
2 >>> oList
3 [1, 2, 3, 4]
4 >>>
5 >>> nList = [x * x for x in range(1,5)]
6 >>> nList
7 [1, 4, 9, 16]
8 >>>

  第一行到第四行是获取自然数1-5存放于指定集合。第五行到第七行是对自然数1-5开平方然后存放于指定集合中。

  上述内容细节还可以进一步优化,加入仅仅保留偶数的平方,那么我们可以这么干。

1 >>> nList = [x * x for x in range(1,5) if x % 2 == 0]
2 >>> nList
3 [4, 16]
4 >>>

  列表生成式实现排列组合,666。。。<又名for循环嵌套>

1 >>> nList = [m + n for m in 'ADC' for n in 'MVP']
2 >>> nList
3 ['AM', 'AV', 'AP', 'DM', 'DV', 'DP', 'CM', 'CV', 'CP']
4 >>>

  这里其实就是嵌套for循环。如何不理解可以换个方式去看。 

1 >>> nList = []
2 >>> for m in 'ADC':
3 ...     for n in 'MVP':
4 ...             nList.append(m + n)
5 ...
6 >>> nList
7 ['AM', 'AV', 'AP', 'DM', 'DV', 'DP', 'CM', 'CV', 'CP']
8 >>>

 

  看着这些代码是不是更好理解怎么肥事。

四、生成器<Generator>

  生成器可以理解为对生成器的优化,这里优化主要是说在内存上的优化。举例子来说,假如需要数据有序的自然数零到一万存放于列表中,这时可以有两种方式,一是直接生成一刀一万的自然数放到内存中。另一种是用到那个就读那个到内存中。很显然第二种方式在内存这块要优于第一种,这就是我们要说的生成器。

  生成器声明格式和列表生成式大致相同,区别在于外围中括号和括号去别。看下生成器在代码中的使用,以及数据获取、

 1 >>> oGenerator = (n for n in range(1, 5))
 2 >>> oGenerator
 3 <generator object <genexpr> at 0x0000000002D60BF8>
 4 >>> next(oGenerator)
 5 1
 6 >>> next(oGenerator)
 7 2
 8 >>> next(oGenerator)
 9 3
10 >>> next(oGenerator)
11 4
12 >>> next(oGenerator)
13 Traceback (most recent call last):
14   File "<stdin>", line 1, in <module>
15 StopIteration
16 >>>

   第一行创建了一个生成器对象。直接该对象。返回了个这'<generator object <genexpr> at 0x0000000002D60BF8>',What???一脸懵逼。。。好吧暂且把它看做是python对一个对象的表达形式吧,就如同java中对象打印一样,获得是对应的hashcode值。    

  next()读取生成器中的数据的系统方法。该方法获取生成器中的数据遇到yield则执行数据返回。yield的功能等同于return,不同点在于yield挂机程序执行,并不会结束方法执行。

  这里对于方法next()使用不是绝对安全的,在地十二行处调用next()方法抛出了一个StopIteration异常,意思就是已经是最后一个数据了,没有更多数据了。那么怎么避免这个问题那???也许有些人想到了for循环,那么对于这个generator是否也适用???我们有我们的办法,isinstance()。想到了就去做。

1 >>> isinstance(oGenerator, Iterable)
2 True
3 >>>

  如上代码证明了Generator生成器其实也是Iterable的子类,那么这就简单了。

>>> oGenerator = (n for n in range(1, 5))
>>> for item in oGenerator:
...     print(item)
...
1
2
3
4
>>>

  到了这里我们也就发现了正确的读取生成器Generator中数据的方法。

  下一步就是如何自定义生成器????

 1 >>> def step():
 2 ...  print('step 1')
 3 ...  yield 1
 4 ...  print('step 2')
 5 ...  yield 6
 6 ...  print('step 3')
 7 ...  yield 12
 8 ...
 9 >>>
10 >>> g = step()
11 >>> g
12 <generator object step at 0x00000000024D2EB8>
13 >>> next(g)
14 step 1
15 1
16 >>> next(g)
17 step 2
18 6
19 >>> next(g)
20 step 3
21 12
22 >>>

  自定义Generator适用关键字yield,方法在执行next()过程中,每当遇到yield都会直接返回,但是方法并未真正结束,仅仅是暂停。当你再一次调用next()则会在当前暂停出继续执行,知道执行完全结束,最后抛出StopIteration异常。

  这里演示过程中采用了next()方法遍历自定义的Generator,在真正使用过程中尽量使用for循环,因为for内部会处理StopIteration异常。

 

posted @ 2017-10-28 15:50  冒泡的章鱼  阅读(1310)  评论(0编辑  收藏  举报