Python基础(八) 万字详解深浅拷贝、生成器、迭代器以及装饰器_python 深拷贝迭代器(1)

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

8.1.4 是否可变

1、不可变类型:数字、字符串、元组

在生命周期中保持内容不变

  • 换句话说,改变了就不是它自己了(id变了)
  • 不可变对象的 += 操作 实际上创建了一个新的对象
x = 1
y = "Python"

print("x id:", id(x))
print("y id:", id(y))

x id: 140718440616768
y id: 2040939892664

x += 2
y += "3.7"

print("x id:", id(x))
print("y id:", id(y))

x id: 140718440616832
y id: 2040992707056

元组并不是总是不可变的

  • 元组中如果含有可以变的类型,则该元组还是可以变的
t = (1,[2])
t[1].append(3)

print(t)

(1, [2, 3])

2、可变类型:列表、字典、集合

  • id 保持不变,但是里面的内容可以变
  • 可变对象的 += 操作 实际在原对象的基础上就地修改
ls = [1, 2, 3]
d = {"Name": "Sarah", "Age": 18}

print("ls id:", id(ls))
print("d id:", id(d))

ls id: 2040991750856
d id: 2040992761608

ls += [4, 5]
d_2 = {"Sex": "female"}
d.update(d_2)            # 把d\_2 中的元素更新到d中

print("ls id:", id(ls))
print("d id:", id(d))

ls id: 2040991750856
d id: 2040992761608

8.1.5 列表操作的几个小例子

【例1】 删除列表内的特定元素

  • 方法1 存在运算删除法

缺点:每次存在运算,都要从头对列表进行遍历、查找、效率低

alist = ["d", "d", "d", "2", "2", "d" ,"d", "4"]
s = "d"
while True:
    if s in alist:
        alist.remove(s)
    else:
        break
print(alist)

['2', '2', '4']

  • 方法2 一次性遍历元素执行删除

首先alist被删除元素时不断在变,但是索引s是按照顺序来的,因此会造成可能跨过某一元素的现象,但是删除仍是按照从列表头开始扫描的顺序进行的。

alist = ["d", "d", "d", "2", "2", "d" ,"d", "4"]
for s in alist:
    if s == "d":
        alist.remove(s)      # remove(s) 删除列表中第一次出现的该元素
print(alist)

['2', '2', 'd', 'd', '4']

解决方法:使用负向索引

负向索引相当于倒序扫描,确保每次遍历的是列表头,同时删除的也是列表头。

alist = ["d", "d", "d", "2", "2", "d" ,"d", "4"]
for i in range(-len(alist), 0):
    if alist[i] == "d":
        alist.remove(alist[i])      # remove(s) 删除列表中第一次出现的该元素
print(alist)

['2', '2', '4']

【例2】 多维列表的创建

ls = [[0]\*10]\*5
ls

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

ls[0][0] = 1
ls

[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

因为下面的四个列表都是第一个列表的复制,因此第一个列表变了,下面的几个都会发生变化。

8.2 简洁的语法

image-20220928221738634

8.2.1 解析语法
ls = [[0]\*10 for i in range(5)]
ls

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

ls[0][0] = 1
ls

[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

这里都是独立创建的,因此互不影响。

1、解析语法的基本结构——以列表解析为例(也称为列表推导)

[expression for value in iterable if conditihon]

  • 三要素:表达式、可迭代对象、if条件(可选)

执行过程

(1)从可迭代对象中拿出一个元素

(2)通过if条件(如果有的话),对元素进行筛选

 若通过筛选:则把元素传递给表达式  
   
 若未通过:  则进入(1)步骤,进入下一次迭代

(3)将传递给表达式的元素,代入表达式进行处理,产生一个结果

(4)将(3)步产生的结果作为列表的一个元素进行存储

(5)重复(1)~(4)步,直至迭代对象迭代结束,返回新创建的列表

# 等价于如下代码
result = []
for value in iterale:
    if condition:
        result.append(expression)

【例】求20以内奇数的平方

squares = []
for i in range(1,21):
    if i%2 == 1:
        squares.append(i\*\*2)
print(squares)   

[1, 9, 25, 49, 81, 121, 169, 225, 289, 361]

squares = [i\*\*2 for i in range(1,21) if i%2 == 1]
print(squares) 

[1, 9, 25, 49, 81, 121, 169, 225, 289, 361]

支持多变量

x = [1, 2, 3]
y = [1, 2, 3]

results = [i\*j for i,j in zip(x, y)]
results

[1, 4, 9]

支持循环嵌套

colors = ["black", "white"]
sizes = ["S", "M", "L"]
tshirts = ["{} {}".format(color, size) for color in colors for size in sizes]
tshirts

['black S', 'black M', 'black L', 'white S', 'white M', 'white L']

2、其他解析语法的例子

  • 解析语法构造字典(字典推导)
squares = {i: i\*\*2 for i in range(10)}
for k, v in squares.items():
    print(k, ": ", v)

0 :   0
1 :   1
2 :   4
3 :   9
4 :   16
5 :   25
6 :   36
7 :   49
8 :   64
9 :   81

  • 解析语法构造集合(集合推导)
squares = {i\*\*2 for i in range(10)}
squares

{0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

  • 生成器表达式
squares = (i\*\*2 for i in range(10))
squares

<generator object <genexpr> at 0x000001DB37A58390>

colors = ["black", "white"]
sizes = ["S", "M", "L"]
tshirts = ("{} {}".format(color, size) for color in colors for size in sizes)
for tshirt in tshirts:
    print(tshirt)

black S
black M
black L
white S
white M
white L

8.2.2 条件表达式

expr1 if condition else expr2

【例】将变量n的绝对值赋值给变量x

n = -10
if n >= 0:
    x = n
else:
    x = -n
x

10

n = -10
x = n if n>= 0 else -n
x

10

条件表达式和解析语法简单实用、运行速度相对更快一些,相信大家会慢慢的爱上它们

8.3 三大神器

image-20220928221753540

8.3.1 生成器
ls = [i\*\*2 for i in range(1, 1000001)]

for i in ls:
    pass

缺点:占用大量内存

生成器

(1)采用惰性计算的方式

(2)无需一次性存储海量数据

(3)一边执行一边计算,只计算每次需要的值

(4)实际上一直在执行next()操作,直到无值可取

1、生成器表达式

  • 海量数据,不需存储
squares = (i\*\*2 for i in range(1000000))

for i in squares:
    pass

  • 求0~100的和

无需显示存储全部数据,节省内存

sum((i for i in range(101))) # 求和,里面是一个生成器

5050

2、生成器函数——yield

  • 生产斐波那契数列

数列前两个元素为1,1 之后的元素为其前两个元素之和

def fib(max):
    ls = []
    n, a, b = 0, 1, 1
    while n < max:
        ls.append(a)
        a, b = b, a + b
        n = n + 1
    return ls


fib(10)

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

中间尝试

def fib(max):
    n, a, b = 0, 1, 1
    while n < max:
        print(a)
        a, b = b, a + b
        n = n + 1


fib(10)

1
1
2
3
5
8
13
21
34
55

构造生成器函数

在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

def fib(max):
    n, a, b = 0, 1, 1
    while n < max:
        yield a
        a, b = b, a + b
        n = n + 1
        

fib(10)

<generator object fib at 0x000001BE11B19048>

for i in fib(10):
    print(i)

1
1
2
3
5
8
13
21
34
55

8.3.2 迭代器

1、可迭代对象

可直接作用于for循环的对象统称为可迭代对象:Iterable

(1)列表、元组、字符串、字典、集合、文件

可以使用isinstance()判断一个对象是否是Iterable对象

from collections import Iterable

isinstance([1, 2, 3], Iterable)

True

isinstance({"name": "Sarah"}, Iterable)

True

isinstance('Python', Iterable)

True

(2)生成器

squares = (i\*\*2 for i in range(5))
isinstance(squares, Iterable)

True

生成器不但可以用于for循环,还可以被next()函数调用

print(next(squares))
print(next(squares))
print(next(squares))
print(next(squares))
print(next(squares))

0
1
4
9
16

直到没有数据可取,抛出StopIteration

print(next(squares))

---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-66-f5163ac9e49b> in <module>
----> 1 print(next(squares))


StopIteration: 

可以被next()函数调用并不断返回下一个值,直至没有数据可取的对象称为迭代器:Iterator

2、迭代器

可以使用isinstance()判断一个对象是否是Iterator对象

(1) 生成器都是迭代器

from collections import Iterator

squares = (i\*\*2 for i in range(5))
isinstance(squares, Iterator)

True

(2) 列表、元组、字符串、字典、集合不是迭代器

isinstance([1, 2, 3], Iterator)

False

可以通过iter(Iterable)创建迭代器

isinstance(iter([1, 2, 3]), Iterator)

True

for item in Iterable 等价于:

先通过iter()函数获取可迭代对象Iterable的迭代器
  
然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item
   
当遇到StopIteration的异常后循环结束

(3)zip enumerate 等itertools里的函数是迭代器

x = [1, 2]
y = ["a", "b"]
zip(x, y)

<zip at 0x1be11b13c48>

for i in zip(x, y):
    print(i)
    
isinstance(zip(x, y), Iterator)

(1, 'a')
(2, 'b')

True

numbers = [1, 2, 3, 4, 5]
enumerate(numbers)

<enumerate at 0x1be11b39990>

for i in enumerate(numbers):
    print(i)
    
isinstance(enumerate(numbers), Iterator)

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)

True

(4) 文件是迭代器

with open("测试文件.txt", "r", encoding = "utf-8") as f:
    print(isinstance(f, Iterator))

True

(5)迭代器是可耗尽的

squares = (i\*\*2 for i in range(5))
for square in squares:
    print(square)

0
1
4
9
16

for square in squares:
    print(square)

再迭代不出来了,因为已经耗尽了

(6)range()不是迭代器

numbers = range(10)
isinstance(numbers, Iterator)

False

print(len(numbers))   # 有长度
print(numbers[0])     # 可索引
print(9 in numbers)   # 可存在计算
next(numbers)         # 不可被next()调用

10
0
True

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-76-7c59bf859258> in <module>
      2 print(numbers[0])     # 可索引
      3 print(9 in numbers)   # 可存在计算
----> 4 next(numbers)         # 不可被next()调用


TypeError: 'range' object is not an iterator

for number in numbers:
    print(number)

0
1
2
3
4
5
6
7
8
9

不会被耗尽。

for number in numbers:
    print(number)

0
1
2
3
4
5
6
7
8
9

可以称range()为懒序列

它是一种序列
  
但并不包含任何内存中的内容
  
而是通过计算来回答问题

8.3.3 装饰器

1、需求的提出

(1)需要对已开发上线的程序添加某些功能

(2)不能对程序中函数的源代码进行修改

(3)不能改变程序中函数的调用方式

比如说,要统计每个函数的运行时间

def f1():
    pass


def f2():
    pass


def f3():
    pass

f1()
f2()
f3()

没问题,我们有装饰器!!!

2、函数对象

函数是Python中的第一类对象

(1)可以把函数赋值给变量

(2)对该变量进行调用,可实现原函数的功能

def square(x):
    return x\*\*2

print(type(square))      # square 是function类的一个实例

<class 'function'>

pow_2 = square          # 可以理解成给这个函数起了个别名pow\_2
print(pow_2(5))
print(square(5))

25
25

可以将函数作为参数进行传递

3、高阶函数

(1)接收函数作为参数

(2)或者返回一个函数

满足上述条件之一的函数称之为高阶函数

def square(x):
    return x\*\*2


def pow\_2(fun):
    return fun


f = pow_2(square)
f(8)

64

print(f == square)

True

4、 嵌套函数

在函数内部定义一个函数

def outer():
    print("outer is running")
    
    def inner():
        print("inner is running")
        
    inner()


outer()

outer is running
inner is running

5、闭包

def outer():
    x = 1
    z = 10
    
    def inner():
        y = x+100
        return y, z
        
    return inner


f = outer()                # 实际上f包含了inner函数本身+outer函数的环境
print(f)

<function outer.<locals>.inner at 0x000001BE11B1D730>

print(f.__closure__)         # \_\_closure\_\_属性中包含了来自外部函数的信息
for i in f.__closure__:
    print(i.cell_contents)

(<cell at 0x000001BE0FDE06D8: int object at 0x00007FF910D59340>, <cell at 0x000001BE0FDE0A98: int object at 0x00007FF910D59460>)
1
10

res = f()
print(res)

(101, 10)

闭包:延伸了作用域的函数

如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,则该函数称为闭包

最后

不知道你们用的什么环境,我一般都是用的Python3.6环境和pycharm解释器,没有软件,或者没有资料,没人解答问题,都可以免费领取(包括今天的代码),过几天我还会做个视频教程出来,有需要也可以领取~

给大家准备的学习资料包括但不限于:

Python 环境、pycharm编辑器/永久激活/翻译插件

python 零基础视频教程

Python 界面开发实战教程

Python 爬虫实战教程

Python 数据分析实战教程

python 游戏开发实战教程

Python 电子书100本

Python 学习路线规划

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值