一、切片
在对数据进行操作时,需要对list,tuple或str取出部分元素
切片基本语法:
object[start_index:end_index:step]
start_index:起始索引(起点,包含该索引);end_index:终止索引(终点,不包含该索引);step:步长(不指定时默认为1)正负数均可,其绝对值大小决定了切取数据时的‘‘步长”,而正负号决定了“切取方向”,正表示“从左往右”取值,负表示“从右往左”取值
citys = ['Shanghai','Beijing','Shenzheng','Guangzhou','Hangzhou']
'''在citys中取出前4个城市'''
gleam_citys = [l1[0],l1[1],l2[2],l3[3]]
对于一个长列表,需要取出100个元素
numbers = [1,2,3,4......n] # n > 1000
'''从numbers中取出前100个元素'''
hundred_num = numbers[0:100] # l4=[1,2,3,4,....100]
上述代码中的 numbers[0:100]即是切片,从numbers索引(下标)0开始,一直取到索引(下标)99,但不包含索引100,即取索引0,1,2,3......99对应的元素(前包含后不包含)
切片时start_index可省略不写
hundred_num = numbers[:100] # 省略start_index时表示从起始端点开始
切片同样end_index可省略不写
hundred_num = numbers[1:] # 省略end_index时表示从终止端点结束
从元素第2个开始,取出3个元素
numbers_seed = numbers[1:4] # numbers_seed=[numbers[1],numbers[2],numbers[3]]
注意索引的前包含后不包含,所以取numbers[1], numbers[2], numbers[3]
当然Python也支持倒数取元素
str_list = ['a','b','c','d','e']
new_str_list_1 = str_list[-1] # 取str_list倒数第一个元素,即'e'
new_str_list_2 = str_list[-3:-1] # 取str_list倒数第3个,倒数第2个元素,即str_list[-3],str_list[-2]
注:
通过切片倒数取元素时,同样遵循前包含后不包含;
倒数第一个元素索引从 -1 开始
对于一个长数列,通过切片可轻松取出任意一段数列
num_list = list(range(100)) # l8 = [0,1,2,3.....98,99]
list_forword = num_list[:10] # 取前10个数 [0,1,2,3,4,5,6,7,8,9]
list_back = num_list[-10:] # 取后10个数 [90,91,92....99]
list_between = num_list[5:10] # 取索引为5-9的元素
通过切片间隔取元素
num_list = [1,2,3,4,5,6,7,8,9,10]
num_list_seed= num_list[0:10:2]
# 对列表num_list按索引间隔为2取元素,即num_list_seed=[num_list[0],num_list[2],num_list[4],num_list[6],num_list[8]]
# 1,3,5,7,9
任务:numbers = list(range(100)) ,通过切片形式,取出numbers中所有奇数
numbers = list(range(100))
odd_numbers = l[1::2]
print(odd_numbers)
任务:尝试一下new_num_list = num_list[ : ]
tuple也是一种特殊的list,唯一区别就是tuple不可变,因此tuple也可以进行切片,切片结果仍是tuple
tuple_num_1 = (1,2,3,4,5)
tuple_num_2 = tuple_num_1[0:3] # tuple也可进行切片
字符串进行切片
str_1 = 'abcdefg'
str_2 = str_1[0:4] # str也能进行切片
字符串第一个元素就是一个字符,切片结果仍是字符串
任务:给定一个字符串,该字符串首尾都包含空格,通过切片的形式,去除该字符串首尾空格
str_3 = ' 测试字符串.....n '
'''str_3是一个字符串,首发包含空格,通过切片的形式,生成一个新字符串str_4,去除str_3的首尾空格'''
二、迭代(Iteration)
通过for循环来遍历list或tuple等可迭代对象,Python中通过 for...in 来完成迭代
dic = {'k_1':'v_1','k_2':'v_2','k_3':'v_3'}
for i in dic: # 字典也可迭代,但输出的是key
print (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(): # 迭代输出字典的value
print(i) # v_1 v_2 v_3
for k, v in d.items(): # 同时迭代key,value
print(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,生成一个新的列表
list_num_1 = [1,2,3,4,5,6,7]
list_res_2 = []
for x in list_num_1:
res = 2*x+1
list_res_2.append(res)
# list_res_2列表[3, 5, 7, 9, 11, 13, 15]
运用列表生成式简化上述代码
list_res_2 = [2*x+1 for x in list_num_1] #list_res_2列表[3, 5, 7, 9, 11, 13, 15]
列表生成式中for循环后面可以加if判断进行筛选
list_res_3 = [2*x+1 for x in list_num_1 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循环实现上述代码功能
任务:根据下面代码,改写成列表生成式
list_num = [1,2,3,4,5,6]
list_num_new = []
for num in list_num:
if num >= 3:
res = num*num + 1
list_num_new.append(res)
四、生成器(generator)
列表对象对内存的占用,决定于其列表中元素个数,如果上百万个元素的列表不仅会占用很大的内部空间,而且其元素利用率不高将会造成很大的资源浪费,所以生成器,就是按照某种算法推算列表元素,通过循环能不断推断下一个元素,而不必创建整个list,来节省空间,即边循环边计算。
创建一个生成器
1.在列表生成式的基础上,把[ ]改成( ),就生成了一个generator
l = [x for x in range(10)]
print(type(l)) #
l_g = (x for x in range(10))
print(type(l_g)) #
生成器可通过next( )函数来一个一个实现打印元素
next(l_g) # 0
next(l_g) # 1
next(l_g) # 2
next(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)) # 执行第一次调用
第一次返回1
print(next(n)) # 执行第二次调用
第二次返回2
print(next(n)) # 执行第三次调用
第三次返回3
print(type(n)) #
for i in n: # 通过 for 循环迭代 new_generator
print(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 iterator
l_t = iter(l) # 通过iter()函数把list变成一个Iterator
print(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 + y
return inner
print(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_1
a = func_1() #正在调用func_1
#函数func_1调用结束
print(a) # .func_1_1 at 0x000001B92BE3DAF0>
print(a()) # 正在调用func_1_1
问题:为什么 print(a) 与 print(a( ))不一样?
前提概念三:
赋值与调用
def func_2():
print("函数func_2被调用")
a = func_2
print(a) #
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_b
b = func_B(func_A) # func_B()执行返回一个 func_b 内嵌函数对象给func_A调用
'''
执行func_B开始
准备返回func_b
func_b执行传入函数前做一些事情
A函数本身的功能
func_b执行传入函数后做一些事情
'''
上述代码func_B函数就是一个装饰器函数,但需要调用func_B函数来实现对func_A函数的功能拓展,
通过@符号装饰func_A函数,可实现直接调用func_A函数来达成装饰器的目的
@func_B
def func_A():
print("A函数本身的功能")
func_A()
'''
执行结果:
执行func_B开始
准备返回func_b
func_b执行传入函数前做一些事情
A函数本身的功能
func_b执行传入函数后做一些事情
'''
被装饰的A函数有单个参数
def func_B(func):
def func_b(x):
return 2*func(x)
return func_b
@func_B
def func_A(x):
return int(x)+1
if __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_B
def func_A(x,y):
return int(x)+int(y)
if __name__ == "__main__":
a = func_A(2,3)
print(a)