高级特性

切片

取list前三个元素:

L = ['diaochan','xiaoqiao','daqiao','wangzhaojun','daji']
print(L[0],L[1],L[2])

diaochan xiaoqiao daqiao

取前N个元素,可以用循环:

L = ['diaochan','xiaoqiao','daqiao','wangzhaojun','daji','caiwenji','yuji']
r = []
n = 5
for i in range(n):
    r.append(L[i])
print(r)

['diaochan', 'xiaoqiao', 'daqiao', 'wangzhaojun', 'daji']

切片法比较简单,例如还是取前N个元素:

L = ['diaochan','xiaoqiao','daqiao','wangzhaojun','daji','caiwenji','yuji']
print(L[0:3])

['diaochan', 'xiaoqiao', 'daqiao']

L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。
如果第一个索引是0,还可以省略:

L = ['diaochan','xiaoqiao','daqiao','wangzhaojun','daji','caiwenji','yuji']
print(L[:3])

['diaochan', 'xiaoqiao', 'daqiao']

也可以写成 L[1:3],取出2个元素。
倒数切片:
倒数第一个元素的索引是-1

L = ['diaochan','xiaoqiao','daqiao','wangzhaojun','daji','caiwenji','yuji']
print(L[-1])
print(L[-3:])
print(L[-3:-1])

yuji
['daji', 'caiwenji', 'yuji']
['daji', 'caiwenji']

还可以有以下操作:

L = list(range(20))  #创建数列
print(L[:10:2])  #前10个数,每两个取一个
print(L[::5])  #所有数,每5个取一个
print(L[:])  #复制一个list

[0, 2, 4, 6, 8]
[0, 5, 10, 15]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:

L = (0,1,2,3,4,5,6,7,8,9)
print(L[:5:2])
print(L[::5])
print(L[:])

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

字符串’xxx’也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串,可以简单的写成如下形式:

print('ABCDEFG'[:3])
print('ABCDEFG'[::2])

ABC
ACEG

迭代

Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。

d = {'a':1,'b':2,'c':3,'d':4}
for key in d:
    print(key)  #默认情况下
for value in d.values():  #迭代value
    print(value)
for k,v in d.items():   #迭代key和value
    print(k,v)

a
b
c
d
1
2
3
4
a 1
b 2
c 3
d 4

因为dict的存储不是按照list的方式顺序排列,所以,迭代出的结果顺序很可能不一样

for ch in 'ABCD':
    print(ch)  

A
B
C
D

判断一个对象是可迭代对象:通过collections模块的Iterable类型判断

from collections import Iterable
print(isinstance('abc', Iterable)) # str是否可迭代
print(isinstance([1,2,3], Iterable)) # list是否可迭代
print(isinstance(123, Iterable) )# 整数是否可迭代

True
True
False

对list实现下标循环:Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身

enumerate:枚举

for i, value in enumerate(['A', 'B', 'C']):  #同时引用了两个变量在Python里很常见
    print(i, value)

0 A
1 B
2 C

引用两个变量的例子:

for a,b in [(1,1),(2,3)]:
    print(a,b)

1 1
2 3

使用迭代查找一个list中最小和最大值,并返回一个tuple:

# -*- coding: utf-8 -*-
def findMinAndMax(L):
    if L!=[]:
        min = L[0]
        max = L[0]
        for i in L[1:]:
            if max < i:
                max = i
            if min > i:
                min = i      
        return (min,max) 
    else:
        return(None,None)
# 测试
if findMinAndMax([]) != (None, None):
    print('测试失败!')
elif findMinAndMax([7]) != (7, 7):
    print('测试失败!')
elif findMinAndMax([7, 1]) != (1, 7):
    print('测试失败!')
elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):
    print('测试失败!')
else:
    print('测试成功!')

测试成功!

列表生成式

一般方法

一般方法:

print(list(range(1,10)))

[1, 2, 3, 4, 5, 6, 7, 8, 9]

或者循环方法:

L = []
for x in range(1,11):
    L.append(x*x)
print(L)

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

列表生成式

但是循环太麻烦,而列表生成式则可以用一行语句代替循环生成上面的list,写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来:

print([x*x for x in range(1,11)])

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

可以加上判断

print([x*x for x in range(1,11) if x%2 == 0])

[4, 16, 36, 64, 100]

使用两层循环,生成全排列

print([x+y for x in 'ABC' for y in 'LMN'])

['AL', 'AM', 'AN', 'BL', 'BM', 'BN', 'CL', 'CM', 'CN']

列出当前目录下的所有文件和目录名

import os # 导入os模块,模块的概念后面讲到
print([d for d in os.listdir('.')]) # os.listdir可以列出文件和目录

['.anaconda', '.astropy', '.bash_history', '.conda', '.condarc', '.config', '.idlerc', '.ipython', '.keras', '.matplotlib', '.PyCharmCE2019.3', '.python_history', '.vscode', '1.mat', 'AppData', 'ApplicmCE2019.3', '.python_history', '.vscode', '1.mat', 'AppData', 'Application Data', 'Contacts', 'Cookies', 'Desktop', 'Documents', 'Docal Settings', 'Music', 'My Documents', 'NetHood', 'NTUSER.DAT', 'ntuwnloads', 'Favorites', 'Intel', 'IntelGraphicsProfiles', 'Links', 'Local Settings', 'Music', 'My Documents', 'NetHood', 'NTUSER.DAT'6b948c6eb}.TMContainer00000000000000000001.regtrans-ms', 'NTUSER.DAT{, 'ntuser.dat.LOG1', 'ntuser.dat.LOG2', 'NTUSER.DAT{2599cde1-271b-11e5-80c6-0026b948c6eb}.TM.blf', 'NTUSER.DAT{2599cde1-271b-11e5-80intHood', 'Recent', 'Saved Games', 'Searches', 'SendTo', 'Templates',c6-0026b948c6eb}.TMContainer00000000000000000001.regtrans-ms', 'NTUSER.DAT{2599cde1-271b-11e5-80c6-0026b948c6eb}.TMContainer00000000000000000002.regtrans-ms', 'ntuser.ini', 'OneDrive', 'Pictures', 'pip', 'PrintHood', 'Recent', 'Saved Games', 'Searches', 'SendTo',
'Templates', 'Videos', '「开始」菜单']

同时迭代两个变量

d = {'x':'a','y':'b','z':'c'}
for k,v in d.items():
    print(k,'=',v)

x = a
y = b
z = c

使用两个变量来生成list

d = {'x':'a','y':'b','z':'c'}
print([k + '=' + v for k,v in d.items()])

['x=a', 'y=b', 'z=c']

把所有的字符串变成小写(or大写)

L = ['Hello','World']
print([s.lower() for s in L])
print([s.upper() for s in L])

['hello', 'world']
['HELLO', 'WORLD']

if … else

错误示例:

print([x for x in range(1, 11) if x % 2 == 0 else 0])
SyntaxError: invalid syntax

print([x if x % 2 == 0 for x in range(1, 11)])
SyntaxError: invalid syntax

for前面的部分是一个表达式,它必须根据x计算出一个结果。因此,考察表达式:x if x % 2 == 0,它无法根据x计算出结果,因为缺少else,必须加上else:

print([x if x % 2 == 0 else -x for x in range(1, 11)])

[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]

上述for前面的表达式x if x % 2 == 0 else -x才能根据x计算出确定的结果。

可见,在一个列表生成式中,for前面的if … else是表达式,而for后面的if是过滤条件,不能带else。
如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错:

 L = ['Hello', 'World', 18, None]
 print([s.lower() for s in L])

IndentationError: unexpected indent

应该改为:

L = ['Hello', 'World', 18, None]
print([x.lower() for x in L if isinstance(x,str)])

['hello', 'world']

isinstance函数

isinstance函数可以判断一个变量是不是字符串

生成器

从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

方法一

generator:
通过next()函数获得generator的下一个返回值

g = (x * x for x in range(10))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

0
1
4
9

对比list:

print([x * x for x in range(10)])

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

区别:仅在于最外层的[]和()

使用for循环

g = (x * x for x in range(10))
for n in g:
    print(n)
    
0
1
4
9
16
25
36
49
64
81

如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,可以用函数来实现。
例如:斐波拉契数列
1, 1, 2, 3, 5, 8, 13, 21, 34, …

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(int(input('请输入:')))

或者更规范:

def fib(max):
    n,a,b = 0,0,1
    while n < max:
        print(b)
        a,b = b,a + b
        n = n+1
    return 'done'
a = (input('请输入:'))
a = int(a)
fib(a)

结果:

请输入:5
1
1
2
3
5

fib(int(input('请输入:')))换成print(fib(int(input('请输入:')))),最后的done可以被打印出来
原因:命令行的fib相当于代码中的print(fib)

注意:

a, b = b, a + b

等价于

t = (b, a + b) # t是一个tuple,但不必显式写出临时变量t就可以赋值。
a = t[0]
b = t[1]

方法二

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
还以斐波拉契数列为例,把print(b)改为yield b:

def fib(max):
    n,a,b = 0,0,1
    while n < max:
        yield b
        a,b = b,a + b
        n = n+1
    return 'done'
print(fib(int(input('请输入:'))))

请输入:5
<generator object fib at 0x000000B3237ACA98>

generator和函数的执行流程不一样。
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
generator的函数在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

简单的例子:

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)
next(odd())
next(odd())

step 1
step 1
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)
print(next(odd()))
print(next(odd()))

step 1
1
step 1
1
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)
f = odd()
print(next(f))
print(next(f))
print(next(f))
print(next(f))

step 1
1
step 2
3
step 3
5
Traceback (most recent call last):
  File "d:/python exercise/1.py", line 12, in <module>
    print(next(f))
StopIteration

区别:赋值给f才是生成器,否则只是一个函数

odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(f)就报错。
在循环过程中不断调用yield就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。
注意:把函数改成generator后,基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代。

>>> for n in fib(6):
...     print(n)

1
1
2
3
5
8

但是用for循环调用generator时,拿不到generator的return语句的返回值。因此必须捕获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

杨辉三角

在这里插入图片描述
答案1:

'每次根据上一个的L,修改,得到下一个L。··规律:每一个值等于它斜上方左右值想加'
'例如第四行第二个数是3,range(2)可以看出来i为0和1;即上一个L的L[0]+L[1]=3,L[1]+L[2]=3,因此yield返回的L=[1 3 3 1]'
'yield的功能相当于return'
def triangles():
    L = [1]
    while len(L)<5:
        yield L
        L = [1]+[L[i]+L[i+1] for i in range(len(L)-1)]+[1] '内部用for循环实现中间的数值相加,两边则单独加'
        
for n in triangles():
    print(n)

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]

答案2:

'与答案1不同的是答案2没有保留第一位和最后一位为1,而是设置为0,然后计算L[0]+L[1]=1'
'例如第二行,上一个L=[0 1 0]但是不输出,下一行range(2),则i为0和1'
def triangles():
    l = [1]
    while True:
        yield l
        l = [0]+l+[0]
        l = [l[i]+l[i+1] for i in range(len(l)-1)]
n = 0
results = []
for t in triangles():
    results.append(t)
    n = n+1
    if n ==10:
        break
for t in results:
    print(t)
if results == [
    [1],
    [1, 1],
    [1, 2, 1],
    [1, 3, 3, 1],
    [1, 4, 6, 4, 1],
    [1, 5, 10, 10, 5, 1],
    [1, 6, 15, 20, 15, 6, 1],
    [1, 7, 21, 35, 35, 21, 7, 1],
    [1, 8, 28, 56, 70, 56, 28, 8, 1],
    [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:
    print('测试通过!')
else:
    print('测试失败!')

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
测试通过!

注意:输入L = [1]+[1] print(L) 输出[1, 1]

迭代器

可以直接作用于for循环的数据类型有以下几种:
(1)集合数据类型,如list、tuple、dict、set、str等;
(2)generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象。

生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。可以使用isinstance()判断一个对象是否是Iterator对象。

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。把list、dict、str等Iterable变成Iterator可以使用iter()函数:


>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

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

小结:
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
Python的for循环本质上就是通过不断调用next()函数实现的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值