返回介绍

数据结构高级内容

发布于 2024-05-30 23:22:17 字数 15643 浏览 0 评论 0 收藏 0

切片

可以切片的数据类型:list、tuple、str

>>> [0, 1, 2, 3, 4, 5][0:3]
(0, 1, 2)
>>> (0, 1, 2, 3, 4, 5)[0:3]
(0, 1, 2)
>>> 'ABCDEFG'[0:3]
'ABC'

迭代

  • Iterator类型:表示一个惰性序列,Iterator 的计算是惰性的,只有在需要返回下一个数据时它才会计算,且一次计算返回一个数据。具有 __next__() 方法。Iterator 甚至可以表示一个无限大的数据流,例如全体自然数。
  • Iterable类型:从它可以直接或间接得到一个Iterator的对象。本身是Iterator对象,或能通过iter()获得到一个Iterator对象。

generator是 Iterator 对象。生成器不但可以作用于 for 循环,还可作用于 next()函数。 集合数据类型如 list、 dict、 str 等是 Iterable 但不是 Iterator,不过可以通过 iter()函数将其转换为 Iterator 对象。使用list等是永远不可能存储全体自然数的。

凡是可作用于 for 循环的对象都是 Iterable 类型(也称之为可迭代对象); 凡是可作用于 next()函数的对象都是 Iterator 类型(也称之为迭代器);

Iterator

使用 isinstance()判断一个对象是否是 Iterator 对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

Iterable

通过isinstance函数可以判断一个对象是否是可迭代对象:

>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str 是否可迭代
True

在 Python 中,迭代是通过 for ... in 来完成的。for 循环本质上就是通过不断调用 next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

it = iter([1, 2, 3, 4, 5])     # 首先获得 Iterator 对象
while True:                    # 循环
    try:
        x = next(it)           # 获得下一个值
    except StopIteration:
        break                  # 遇到 StopIteration 就退出循环

list或 tuple 的迭代是通过下标完成的。
dict 默认情况下迭代的是 key。如果要迭代 value,可以用 for value in d.values(),如果要同时迭代 key 和 value,可以用 for k, v in d.items()
字符串的迭代,例如:for ch in 'ABC'

通过enumerate 函数可以把一个 list 变成索引-元素对,这样就可以在 for 循环中同时迭代索引和元素本身:

>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2 C

推导式(Comprehension)

推导式是从一个或多个迭代器简洁快速创建数据结构的一种方法。
以列表推导式来分析下原理:
[(x,y) for x in range(3) if x != 0 for y in range(5) if y != 0]
等价于:

result = []
for x in range(3):
    if not x != 0:
        continue
    for y in range(5):
        if not y != 0:
            continue
        result.append((x,y))

[注] 如果推导式中有多条for子句或if子句,嵌套次序就是它们的书写顺序。

列表推导式

基本格式:
[expression for item in iterable if condition]
举例:

mylist = [x for x in range(6)]
mylist = [(x, y) for x in [1,2,3] for y in [1,5,6]]
mylist = [(x, y) for x in [1,2,3] for y in [1,5,6] if x != y]
mylist = [(x, y) for x in [1,2,3] if x != 1 for y in 'abc' if y != 'a']

字典推导式

基本格式:
{key_expression:value_expression for item in iterable if condition}
举例:

text = 'hello erick'
mydict = {x:text.count(x) for x in set(text) if x != ' '}  
#text存在重复字母,浪费时间,因此用set来改善

集合推导式

与列表推导式相似,将[]改成{}即可。
举例:

myset = {x for x in 'abc'}

生成器推导式(生成器表达式,Generator Expressions)

元组没有推导式,它的圆括号是用来做生成器推导式的。
最简单的格式:
(expression for item in iterable if condition)
举例:

mygenerator = (x for x in range(8) if x != 0) #返回一个 generator 对象
for i in mygenerator:
    print(i)

如果生成器表达式作为函数唯一参数去调用时,它的圆括号可以省略。
举例:

result = sum(x*y for x,y in zip([1,2], [3,4]))
mytuple = tuple(x for x in range(10))
mylist  = list(x for x in range(10))
mydict  = dict( (str(x), x) for x in range(10) )

序列解包(sequence unpacking)

序列解包的本质是把一个序列或任何可迭代对象中的元素同时赋值给多个变量。
如果等号右侧含有表达式,会把所有表达式的值先计算出来,然后再进行赋值。
例如:

  • 多个变量同时赋值
    x, y, z = 1, 2, 3
    v_tuple = (False, 2, 'hello')
    (a, b, c) = v_tuple
    a, b, c = v_tuple
    
  • 交换两个变量的值
    a, b = b, a  #交换两个变量的最快的方式
    
  • 字符串进行解包
    x, y, z = 'abc'
    
  • 解包给切片赋值
    x = [1,2,3]
    x[:2] = '0123' #结果x为:['0', '1', '2', '3', 3]
    
  • 迭代器对象进行解包
    x, y, z = iter([1,2,3])
    
  • range对象进行解包
    x, y, z = range(3)
    
  • 可迭代的map对象进行解包
    x, y, z = map(str, range(3))
    
  • sorted函数返回排序后的列表进行解包
    x, y, z = sorted([1,3,2])
    
  • 如果想将结果解释为 (a, <everything else>),你需要用星来表示,就如在函数参数中那样,不同的是这里解压后*后面的变量是list类型(如果没有元素则为空列表)。
    a, *b = [1, 2, 3, 4]   #a为1  b为[2,3,4]
    a, *b = (1,)        #a为1  b为[]
    

生成器

注意:一个生成器对象只能遍历一次,不能反复遍历。如果需要重新遍历,需要生成一个新的生成器对象。

创建generator对象的方法:

  • 使用生成器表达式(生成器推导式)
  • 使用生成器函数

生成器表达式(生成器推导式)

>>> f = (x for x in ‘abc’) #返回一个 generator 对象
>>> f
<generator object <genexpr> at 0x1022ef630>

生成器函数

任何包含yield关键字的函数都是一个生成器函数。
1)调用生成器函数将返回一个generator 对象;
2)第一次对生成器使用next方法时,生成器才开始执行生成器函数;
3)每次遇到yield则中断返回,并将 yield 后的参数作为此次的返回值;
4)再次执行时从上次中断的 yield 语句处继续执行;
5)当调用 next 方法时生成器函数结束或遇到return语句,则此次调用将抛出 StopIteration 异常。
举例:

def genefunc():
    ''' 生成器函数 '''
    yield 1
    yield 'hello'
    yield (1,2)
g = genefunc()
for i in g:
    print(i)

generator对象的使用

可以通过 next()函数获得 generator 的下一个返回值,直到计算到最后一个元素,没有更多的元素时,会抛出StopIteration 的错误:

>>> next(f)
a
>>> next(f)
b
>>> next(f)
c
>>> next(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

为了简化,还可以使用for 循环,因为 generator 也是可迭代对象:

for i in f:
    print(i)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文