zoukankan      html  css  js  c++  java
  • 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异常。

  • 相关阅读:
    EDA cheat sheet
    numpy.bincount()
    非负矩阵分解的两种方法简析
    Python列表解析和字典解析
    Pandas使用groupby()时是否会保留顺序?
    Reduce pandas memory size
    Understanding the Transform Function in Pandas
    What’s up with the Graph Laplacian
    如何在github上下载单个文件夹
    TCP回射服务器修订版(ubuntu 18.04)
  • 原文地址:https://www.cnblogs.com/liemng/p/7744551.html
Copyright © 2011-2022 走看看