Python进阶(一)

前言:本博客主要复习下Python进阶知识,迭代器、生成器、装饰器的应用和原理,常用的高阶函数以及赋值、深浅拷贝。

目录

常见数据结构

可迭代对象&迭代器

生成器 

装饰器

高阶函数

map函数

lambda表达式

reduce函数

filter

sorted 

enumerate 

赋值、深浅拷贝


常见数据结构

先来复习下python中常见的数据结构:字典、列表、字符串、元组、集合,以及它们常见的用法和操作。

在处理数据时,经常会用到遍历,那什么是遍历?

从列表、元组、字符串中取出数据,用for i in ... 语句,依次拿到数据,这个过程就是遍历,可以用for循环的对象是可迭代对象,即Iterable。

可迭代对象&迭代器

interable本质是什么?如何自己去实现一个可迭代对象?

示例如下:

from collections.abc import Iterable
class Mylist():
    def __init__(self):
        self.container = []

    def add(self, other):
        self.container.append(other)

    def __iter__(self):
        pass
mylist = Mylist()
print(isinstance(mylist, Iterable))
print(isinstance([], Iterable))
print(isinstance("abcdef", Iterable))
print(isinstance({}, Iterable))
print(isinstance(range(10), Iterable))

 可以看到,内部实现这个方法def __iter__(self): ,就是可迭代对象

可迭代对象不是迭代器,iter()可将可迭代对象转为迭代器

迭代器Iterator,实现了__iter__和__next__()。

其中__iter__()方法返回迭代器对象本身 __next__()方法返回容器的下一个元素,直到结尾抛出StopIteration异常。

实现一个迭代器

class Mylist():
    def __init__(self,data):
        self.__data = data
        self.__count = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.__count < len(self.__data):
            val = self.__data[self.__count]
            self.__count += 1
            return val
        else:
            raise StopIteration


mylist = Mylist([1,2,3,4,5,6])
print(mylist)
for i in mylist:
    print(i)

生成器 

创建列表可以用列表生成式:[i for i in range(5)]

生成器表达式:(i for i in range(5))

生成器函数使用yield语句而不是return语句返回结果

生成器只能遍历一次

def hanshu(n):
    for i in range(n):
        yield i
a = hanshu(5)
for i in a:
    print(i)

关于生成器的更多内容可以查看下面的这篇博客。

python生成器的原理和业务场景下的使用_colourmind的博客-CSDN博客

装饰器

python里很多@的用法,这个@是什么意思?@就是装饰器的意思。

接下来学习装饰器的应用和原理。

现在有一个需求,将调用接口的每个函数的耗时取出来。

思考:在每个函数内部开始执行前打印时间,调用接口执行结束后打印时间,取两者的差值,每个函数都需要这样取做,非常麻烦,有没有什么更简便的方式呢?

答:装饰器可以实现,运用到了闭包的原理。

示例代码如下:

import time
#定义一个新功能 外部函数
def time_test(func):
    #内部函数 调用了被修饰的函数,同时在调用前后计算了时间,可以得到函数的耗时
    def inner(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        end_time = time.time()
        print(end_time - start_time)
        return func(*args,**kwargs)
    return inner
@time_test #装饰器名称,就是新功能的外部的函数名
def now(a,b,c):
    time.sleep(10)
    return a+b+c
now(1,2,4)

高阶函数

map函数

语法:map(func,iterable……)

计算列表中每个元素的平方

def square(x):
    return x ** 2
list_a = [1,2,4,5,6,7,8,9]
list_new = list(map(square,list_a))
print(list_new)

lambda表达式

两个列表相同位置的元素相加

list_a = [1,2,3,4,5,6,7,8,9]
list_b = [9,8,7,6,5,4,3,2,1]
list_new = list(map(lambda x,y:x+y,list_a,list_b))
print(list_new)

以list_a元素的值作为key,list_b元素的值作为value

list_a = [1,2,3,4,5,6,7,8,9]
list_b = ['a','b','c','d','e','f','g','h','i','j']
dict_new = dict(map(lambda x,y:[x,y],list_a,list_b))
print(dict_new)

reduce函数

reduce(function,sequence[,initial])

最多接收3个参数,第三个参数可传可不传

from functools import reduce
def f(x,y):
    return x+y
a = reduce(f,[1,2,3,4,5],80)
print(a)

filter

filter(function or None,iterable)

第一个是函数,第二个是序列,序列的每个元素作为参数传递给函数进行判断,将返回True的元素加到新的列表中。

过滤出奇数

def odd_num(n):
    return n % 2 == 1
odd_num = filter(odd_num,[1,2,3,4,5,6,7,8,9])
print(list(odd_num))

过滤出首字母大写的字符串,可以看到如果不用这个函数,需要新建一个空列表,然后遍历调用upper函数再判断,为True加到列表里,非常繁琐。

def upper(n):
    return n[0].isupper()
upper_str = filter(upper, ["Python", "javascript", "Learn", "Java", "Good","test"])
print(list(upper_str))
//如果不用filter这个函数
list_upper_str = []
for i in ["Python", "javascript", "Learn", "Java", "Good","test"]:
    res = upper(i)
    if res == True:
        list_upper_str.append(i)
print(list_upper_str)

sorted 

对列表中的元素进行排序

nums = [1,35,523,34,342,345,3342,32,54,52,78]
print(sorted(nums,reverse=True))

enumerate 

enumerate这个函数,是枚举的意思,enumerate(列表)

for x,y in enumerate(列表) 其中,x--是索引,y--是具体的值

enumerate(list,start=x) start表示下标从x开始

enumerate()函数将可迭代对象组合成一个索引序列,一般用在for循环中

在列表里找某个元素所在的索引,一般要用到enumerate这个函数

如下面的代码,在遍历列表时,可以取出元素所在的下标,enumerate函数的应用很常见

for index,value in enumerate(["python","Java","JavaScript","PHP","C++"]):
    print(index,value)

看下面应用的例子:一个数组,已知需要剔除数组的下标,给出剔除后的数组

不用遍历,要用enumerate函数,[n for i, n in enumerate(list_a) if i not in index_list]

list_a = ['香蕉','橘子','火龙果','梨','苹果','柚子','csdn']
index_list = [1,2,6]
lis = [n for i, n in enumerate(list_a) if i not in index_list]
print(list_a)

例子:取列表里第3、4、5位都为0的值所在的索引

[x for x, y in list(enumerate(list_a) if y[2:5] == ['0','0','0'])]

当然上面只是列出了常见的高级函数,除此之外,还有很多高级的函数,需要平时在应用时多加学习和练习。

赋值、深浅拷贝

在比较相等时,可以用==、is,那两者有什么区别?

is 比较的是两个引用是否指向了同一个对象

== 比较的是两个对象是否相等

可以看到下面的例子很形象,a is c返回的是False,两者的id也不同

而a is b返回的是True,两者的id是相同的

import copy

a = [1, 2, 3, 4, [9, 8, 7]]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
print("a的原id地址为:", id(a))
print("给b赋值后,其id地址为:", id(b))
print("浅拷贝a后,其id地址为:", id(c))
print("深拷贝a后,其id地址为:", id(d))
print("修改a的值后")
a.append(5)
a[4].append(10)
print("a的值变为:", a)
print("经过赋值的b的值是:", b)
print("经过浅拷贝后c的值是:", c)
print("经过深拷贝后d的值是:", d)

a = [1,2,3,4]
c = copy.deepcopy(a)
print(a is c) //False
print(a == c) //True

根据上面的代码,用=进行赋值时,b的id没有发生变化,而用到copy.deepcopy()时,c的id发生了变化,那这是为什么呢?

赋值,其本质是复制了新对象的引用,不会开辟新的内存空间,如果a的值改了,b的值当然也随之发生改动。

浅拷贝,创建新的对象,新对象是对原对象的引用。

而深拷贝,是对于一个对象所有层次的拷贝,而不是引用。也就是,把对象复制一遍,并且该对象中引用的其他对象也复制了一遍。

可以看下面的例子,理解下赋值、深浅拷贝。

浅拷贝只拷贝了一层,所以在改变[9,8,7]里元素的值时,也跟着改变了。

 此外,具体可参考下面的这篇文章。

Python中的赋值(复制)、浅拷贝与深拷贝 - 知乎 (zhihu.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MRJJ_9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值