Python 高级特性

279 阅读5分钟

切片

  • 我理解的切片主要是为了方便选用 list 或者 tuple 或者 str 等类型数据的部分元素。

  • 常见的对于单个元素的使用,直接通过索引选取即可,如选取 L 中的第 2 个元素 L[1]。

  • 对于指定范围内的索引操作,就显得效率很低,如选取L中的第 2 到第 4 个元素,L[1],L[2],L[3],这种方式太笨拙了,需要手动一个一个地选取,如果要选取一万个呢?难道要一个一个输入?

  • 切片通过指定索引皆就可以方便取出,选取L中的第 2 到第 4 个元素,L[1:4]。

  • 可以通过切片生成 list

      >>> L = list(range(100))
      >>> L
      [0, 1, 2, 3, ..., 99]
    
  • 倒数第一个元素的索引是 -1 ,正数第一个元素的索引是0

      >>> L[-2:]
      [98, 99]
    
  • 取某个范围内的元素

      >>> L[10:20]
      [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    
  • 每两个取一个

      >>> L[:10:2] #  “:”表示从 0 开始遍历
      [0, 2, 4, 6, 8]
    
  • tuple 也是一种 list,唯一区别是 tuple 不可变。因此, tuple 也可以用切片操作,只是操作的结果仍是 tuple:

      >>> (0, 1, 2, 3, 4, 5)[:3]
      (0, 1, 2)	
    
  • 字符串也可以看成是一种 list ,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串。

迭代

  • 如果给定一个 list 或 tuple 或者 str 或者 dict 等类型,我们可以通过 for 循环来遍历,这种遍历我们称为迭代(Iteration)。在 Python 中只要是可迭代对象,无论有无下标,都可以迭代。

  • 如何判断一个对象是可迭代对象呢?方法是通过 collections 模块的 Iterable 类型判断:

      >>> from collections import Iterable
      >>> isinstance('abc', Iterable) # str是否可迭代
      True
      >>> isinstance([1,2,3], Iterable) # list是否可迭代
      True
      >>> isinstance(123, Iterable) # 整数是否可迭代
      False
    
  • Python 内置的 enumerate 函数可以把一个 list 变成索引-元素对,这样就可以在 for 循环中同时迭代索引和元素本身。

      >>> for i, value in enumerate(['A', 'B', 'C']):
      ...		print(i, value)
      0 A
      1 B
      2 C
    
  • 默认情况下,dict 迭代的是 key。如果要迭代 value,可以用 for value in d.values(),如果要同时迭代 key 和value ,可以用 for k, v in d.items()。

  • 同时引用了两个变量,在 Python 里是很常见的

      >>> for x, y in [(1, 1), (2, 4), (3, 9)]:
      ...     print(x, y)
      ...
      1 1
      2 4
      3 9
    

列表生成式

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

  • 如求平方数,并做偶数判断

      >>> [x * x for x in range(1, 11) if x % 2 == 0]
      [4, 16, 36, 64, 100]
    
  • 使用两层循环

      >>> [m + n for m in 'ABC' for n in 'XYZ']
      ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
    
  • 列表生成式也可以使用两个变量来生成list

      >>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
      >>> [k + '=' + v for k, v in d.items()]
      ['y=B', 'x=A', 'z=C']
    

生成器

  • 受到内存限制,通过列表生成式生成的列表容量肯定是有限的。生成大量的元素时候,如果我们仅仅需要访问前面几个元素,那很多其他元素占用的空间都浪费了。所以,按照某种算法一边循环一边计算的机制,称为生成器:generator 。

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

      >>> L = [x * x for x in range(5)]
      >>> L
      [0, 1, 4, 9, 16]
      >>> g = (x * x for x in range(5))
      >>> g
      <generator object <genexpr> at 0x11fb91bf8>
    
  • 第二种创建方法是在函数中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是一个 generator。

  • 如果要一个一个打印出来,可以通过 next() 函数获得generator的下一个返回值,但是一般情况下是不会用的,因为一个一个输出,这种做法太笨拙了,而且容易报错。

      def odd():
          print('step 1')
          yield 1
          print('step 2')
          yield(3)
          print('step 3')
          yield(5)
          
      	    
      >>> o = odd()
      >>> next(o)
      step 1
      1
      >>> next(o)
      step 2
      3
      >>> next(o)
      step 3
      5
      >>> next(o)
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      StopIteration
    
  • 正确的方法是使用for循环,因为 generator 也是可迭代对象。并且不需要关心因为 next() 方法而引起的 StopIteration 的错误。

      def fib(max):
          n, a, b = 0, 0, 1
          while n < max:
              yield b
              a, b = b, a + b
              n = n + 1
          return 'done'
      >>> for n in fib(6):
      ...     print(n)
      ...
      1
      1
      2
      3
      5
      8
    
  • 如果想要拿到返回值,必须捕获 StopIteration 错误,返回值包含在 StopIteration 的value中。

      >>> 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循环的对象都是 Iterable 类型;

  • 凡是可作用于 next() 函数的对象都是 Iterator 类型,它们表示一个惰性计算的序列;

  • 集合数据类型如 list、dict、str 等是 Iterable 但不是 Iterator,不过可以通过 iter() 函数获得一个 Iterator 对象。

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

本文参考:

廖雪峰:www.liaoxuefeng.com/wiki/101695…

一分不嫌少,一分也有爱

支付宝

支付宝

微信

微信