一、切片
在对数据进行操作时,需要对list,tuple或str取出部分元素
l1 = ['Shanghai','Beijing','Shenzheng','Guangzhou','Hangzhou']'''在l1中取出前4个城市'''l2 = [l1[0],l1[1],l2[2],l3[3]]
对于一个长列表,需要取出100个元素
l3 = [1,2,3,4......n] # n > 1000'''从l3中取出前100个元素'''l4 = l3[0:100] # l4=[1,2,3,4,....100]
上述代码中的 l3[0:100]即是切片,从l3索引0开始,一直取到索引100,但不包含索引100,即取索引0,1,2,3……99对应的元素(前包含后不包含)
当第一个索引为0的时候可简写
l4 = l3[:100] # 第一个索引为0时可省略实现简写
从元素第2个开始,取出3个元素
l5 = l3[1:4] # l5=[l3[1],l3[2],l3[3]]
注意索引的前包含后不包含,所以取l3[1], l3[2], l3[3]
当然Python也支持倒数取元素
l5 = ['a','b','c','d','e']l6 = l5[-1] # 取l5倒数第一个元素,即'e'l7 = l5[-3:-1] # 取l5倒数第3个,倒数第2个元素,即l5[-3],l5[-2]
注:
通过切片倒数取元素时,同样遵循前包含后不包含;
倒数第一个元素索引从 -1 开始
对于一个长数列,通过切片可轻松取出任意一段数列
l8 = list(range(100)) # l8 = [0,1,2,3.....98,99]l9 = l8[:10] # 取前10个数 [0,1,2,3,4,5,6,7,8,9]l10 = l8[-10:] # 取后10个数 [90,91,92....99]l11 = l8[5:10] # 取索引为5-9的元素
通过切片间隔取元素
l12 = [1,2,3,4,5,6,7,8,9,10]l13 = l12[0:10:2]# 对列表l12按索引间隔为2取元素,即l13=[l12[0],l12[2],l12[4],l12[6],l12[8]]# 1,3,5,7,9
任务:l8 = list(range(100)) ,通过切片形式,取出l8中所有奇数
l = list(range(100))l2 = l[1::2]print(l2)
任务:尝试一下l14 = l8[ : ]
tuple也是一种特殊的list,唯一区别就是tuple不可变,因此tuple也可以进行切片,切片结果仍是tuple
t1 = (1,2,3,4,5)t2 = t1[0:3] # tuple也可进行切片
字符串进行切片
s1 = 'abcdefg's2 = s1[0:4] # str也能进行切片
字符串第一个元素就是一个字符,切片结果仍是字符串
任务:给定一个字符串,该字符串首尾都包含空格,通过切片的形式,去除该字符串首尾空格
s3 = ' 测试字符串.....n ''''s3是一个字符串,首发包含空格,通过切片的形式,生成一个新字符串s4,去除s3的首尾空格'''
二、迭代(Iteration)
通过for循环来遍历list或tuple等可迭代对象,Python中通过 for…in 来完成迭代
dic = {'k_1':'v_1','k_2':'v_2','k_3':'v_3'}for i in dic: # 字典也可迭代,但输出的是keyprint (i) # 输出:k_1 k_2 k_3
迭代字典对象时,默认输出的是字典的所有 key
如果要迭代字典中的value,可通过 for i in dic.values( ),如果要同时迭代key和value,可以用for k, v in dic.items( )
for i in dic.values(): # 迭代输出字典的valueprint(i) # v_1 v_2 v_3for k, v in d.items(): # 同时迭代key,valueprint(f'{k}:{v}') # k_1:v_1 k_2:v_2 k_3:v_3
迭代字符串
s = "测试字符串"for i in s: # 迭代字符串print(i)
任务:通过迭代,查找list [1,8,4,7,5,3,2]的最大数
三、列表生成式
L = [表达式 for 变量 in 可迭代对象 ]
即:变量从可迭代对象中获取元素作用到表达式中
遍历列表 [1,2,3,4,5,6,7] 根据公式 2x+1,生成一个新的列表
l1 = [1,2,3,4,5,6,7]l2 = []for x in l1:s = 2*x+1l2.append(s)# l2列表[3, 5, 7, 9, 11, 13, 15]
运用列表生成式简化上述代码
l2 = [2*x+1 for x in l1] #l2列表[3, 5, 7, 9, 11, 13, 15]
列表生成式中for循环后面可以加if判断进行筛选
l3 = [2*x+1 for x in l1 if x % 2 ==0] # 结果[5, 9, 13]
上述代码只有满足if 条件后的元素才会参加 2*x+1 运算,注意:列表生成式中if作为筛选条件,后面不能跟else
列表生成式中for循环后面可以再嵌套for循环
l4 = [x+y for x in '123' for y in 'abc']# ['1a','1b','1c','2a','2b','2c','3a','3b','3c']
任务:根据l4列表生成式逻辑,请定义一个函数,使用嵌套的for循环实现上述代码功能
任务:根据下面代码,改写成列表生成式
l5 = [1,2,3,4,5,6]l6 = []for i in l5:if i >= 3:s = i*i + 1l6.append(s)
四、生成器(generator)
列表对象对内存的占用,决定于其列表中元素个数,如果上百万个元素的列表不仅会占用很大的内部空间,而且其元素利用率不高将会造成很大的资源浪费,所以生成器,就是按照某种算法推算列表元素,通过循环能不断推断下一个元素,而不必创建整个list,来节省空间,即边循环边计算。
创建一个生成器
1.在列表生成式的基础上,把[ ]改成( ),就生成了一个generator
l = [x for x in range(10)]print(type(l)) # <class 'list'>l_g = (x for x in range(10))print(type(l_g)) # <class 'generator'>
生成器可通过next( )函数来一个一个实现打印元素
next(l_g) # 0next(l_g) # 1next(l_g) # 2next(l_g) # 3
当next(l_g) 没有更多元素时会抛出StopIteration
因为 generator 是可迭代对象,可使用for循环迭代
for i in l_g: # l_g是生成器也是迭代器print(i)
2.在函数中通过 yield 来定义一个 generator
在Python程序中函数一般是顺序执行,遇到 return 语句返回结果并结束或执行到函数最后一句后结束运行,但在作为 generator 的函数,每次调用 next( ) 执行时,遇到 yield 就返回,当再次执行时是从上次返回的 yield 语句处继续执行
def new_generator():print('执行第一次调用')yield ('第一次返回1')print('执行第二次调用')yield '第二次返回2'print('执行第三次调用')yield '第三次返回3’n = new_generator()print(next(n)) # 执行第一次调用第一次返回1print(next(n)) # 执行第二次调用第二次返回2print(next(n)) # 执行第三次调用第三次返回3print(type(n)) # <class 'generator'>for i in n: # 通过 for 循环迭代 new_generatorprint(i)'''执行第一次调用第一次返回1执行第二次调用第二次返回2执行第三次调用第三次返回3'''
五、迭代器(Iterator)
可直接通过for循环的数据类型有:
1.集合类数据类型:list, tuple, dict, set, str
2.generator 生成器
所有可通过for循环迭代的可称为可迭代对象(Iterable)
迭代器:可以被next( )函数不断调用并返回下一个值的对象(Iterator)
问题:
1、迭代对象都是迭代器(True or False)?F
2、迭代器都是迭代对象(Ture or False)?T
3、生成器属于迭代器 ( Ture or False)?T
4、list, dict, str 是迭代器(True or False) ?F
生成器都是Iterator,但list、dict、str虽然是Iterable,却不是Iterator
Iteration/Iterable/Iterator?
iter( )函数可把Iterable 变成 Iterator
l = [1,2,3,4,5]next(l) # TypeError: 'list' object is not an iteratorl_t = iter(l) # 通过iter()函数把list变成一个Iteratorprint(next(l_t))print(next(l_t))print(next(l_t))

总结:
1、凡是可用for循环的都是可迭代对象Iterable;
2、凡是可用next( )函数返回下一值的都是迭代器Iterator;
3、生成器是通过某种算法推算,边循环边计算的机制,可以通过next( )函数不断返回下一值
因此,生成器也是一种迭代器;
六、装饰器
前提概念一:
闭包:在函数中再嵌套一个函数,并且引用外部函数的变量,这就是一个闭包了
def outer(x):def inner(y):return x + yreturn innerprint(outer(6)(5))
函数中可定义函数
def func_1():print("正在调用func_1")def func_1_1():return "正在调用func_1_1"def func_1_2():return "正在调用func_1_2"print(func_1_1())print(func_1_2())print("函数func_1调用结束")#正在调用func_1正在调用func_1_1正在调用func_1_2函数func_1调用结束
函数中定义的函数,只能在func_1函数内调用
前提概念二:
函数中返回函数
def func_1():print("正在调用func_1")def func_1_1():return "正在调用func_1_1"print("函数func_1调用结束")return func_1_1a = func_1() #正在调用func_1函数func_1调用结束print(a) # <function func_1.<locals>.func_1_1 at 0x000001B92BE3DAF0>print(a()) # 正在调用func_1_1
问题:为什么 print(a) 与 print(a( ))不一样?
前提概念三:
赋值与调用
def func_2():print("函数func_2被调用")a = func_2print(a) # <function func_2 at 0x00000219AAD8F040>b = func_2() # 函数func_2被调用c = a() # 函数func_2被调用
从上述代码可知,当 a = func_2 时,是把func_2函数对象内存地址赋值给变量a,并不会执行func_2这个函数中的代码;当 b = func_2( )时,函数func_2( )会被调用,加上()会运行这个函数中的代码
装饰器:
在Python中,可以把函数A作为参数传入另一个函数B,从而实现在不改变函数A原有代码的基础上对函数A增加新功能
def func_A():print("A函数本身的功能")def func_B(func):print("执行func_B开始")def func_b():print("func_b执行传入函数前做一些事情")func()print("func_b执行传入函数后做一些事情")print("准备返回func_b")return func_bb = func_B(func_A) # func_B()执行返回一个 func_b 内嵌函数对象给func_A调用'''执行func_B开始准备返回func_bfunc_b执行传入函数前做一些事情A函数本身的功能func_b执行传入函数后做一些事情'''
上述代码func_B函数就是一个装饰器函数,但需要调用func_B函数来实现对func_A函数的功能拓展,
通过@符号装饰func_A函数,可实现直接调用func_A函数来达成装饰器的目的
@func_Bdef func_A():print("A函数本身的功能")func_A()'''执行结果:执行func_B开始准备返回func_bfunc_b执行传入函数前做一些事情A函数本身的功能func_b执行传入函数后做一些事情'''
被装饰的A函数有单个参数
def func_B(func):def func_b(x):return 2*func(x)return func_b@func_Bdef func_A(x):return int(x)+1if __name__ == "__main__":a = func_A(2)print(a)print(func_A.__name__) # 结果为func_b,即func_A被装饰后指向了func_b
被装饰的A函数有多个参数
def func_B(func):def func_b(*args,**kwargs):return 2*func(*args,**kwargs)return func_b@func_Bdef func_A(x,y):return int(x)+int(y)if __name__ == "__main__":a = func_A(2,3)print(a)
