【Python学习】——语言风格(变量赋值、深浅拷贝、for循环陷阱)

目录

1、赋值

 2、赋值的分类——引用赋值、值赋值

1) 不可变对象引用赋值——字符串、数值、元组等

2)可变对象引用赋值——列表、集合、字典

3)可变与不可变对象的引用赋值内部分析

4)在py文件中,和作用域有关,如在同一个函数中的相同值的变量是相等的,即值相等,地址也相等

3、深拷贝与浅拷贝

4、循环——序列和非序列的循环中进行元素的修改


 

1、赋值

# 赋值包含多种赋值方式,一般赋值、元组赋值、序列赋值、解包赋值
a = "long"
b,c = "1",2
d,e,f,g = "long"
h,*i = "long"
print(a)
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
print(h)
print(i)

long
1
2
l
o
n
g
l
['o', 'n', 'g']

当使用一个*前缀变量的时候,表示将序列对应的元素全部收集到一个列表中(注意,总是一个列表),这个列表名为*开头的那个变量名。*号可以出现在任意位置处,只要赋值的时候能前后对应位置关系即可。

注意其中的几个关键字:序列、对应的元素、列表

  • 序列意味着可以是列表、元组、字符串等等
  • 列表意味着只要收集不报错,赋值给解包变量的一定是一个列表
  • 对应的元素意味着可能收集到0或任意个元素到列表。

不管如何,收集的结果总是列表,只不过可能是空列表或者只有一个元素的列表。

 

两个注意事项:

  1. 因为序列解包是根据元素位置来进行赋值的,所以不能出现多个解包变量
  2. 如果将序列直接赋值给单个解包变量时(即没有普通变量),这个解包变量必须放在列表或元组中
a,*b,c,*d = L     # 错误
*a = L            # 错误
[*a] = L          # 正确
(*a) = L          # 正确

 2、赋值的分类——引用赋值、值赋值

引用赋值——指的是将内存地址赋值给变量来实现赋值

1) 不可变对象引用赋值——字符串、数值、元组等

a = 1000

b = a

a = 2000

前两行b=a是将1000的地址赋值给b,即a和b都是指向值1000的内存地址。第三行a=2000是对a重新进行赋值,因为数值是不可改变的对象,因此会先开辟一个内存地址用于存储2000,然后将a指向2000

不可变对象变量之间不会互相影响,即如果一开始两个变量指向同一个内存地址,当其中一个变量的值发生了改变的时候,另一个变量不会受到影响

对于不可变对象,修改变量的值意味着在内存中要新创建一个数据对象

a = 10000
b = a
a = 20000>>> a,b
(20000, 10000)

2)可变对象引用赋值——列表、集合、字典

对于可变对象,比如列表,它是在"原处修改"数据对象的(注意加了双引号)。比如修改列表中的某个元素,列表的地址不会变,还是原来的那个内存对象,所以称之为"原处修改"。例如:

L1 = [111,222,333]
L2 = L1
L1[1] = 2222>>> L1,L2
([111, 2222, 333], [111, 2222, 333])

L2是通过引用赋值得到的值,值为可变对象列表,当对L1改变一个列表元素时,其列表的地址不会发生改变,因此其L2的值也会发生相应的改变

L1[1]赋值的前后,数据对象[111,222,333]的地址一直都没有改变,但是这个列表的第二个元素的值已经改变了。因为L1和L2都指向这个列表,所以L1修改第二个元素后,L2的值也相应地到影响。也就是说,L1和L2仍然是同一个列表对象[111,2222,333]

结论是:对于可变对象,变量之间是相互影响的

3)可变与不可变对象的引用赋值内部分析

可变对象和不可变对象的赋值形式虽然一样,但是修改数据时的过程不一样。

对于不可变对象,修改数据是直接在堆内存中新创建一个数据对象。如图:

对于可变对象,修改这个可变对象中的元素时,这个可变对象的地址不会改变,所以是"原处修改"的。但需要注意的是,这个被修改的元素可能是不可变对象,可能是可变对象,如果被修改的元素是不可变对象,就会创建一个新数据对象,并引用这个新数据对象,而原始的那个元素将等待垃圾回收器回收。

>>> L=[333,444,555]
>>> id(L),id(L[1])
(56583832, 55771984)
>>> L[1]=4444
>>> id(L),id(L[1])
(56583832, 55771952)

如图所示:

4)在py文件中,和作用域有关,如在同一个函数中的相同值的变量是相等的,即值相等,地址也相等

3、深拷贝与浅拷贝

1)深拷贝

完全创建一个新的数据对象,不会受到其他变量的元素值变化的影响

2)浅拷贝,只是拷贝了第一层的元素,若第一层的元素是可变对象,则引用的是可变对象的地址,因此还是会受到其他变量的影响

# 引用赋值——只是得到了地址
print("赋值----------------------")
L = [1,2,[3,4,5]]
L2 = L
print("修改元素前-----------")
print(L)
print(L2)
print("修改元素后-----------")
L[0] = 0
print(L)
print(L2)

赋值----------------------
修改元素前-----------
[1, 2, [3, 4, 5]]
[1, 2, [3, 4, 5]]
修改元素后-----------
[0, 2, [3, 4, 5]]
[0, 2, [3, 4, 5]] 

print("浅拷贝------------------------")print("浅拷贝1------------------------")
# 浅拷贝——只是拷贝了第一层的元素,若为不可变元素,则会重新为元素创建一个新的数据对象,若为可变数据对象,则只是拷贝了地址
L = [1,2,[3,4,5],6]
L1 = L.copy()
print("修改不可变对象的元素前-----------")
print(L)
print(L1)
print("修改不可变对象的元素后-----------")
L[0] = 0
print(L)
print(L1)print("浅拷贝1------------------------")
L = [1,2,[3,4,5],6]
L1 = L.copy()
print("修改可变对象的元素前-----------")
print(L)
print(L1)
print("修改可变对象的元素后-----------")
L[2][0] = 0
print(L)
print(L1)print("浅拷贝2------------------------")
L = [1,2,[3,4,5]]
L3 = L[:]
print("修改元素前-----------")
print(L)
print(L3)
print("修改元素后-----------")
L[0] = 0
L[2][0] = 0
print(L)
print(L3)

 

浅拷贝------------------------
浅拷贝1------------------------
修改不可变对象的元素前-----------
[1, 2, [3, 4, 5], 6]
[1, 2, [3, 4, 5], 6]
修改不可变对象的元素后-----------
[0, 2, [3, 4, 5], 6]
[1, 2, [3, 4, 5], 6]
浅拷贝1------------------------
修改可变对象的元素前-----------
[1, 2, [3, 4, 5], 6]
[1, 2, [3, 4, 5], 6]
修改可变对象的元素后-----------
[1, 2, [0, 4, 5], 6]
[1, 2, [0, 4, 5], 6]
浅拷贝2------------------------
修改元素前-----------
[1, 2, [3, 4, 5]]
[1, 2, [3, 4, 5]]
修改元素后-----------
[0, 2, [0, 4, 5]]
[1, 2, [0, 4, 5]]

from copy import deepcopy
print("深拷贝------------------------")
L = [1,2,[3,4,5]]
L1 = deepcopy(L)
L[0] = 0
L[2][0] = 0
print(L)
print(L1)

深拷贝------------------------
[0, 2, [0, 4, 5]]
[1, 2, [3, 4, 5]]

一般我们使用到的都是浅拷贝

4、循环——序列和非序列的循环中进行元素的修改

https://www.cnblogs.com/f-ck-need-u/p/10129317.html

1)列表进行原地修改时(L+=[val1,val2]),进行后面的迭代时,进行迭代的是修改后的列表,因为for是一个迭代器,使用的是next,即通过索引进行的,因此列表原地修改会导致元素出现奇怪的现象

为了避免这种情况,我们对列表进行修改时,建议生成一个新的列表对象来进行存放

L = ['a','b','c','d','e']## 原处修改列表,新元素f、g也会被迭代
for i in L:if i in "de":L += ["f", "g"]print(i)## 创建新列表,新元素f、g不会被迭代
for i in L:if i in "de":L = L + ["f", "g"]print(i)

这个for迭代器在迭代刚开始的时候,先找到L所指向的迭代对象,即内存中的[1,2,3,4]。如果迭代过程中如果L变成了一个集合,或另一个列表对象,for的迭代并不会收到影响。但如果是在原处修改这个列表,那么迭代将会收到影响,例如新增元素也会被迭代到。

这里通过列表索引来进行元素的遍历和修改即可避免上面的情况

2)迭代一个列表,迭代过程中删除一个列表元素。

L = ['a','b','c','d','e']
for i in L:if i in "bc":L.remove(i)print(i)print(L)

输出的结果将是:

b
['a', 'c', 'd', 'e']

这个for循环的本意是想删除b、c元素,但结果却只删除了b。通过结果可以发现,c根本就没有被for迭代。之所以会这样,是因为迭代到b的时候,满足if条件,然后删除了列表中的b元素。正因为删除操作,使得列表中b后面的元素整体前移一个位置,也就是c元素的索引位置变成了index=1,而index=1的元素已经被for迭代过(即元素b),使得c幸运地逃过了for的迭代。

3)迭代的是字典或者集合时,虽然两者都是可变序列,但是时无序的,因此在迭代的过程中,是不允许字典或者集合发生改变的,否则会报错

D = {'a':1,'b':2,'c':3,'d':4,'e':5}for i in D:if i in "bc":del D[i]print(i)print(D)

报错:

b
Traceback (most recent call last):File "g:/pycode/lists.py", line 12, in <module>for i in D:
RuntimeError: dictionary changed size during iteration
S = {'a','b','c','d','e'}for i in S:if i in "bc":S.remove(i)print(i)print(S)

报错:

b
Traceback (most recent call last):File "g:/pycode/lists.py", line 4, in <module>for i in L:
RuntimeError: Set changed size during iteration

若想修改字典的话,我们可以复制一份数据对象作为副本,然后将副本进行迭代,将原来的字典或集合作为修改对象 

D = {'a':1,'b':2,'c':3,'d':4,'e':5}for i in D.copy():if i in "bc":D.pop(i)print(i)
print(D)S = {'a','b','c','d','e'}for i in S.copy():if i in "bc":S.remove(i)print(i)
print(S)

 注意:在进行可变对象数据对象的迭代与修改时,我们只需要将迭代对象和修改对象分开就不会出现上述的错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/255862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

判断庄家是否出货

1. 大盘处于强势的时候 日平均线在横盘的时候&#xff0c;缓慢拉升然后急剧下跌 高位盘整的时候 2. 有利好消息发布的时候 因为庄家会利用这个对于散户来说这个买入时机来进行出货操作&#xff0c;可见庄家真是阴险狡诈转载于:https://www.cnblogs.com/dcz1001/p/6115893.html

【深度学习】——常见深度学习模型总结、anchor-free和anchor-based

目录 1、faster rcnn&#xff1a; 2、SSD&#xff1a; 3、YOLOv1: 小结&#xff1a; 拓展&#xff1a;anchor-based和anchor-free anchor 1、faster rcnn&#xff1a; FasterRcnn 算法原理讲解笔记&#xff08;非常详细&#xff09;https://blog.csdn.net/xjtdw/article…

真静态和伪静态的区别

首先肯定的是纯静态和伪静态都是SEO的产物&#xff0c;但纯静态和伪静态还是有很大区别的。 纯静态是生成真实的HTML页面保存到服务器端&#xff0c;用户访问时直接访问这 个HTML页面即可&#xff0c;从而大大的减轻了服务器压力&#xff08;如dedecms就是采用的纯静态&#xf…

非常有趣的Console

console觉醒之路&#xff0c;打印个动画如何&#xff1f; 原文地址: http://www.helloweba.com/view-blog-383.html 批量去掉或替换文本中的换行符&#xff08;notepad、sublime text2&#xff09; 原文地址&#xff1a;http://m.blog.csdn.net/article/details?id43228729 有…

假期实践

第一天 地点:杭州颐高数码城 第一天&#xff0c;我来到了自己家附近的颐高数码城。文三路这边有一个卖数码产品的一条街&#xff0c;这里也是最贴近我专业实践的地方&#xff0c;所以第一天的实践我选择了这里。 2001年开业的颐高数码广场座落于“电子一条街”文三路、学院路口…

3.AngularJS-过滤器

转自&#xff1a;https://www.cnblogs.com/best/p/6225621.html 二、过滤器 使用过滤器格式化数据&#xff0c;变换数据格式&#xff0c;在模板中使用一个插值变量。语法格式如下&#xff1a; {{ express | filter:parameter1:p2:p3… | … | …}} 过滤器分了内置过滤器与自定义…

【深度学习】——训练过程

包含哪些层 训练过程 其实就是yf(x)的求参过程&#xff0c;先给参数一个初始值&#xff0c;然后根据初始函数计算得到预测值&#xff0c;根据预测值和真值计算损失&#xff0c;然后又根据损失函数进行反向传播更新参数&#xff0c;更新参数后&#xff0c;再次计算预测值&#…

thinkphp自定义模板标签(一)

thinkphp内置的foreach和include等模板标签使用是非常方便的&#xff1b;但是内置的那些标签只能满足常用功能&#xff0c;个性化的功能就需要我们自己编写自定义模板标签了&#xff1b;下面就是要讲解如何实现&#xff1b; 示例环境&#xff1a;thinkphp3.2.3 thinkphp的模板标…

【深度学习】——激活函数(sigmoid、tanh、relu、softmax)

目录 激活函数 1、作用 2、常用激活函数 3、衡量激活函数好坏的标准&#xff1a; 4、不同的激活函数 1&#xff09;sigmoid 2&#xff09;tanh函数 3&#xff09;RULE函数和leak-relu函数 4&#xff09;softmax函数 激活函数 1、作用 如果只是线性卷积的话&#xff0c…

【深度学习】——分类损失函数、回归损失函数、交叉熵损失函数、均方差损失函数、损失函数曲线、

目录 代码 回归问题的损失函数 分类问题的损失函数 1、 0-1损失 (zero-one loss) 2、Logistic loss 3、Hinge loss 4、指数损失(Exponential loss) 机器学习的损失函数 Cross Entropy Loss Function&#xff08;交叉熵损失函数&#xff09; 交叉熵优点 Mean Squared E…

【转】应用架构一团糟?如何将单体应用改造为微服务

概述 将单体应用改造为微服务实际上是应用现代化的过程&#xff0c;这是开发者们在过去十年来一直在做的事情&#xff0c;所以已经有一些可以复用的经验。 全部重写是绝对不能用的策略&#xff0c;除非你要集中精力从头构建一个基于微服务的应用。虽然听起来很有吸引力&#xf…

Linux 解决ssh连接慢的问题

备份文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak 编辑文件 vi /etc/ssh/sshd_config 输入/ 查找GSSAPIAuthentication 设置如下 GSSAPIAuthentication no # 是否允许使用基于 GSSAPI 的用户认证。默认值为"no"。仅用于SSH-2 详细解释 输入/ 查找UseDNS …

【Hibernate】Hibernate系列6之HQL查询

HQL查询 6.1、概述 6.2、分页查询 6.3、命名查询 6.4、投影查询-部分字段查询 6.5、报表查询 6.6、迫切左外连接、左外连接 6.7、迫切内连接、内连接 6.8、QBC查询、本地查询 转载于:https://www.cnblogs.com/junneyang/p/5254641.html

【深度学习】——梯度下降优化算法(批量梯度下降、随机梯度下降、小批量梯度下降、Momentum、Adam)

目录 梯度 梯度下降 常用的梯度下降算法&#xff08;BGD&#xff0c;SGD&#xff0c;MBGD&#xff09; 梯度下降的详细算法 算法过程 批量梯度下降法&#xff08;Batch Gradient Descent&#xff09; 随机梯度下降法&#xff08;Stochastic Gradient Descent&#xff09…

双工位机器人 焊接夹具注意事项 o(╯□╰)o

焊接夹具设计注意事项 一套完美的夹具,需要机械设计人员正确的设计思想&#xff0c;良好的配件质量&#xff0c;钳工负责认真的装配质量,卡具在使用中不断的修磨和改进&#xff0c;才会达到好的效果。 本人非机械设计&#xff0c;只是在使用焊接卡具过程中遇到了很多卡具设计上…

【机器学习】——《机器学习实战》面试复习

目录 一、机器学习概念 二、机器学习步骤 三、有监督学习 1、k-近邻算法 核心思想 实例&#xff1a;手写数字的识别 优缺点&#xff1a; 2、决策树 相关概念 核心思想 一些小技巧 优缺点 3、神经网络 4、SVM——支持向量机 核心思想 SVM和SVR的区别 ​ 优缺点…

ubuntu安装LDAP

参考文献&#xff1a; https://help.ubuntu.com/12.04/serverguide/openldap-server.html&#xff08;最主要的&#xff09; http://www.linuxidc.com/Linux/2011-08/40020.htm http://blog.chinaunix.net/uid-24276740-id-3360306.html 前言 在网上搜索ldap的安装配置&#xf…

ABB机器人之LOADDATA

ABB机器人之LOADDATA loaddata是用来描述连接到机器人机械接口的负载&#xff08;机器人的安装法兰&#xff09;。loaddata数据通常定义有效载荷或负荷&#xff08;通过指令gripload设置机器人抓手负载 或mechunitload指令设置变位机负载。loaddata通常也作为tooldata的一部分&…

【深度学习】——性能指标(ROC、MAP、AUC等)

目录 一、分类任务性能指标 1、混淆矩阵 2、精确度ACCURACY 正确数/总数 3、查全率&#xff08;RECALL&#xff09;——真正正样本中预测正确的比例 4、查准率&#xff08;precision&#xff09;——预测为正样本中的预测正确的比例 5、F-score——对查准率和查全率进行结…

【深度学习】——过拟合的处理方法

目录 一、什么是过拟合&#xff1f;&#xff08;overfitting&#xff09; 二、过拟合的表现&#xff08;判定方法&#xff09; 训练集、测试集、验证集区别 测试集与验证集的区别 三、产生过拟合的原因 1、样本方面 2、模型方面 四、避免过拟合的方法 1、样本方面 1&…