Python(三)


高级特性

一、切片(Slice)

  1. 取一个list或tuple的部分元素的操作。

    # 法一:若截断N个元素,该方法不好用
    [L[0], L[1]]
    
    # 法二:循环
    r = []
    n = 4
    for i in range(n): # 0~n-1
        r.append(L[i])
    print(r)
    
    # 法三:切片操作符
    
    print(L[0:3]) # 0-2
    # 如果第一个索引是0,可以省略
    L[:3]
    
    L[1:3] # 从1开始,取2个元素
    
    # 同样支持倒数切片
    L[-2:] # 倒数第2个到最后
    L[-2:-1] # -2到-1,不含-1
    A = list(range(100)) #0-99的列表
    A[-10:] #后10个数
    A[:10] #前10个数
    A[10:20] #前11-20个数 10-19
    A[:10:2] # 前10个数,每两个取一个
    A[::5] #所有数,每5个取一个
    A[:] #只写[:]就可以原样复制一个list
  2. tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple

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

    'ABCDEFG'[:3] # 'ABC'
    'ABCDEFG'[1::2] # 'BDF'

二、迭代

  1. Python中用for...in...来完成迭代,可以通过for循环来遍历listtuple

  2. Python的for循环抽象程度要高于C的for循环,因为Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。

  3. 只要是可迭代对象,无论有无下标,都可以迭代,比如dict就可以迭代。

    d = {'a':1, 'b':2, 'c':3}
    for key in d: # dict默认迭代key
        print(key)
    for value in d.values(): # dict用values()可迭代访问value
        print(value)
    for k,v in d.items(): # dict同时迭代key和value
        print(k,'=',v)
    for ch in 'ABCDEFG' :
        print(ch)
  4. 如何判断一个对象是否是可迭代对象?可以通过collections.abc模块的Iterable类型判断。

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

    for i, value in enumerate(['A', 'B', 'C']):
        print(i, value)
    # Python中可以在for循环引用多个变量
    for x, y in [(1, 1), (2, 4), (3, 9)]:
        print(x, y)
    for x, y, z in [(1, 2, 3), (3, 4, 6), (5, 6, 9)]:
        print(x, y, z)    
  6. 迭代查找一个list中的最大值和最小值,并返回一个tuple

    li = [1,3,5,9,4,0,6]
    def fine_min_max(n):
        if len(n) == 0:
            return None, None
        else:
            min = max = li[0]
            for i in n :
                if i > max:
                    max = i
                if i < min:
                    min = i
            return (min, max)
    print(fine_min_max(li))
    
    def find2(L):
        L1 = L[:]
        L1 = sorted(L1)
        max = L1[-1]
        min = L1[0]
        return(max, min)
    print(find2(li))     

三、列表生成式

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

    list(range(1, 11)) # 生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    L = []
    for x in range(1,11): # 生成[1x1, 2x2, 3x3, ..., 10x10]
        L.append(x*x)
    # 循环繁琐,用列表生成器
    [x * x for x in range(1,11)]
    [x * x for x in range(1,11) if x % 2 == 0] # 筛选出偶数
    # 两层循环全排列
    [m + n for m in 'ABC' for n in 'XYZ']
    [j+k+l for j in '12345' for k in 'NUSQX' for l in '@#$%&']
  2. 运用列表生成式,列出当前目录下的所有文件和目录名。

    import os # 导入os模块
    [d for d in os.listdir('.')] # os.listdir可以列出文件和目录
  3. 列表生成器使用两个变量生成list。

    d = {'x':'A','y':'B','z':'C'}
    [k+'=' + v for k, v in d.items()]
  4. 把一个list中所有的字符串变成小写。

    str.lower()
    str.upper()
    L = ['HELLO', 'World', 'Apple', 'GOOD']
    [s.lower() for s in L]
    [s.upper() for s in L]
  5. 列表生成式中的if...else...使用。for后面的if是一个筛选条件,不能带else;for前面的部分是一个表达式,它必须根据x计算出一个结果,要带上else。

    [x for x in range(1, 11) if x % 2 == 0] # [2, 4, 6, 8, 10]
    [x if x % 2 == 0 else -x for x in range(1, 11)] #  [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]

四、生成器

  1. 一边循环一边计算的机制,称为生成器:generator。通过列表生成式,直接创建一个列表,但是受到内存限制,列表容量肯定是有限的。而且如果在一个占用内存很大的列表中含有很多元素,而只需访问前几个元素,那么绝大多数元素占用的空间就被浪费了。如果列表能够按照某种算法推算出后面的元素,就可以不必创建完整的list从而节省大量空间。

  2. 创建生成器的方法

    • 把一个列表生成式的[]改成(),就创建了一个generator。可以通过next()函数获得generator的下一个返回值,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

      g = (x * x for x in range(10))
      next(g)
      next(g)
      # 上面不断调用next(g),繁琐
      # 正解:用for循环
      for n in g:
          print(n)
      
      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)
      # 上面的函数和generator仅一步之遥。要把fib函数变成generator函数,只需要把print(b)改为yield b就可以了
      def fib2(max):
          n, a, b = 0, 0, 1
          while n < max:
              yield b
              a, b = b, a + b
              n = n + 1
          return 'done'
      f = fib2(6)

      在循环中不断调用yield就会不断中断,要给循环设置一个条件来退出循环;同样的把函数改成generator函数后,不用next()获取返回值而是直接用for循环迭代。

      for n in fib2(6):
          print(n)

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

      g = fib2(6)
      while True:
          try:
              x = next(g)
              print('g:', x)
          except StopIteration as e :
              print('Generator return value:', e.value)
              break
    • 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一个generator函数将返回一个generator。generator函数和普通函数的执行流程不一样。普通函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

      def odd():
          print('step 1')
          yield 1
          print('step 2')
          yield 2
          print('step 3')
          yield 3
      o = odd()
      next(o) # step 1
      next(o) # step 2
      next(o) # step 3
      next(odd()) # step 1
      next(odd()) # step 1
      next(odd()) # step 1
      # 原因在于odd()会创建一个新的generator对象,上述代码实际上创建了3个完全独立的generator,对3个generator分别调用next()当然每个都会返回第一个值。

      调用该generator函数时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值。

  3. 杨辉三角形

    def triangles():
        L = [1]
        yield L
        while True:
            L = [v+w for v,w in zip([0]+L,L+[0])]
            yield L
    #打印三角
    for i,row in enumerate(triangles()):
        print(row)
        if i>=10:
            break

五、迭代器

  1. 可以直接作用于for循环的对象统称为可迭代对象:Iterable;可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

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

    from collections.abc import Iterable
    isinstance([], Iterable)
    
    from collections.abc import Iterator
    isinstance([], Iterator)
    isinstance({}, Iterator)
    isinstance('abc', Iterator)
    
    isinstance(iter([]), Iterator)
    isinstance(iter('abc'), Iterator)
  3. Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。


文章作者: nusqx
文章链接: https://nusqx.top
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 nusqx !
评论
  目录