Python基础之高级特性介绍

一、切片

在对数据进行操作时,需要对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))  # <class 'list'>
l_g = (x for x in range(10))
print(type(l_g)) # <class 'generator'>

 生成器可通过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)) # <class 'generator'>

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)    # <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_2
print(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_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)

 

 

 

 

 

 

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值