美文网首页
Python高级特性

Python高级特性

作者: 夏海峰 | 来源:发表于2020-04-06 15:43 被阅读0次

在Python中,代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。一行代码能实现的功能,决不写5行代码。请始终牢记,代码越少,开发效率越高。Python中有非常多实用的高级特性,可以帮助我们实现代码的简洁,本篇逐一介绍它们——切片、列表生成式、Generator生成器、迭代器

1、切片 Slice

对经常需要获取指定索引范围的操作,用循环十分繁琐,Python提供了切片(Slice)操作符来实现范围取值。list、tuple、字符串,都支持切片操作。

(1)list 切片:对 list 进行各种切片操作。

L = list(range(100))
print('创建0-100的数列:', L)
l1 = L[:10] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print('切片:取前10个元素', l1)

l2 = L[4:8] # [4, 5, 6, 7]
print('切片:取4-8位置的元素', l2)

l3 = L[-1] # 99
print('切片:取最后一个元素', l3)

l4 = L[-10:] # [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
print('切片:取后10个元素', l4)

l5 = L[:10:2] # [0, 2, 4, 6, 8]
print('切片:前10个元素,每两个取一个', l5)

l6 = L[::20] # [0, 20, 40, 60, 80]
print('切片:所有元素,每20个取一个', l6)

l7 = L[:]  # 复制L
print('切片:复制L', l7)

(2)tuple 切片:tuple类型,是不可变list,它也支持切片操作,返回的结果仍是tuple类型。

T = (0,1,2,3,4,5,6,7,8,9)

t1 = T[:3]  # (0, 1, 2)
print('切片:取前3个元素', t1)

t2 = T[::2]  # (0, 2, 4, 6, 8)
print('切片:所有元素,每两个取一个', t2)

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

S = 'ABCDEFG'

s1 = S[:]  # 复制字符串
print('切片:复制字符串', s1)

s2 = S[-5:]  # 取后5个字符 CDEFG
print('切片:取后5个字符', s2)

2、迭代(for...in 数据遍历)

  • 什么是迭代? 如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
  • Python中,使用 for...in 来遍历一切可迭代的对象,比如 list、tuple、dict、字符串等。

(1)如何判断一个对象是否可迭代呢?方法是使用collections模块的Iterable类型来判断。

from collections.abc import Iterable

b1 = isinstance('abc', Iterable) # True
b2 = isinstance([1,2,3], Iterable) # True
b3 = isinstance((1,2,3), Iterable) # True
b4 = isinstance({'a':1,'b':2,'c':3}, Iterable) # True

print(b1, b2, b3, b4)
# 证明字符串、list、tuple和dict都是可迭代的、可遍历的。

(2)遍历 dict

  • dict的存储不是按照list方式的顺序排列,所以,每次迭代出的结果顺序很可能不一样。
d = {'a':1, 'b':2, 'c':3}
for k in d.keys():
    print('遍历dict:key', k)

for v in d.values():
    print('遍历dict:value', v)

for k,v in d.items():
    print('同时遍历:key - value', k, v)

(3)遍历 list

l = ['apple', 'bus', 'car', 'duck']

for v in l:
    print('遍历list:', v)
  • 如何在遍历时获取到list的下标索引号?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身了。
L = enumerate(l)
for i,v in L:
    print('索引:',i, ',元素:', v)
# 索引: 0 ,元素: apple
# 索引: 1 ,元素: bus
# 索引: 2 ,元素: car
# 索引: 3 ,元素: duck
# 遍历元素中的两个变量
for x,y in [(1,1),(2,2),(3,3),(4,4)]:
    print('(x,y):', x, y)

(4)遍历 tuple

for x,y in ((1,2),(2,4),(3,6),(4,8)):
    print('(x,y):', x, y)

for i,v in enumerate(((1,2),(2,4),(3,6),(4,8))):
    print('遍历tuple', i, v)

(5)遍历字符串

for v in 'hello world':
    print('遍历字符串:', v)

for i,v in enumerate('hello world'):
    print('遍历字符串:', i, v)

3、列表生成式

  • 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的方式。
L1 = list(range(11,21))
print('L1:', L1)
# L1: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
L2 = [x*x for x in range(1,11)]
print('L2:', L2)
# L2: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
  • for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方。
L3 = [x*x for x in range(1,11) if x%2==0]
print('L3:', L3)
# L3: [4, 16, 36, 64, 100]
  • 使用两层循环,生成排列。更多层的循环用得较少。
L4 = [m+n for m in 'ABCD' for n in '1234']
print('L4:', L4)
# L4: ['A1', 'A2', 'A3', 'A4', 'B1', 'B2', 'B3', 'B4', 'C1', 'C2', 'C3', 'C4', 'D1', 'D2', 'D3', 'D4']
  • 实例:列出当前目录下所有文件和目录名。
import os
L6 = [d for d in os.listdir('.')]
print('L6:', L6)
# L6: ['1.py', '2.py', '3.py']
  • 列表生成式中for循环的对象,还可以是dict对象。
D = {'x':'apple', 'y':'orange', 'z':'banana'}
L7 = [k+'='+v for k,v in D.items()]
print('L7:', L7)
# L7: ['x=apple', 'y=orange', 'z=banana']
  • 实例:把list中的字符串元素的字母都转化成小写
S = ['HELLO','WORLD','APPLE','ORANGE']
L8 = [s.lower() for s in S]
print('L8:', L8)
# L8: ['hello', 'world', 'apple', 'orange']
  • 列表生成式中,for的前面可以使用if...else。for的后面可以使用if,但不能使else,特别要注意。看下面这个综合的例子:
L9 = [x*2 if x%2==0 else -x for x in range(1,11)]
print('L9:', L9)
# L9: [-1, 4, -3, 8, -5, 12, -7, 16, -9, 20]
  • 列表生成式中,for之前的是表达式,for之后的是过滤条件。因此for之后可以使用if...else,而for之后不能使用else。

4、生成器 Generator

  • 如果一个list列表中,后面的元素总是由前面元素推算而来,那么我们通常不必创建完整的list,而动态地使用“一边循环一边计算”的机制来实现,以节省大量的内存空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

(1)第一种方法,使用列表生成式 创建generator生成器

  • 要创建一个generator生成器,有很多种方法。其中最简单的方法之一,就是把一个列表生成式的 [] 改成 () ,即创建了一个generator。
L = [x*x for x in range(10)]  # 列表生成式,创建list列表
print('列表生成式:', L)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
G = (x*x for x in range(5))
print('生成器:', G)
# <generator object <genexpr> at 0x0321BCD8>
  • 列表L和生成器G,它们的区别仅仅在于“列表生成式”外面的 [] 和 (),前者是列表,后者是generator。
  • 生成器的 next()。每次调用next(G),就计算出G的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
print(next(G))  # 0
print(next(G))  # 1
print(next(G))  # 4
print(next(G))  # 9
print(next(G))  # 16
# print(next(G))  # Traceback (most recent call last):StopIteration
  • 使用 for...in 循环来遍历可迭代的generator对象。通过for循环来迭代它,不会出现StopIteration的错误。
G2 = (x*x for x in range(5))
for g in G2:
    print('遍历生成器:', g)

(2)第二种方法,使用generator函数创建生成器

  • 函数中使用了yield关键字,就是generator函数。调用generator函数,返回一个生成器对象。
# 定义 generator函数
def odd():
    yield 1
    yield 3
    yield 5
    return 'done'

G3 = odd()
print('生成器', G)  # <generator object <genexpr> at 0x0321BCD8>

for g in G3:
    print('G3: ', g)
# 依次打印 1,3,5

(3)实例:用生成器定义著名的斐波拉契数列

  • 用生成器定义著名的斐波拉契数列(Fibonacci,除第一个和第二个数外,任意一个数都可由前两个数相加得到)。Fibonacci数列无法使用“列表生成式”来创建,但使用“生成器”来创建将非常地方便。
def fib(max):
    n,a,b = 0,0,1
    while n<max:
        yield b
        a,b = b,a+b
        n+=1
    return 'done'

G4 = fib(6)
for g in G4:
    print('G4: ', g)
# 依次打印 1,1,2,3,5,8

(4)generator函数的返回值

  • 使用 yield 关键字定义的generator函数,如何才能取到它的return返回值呢?如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。
def test():
    yield 'a'
    yield 'b'
    return 'done'

G5 = test()
while True:
    try:
        x = next(G5)
        print('G5: ', g)
    except StopIteration as e:
        print('generator函数的返回值:', e.value)  # 'done'
        break

5、迭代器 Iterator

  • 可以直接作用于for循环的数据类型有以下几种:一类是集合数据类型,如list、tuple、dict、set、str等;一类是generator,包括生成器和带yield的生成器函数。这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
  • 生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值。可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

(1)如何判断一个对象是否是Iterable可迭代的?

from collections.abc import Iterable

# 定义生成器函数
def gen():
    yield 1
    yield 2
    return 'done'
# 创建生成器
G = gen()

b1 = isinstance([], Iterable) # True
b2 = isinstance((), Iterable) # True
b3 = isinstance({}, Iterable) # True
b4 = isinstance('', Iterable) # True
b5 = isinstance((x for x in range(10)), Iterable) # True
b6 = isinstance(G, Iterable) # True

print(b1,b2,b3,b4,b5,b6)

(2)如何判断一个对象是不是Iterator生成器对象?

  • 生成器都是Iterator对象,但list、dict、str虽然是Iterable可迭代的,但不是Iterator对象。使用 iter() 函数可以把list、dict、str等变成Iterator生成器对象。
from collections.abc import Iterator

b7 = isinstance([], Iterator) # False
b8 = isinstance(iter([]), Iterator) # True
b9 = isinstance('abc', Iterator) # False
b10 = isinstance(iter('abc'), Iterator) # True

print(b7,b8,b9,b10)

(3)你可能会问,为什么list、dict、str等数据类型不是Iterator?

  • 这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
  • Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
  • 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列。Python的for循环本质上就是通过不断调用next()函数实现的。

参考资源:
1、廖雪峰Python教程
2、Python官方文档


END!!!

相关文章

  • Python学习(三)

    Python的高级特性 python中有很多高级特性,比起C/C++来说要简单许多,运用起来十分方便。 切片 通常...

  • Python高级特性

    切片slice取指定索引范围的操作:[0:10:2]-->意为从第一个元素到第11个元素,元素之间隔2 迭代ite...

  • python 高级特性

    1.切片对取数据很方便,如取一个list的前n个元素,没有接触到切片的,可以使用循环,但是用切片就会很简单: 也支...

  • Python高级特性

    切片 迭代 列表生成式 生成器 generator generator:按照某种算法推算出来结果,是一种一边循环一...

  • Python——高级特性

    #!/usr/bin/python # -*- coding:UTF-8 -*- __author__ = 'wx...

  • python高级特性

    python高级特性 iteration迭代 对list,tuple的遍历被称为迭代。对list实现类似Java那...

  • python高级特性

    一、列表生成器 1. 形式: [表达式 for ... in 可迭代类型 [if expression] ] 2....

  • Python 高级特性

    切片 迭代 列表生成式 生成器 迭代器

  • Python高级特性

    掌握了Python的数据类型、语句和函数,基本上就可以编写出很多有用的程序了。 比如构造一个1, 3, 5, 7,...

  • python高级特性

    1、切片(slice)L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3...

网友评论

      本文标题:Python高级特性

      本文链接:https://www.haomeiwen.com/subject/pocbphtx.html