哈喽大家好,我是咸鱼。

前天有个小伙伴找到我,给了我一段 python 代码:

a = [1, 2]
a[1] = a
print(a[1])

然后问我为什么结果是 [1, [...]],我一看这个问题有意思,我说三言两语解释不清楚,我写篇文章到时候你看下吧,于是有了今天这篇文章。

在正式开始之前,让我们先弄清楚一些概念。

对象?变量?引用?赋值?

"Python 中一切皆对象",相信这句话大家在学习 Python 的时候都已经听的耳朵起茧子了吧。

在 Python 中,所有的数据都是对象,包括基本数据类型(例如整数、浮点数、字符串等)以及用户自定义的类型(类的实例等)。

对象其实是内存中分配的一块空间,用来存储其值。每个对象都有一个唯一的标识符(id),可以通过 id() 函数获取

不但如此,每一个对象都具有两个标准的头部信息:

  • 类型标志符(Type Identifier): 每个对象都有一个类型信息,可以通过 type() 函数获取。
  • 引用计数器(Reference Counter): 引用计数器表示有多少个引用指向该对象,当引用计数降为零时,对象会被垃圾回收。( Python 也使用其他垃圾回收机制,例如循环垃圾回收器来处理引用环的情况。)

在 Python 中,变量实际上是对象的【引用】,而不是对象本身的【存储】。当我们执行赋值语句时,会自动建立变量和对象之间的关系,即引用。

变量就像是一个指针,【指向】内存中存储对象的位置。

我们来看一个例子:

a = 1
b = a
a = a + 1

首先将 1 赋值于 a,即 a 指向了 1 这个对象。

接着 b = a 则表示让变量 b 也同时指向 1 这个对象。Python 的对象可以被多个变量所指向(引用)。

最后执行 a = a + 1,在这里需要注意的是,Python 的基础数据类型(例如整型(int)、字符串(string)等)是不可变的

所以,a = a + 1,并不是让 a 的值增加 1,而是表示重新创建了一个新的值为 2 的对象,并让 a 指向它。但是 b 仍然不变,仍然指向 1 这个对象。

因此最后的结果是,a 的值变成了 2,而 b的值不变仍然是 1



通过这个例子你可以看到,这里的 ab,开始只是两个指向同一个对象的变量而已,或者你也可以把它们想象成同一个对象的两个名字。

简单的赋值 b = a,并不表示重新创建了新对象,只是让同一个对象被多个变量指向或引用。

为什么?

在了解了变量、对象、引用、赋值之后,我们回到一开始的例子。

a = [1, 2]
a[1] = a
print(a[1])

这段代码中创建了一个列表 a,其中包含两个元素(1 和 2),然后 a[1] 被赋值为整个列表 aa[1] = a),当你打印 a[1] 时,它实际上是指向列表 a 本身。

a = [1, <reference to a>]

这样就会导致循环引用的问题。

我们来分步骤解释一下这个过程:

  • a 是一个包含两个元素的列表:[1, 2]
  • a[1] = a 将列表 a 的第二个元素设为 a,即a[1]实际上指向列表 a 本身,形成了一个循环引用
  • 当打印 a[1] 时,Python 发现这是一个特殊的情况,即这个元素是对列表本身的引用。为了避免无限循环,Python 会显示 ...,表示引用已经进入了一个循环。因此看到的结果是 [1, [...]]

那如何避免循环引用呢?可以使用浅拷贝或者深拷贝来解决。

我们用浅拷贝来试一下:

import copy

a = [1, 2]
a[1] = copy.copy(a)
print(a[1]) # 结果是[1,2]

浅拷贝创建一个新的对象,然后将原始对象中的元素复制到新对象中。但是,如果原始对象的元素是可变对象(例如列表),那么浅拷贝只会复制对象的引用而不是对象本身。

就比如上面的例子:

  • a = [1, 2] 创建了一个列表 a,其中有两个元素 1 和 2。
  • a[1] = copy.copy(a) 将列表 a 的第二个元素修改为对列表 a 的浅拷贝。
  • 打印 a[1],此时 a[1] 指向了新的对象 [1, 2]

关于浅拷贝深拷贝的内容咸鱼后期再写篇文章介绍一下!

Python 变量?对象?引用?赋值?一个例子解释清楚的更多相关文章

  1. Python 变量 对象 引用

    1.变量 变量第一次赋值时被创建,变量在使用前必须赋值 变量本身没有类型,变量类型为它引用的对象类型: 变量在使用时被替换成它引用的对象 2.对象 对象本身具有计数和类型,变量引用对象,当对象的引用变 ...

  2. 细说PHP-5.3.4变量的引用赋值

    变量总是传值赋值.也就是说,当讲一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量.这意味着,当一个变量的值赋予另个一变量时,改变其中一个变量的值,将不会影响到另一个变量.PHP中提供了 ...

  3. python之局部变量引用赋值前的结果

    通过正则表达式,实现加减 昨晚在做计算器的时候,被一个BUG搞懵比了.现在再看看,发现我好小白啊~~ #++- num = input("please input:") sa = ...

  4. Python——变量的引用和函数的参数和返回值的传递方式

    变量的引用 在python中,所有的变量都是指向地址,变量本身不保存数据,而是保存数据在内存中的地址.我们用下面的程序来理解: a = 10 print(id(a)) a = 11 print(id( ...

  5. python 结合redis 队列 做一个例子

    结合redis 队列 做了一个例子 #!/usr/bin/env python # coding: utf-8 # @Time : 2018/12/21 0021 13:57 # @Site : # ...

  6. python变量、引用、拷贝之间的关系

    Python中一切皆为对象,不管是集合变量还是数值型or字符串型的变量都是一个引用,都指向对应内存空间中的对象. 简而言之: 变量直接赋值:新变量本身及其内部的元素都与原变量指向相同的内存空间,并且值 ...

  7. python变量的引用,浅拷贝

    python的变量是对象引用 l1和l2引用的相同的对象,所以会相互影响 元组不变的是引用的物理地址,如果引用的对象是可变的,那么远祖也会发生变化 但是t1[2]的id时钟没有发生变化 2 默认是浅拷 ...

  8. python变量和变量赋值的几种形式

    动态类型的语言 python是动态类型的语言,不需要声明变量的类型. 实际上,python中的变量仅仅只是用来保存一个数据对象的地址.无论是什么数据对象,在内存中创建好数据对象之后,都只是把它的地址保 ...

  9. Python中的可变、不可变对象和赋值技巧序列解包

    可变对象和不可变对象 在python中一切皆对象.在Python中不存在所谓的值传递调用,一切传递都是对象的引用,也可认为是传址. python中,对象分为可变(mutable)和不可变(immuta ...

  10. python按引用赋值和深、浅拷贝

    按引用赋值而不是拷贝副本 在python中,无论是直接的变量赋值,还是参数传递,都是按照引用进行赋值的. 在计算机语言中,有两种赋值方式:按引用赋值.按值赋值.其中按引用赋值也常称为按指针传值(当然, ...

随机推荐

  1. 单位换算详解:bit、Byte、bps、Bps、pps、Gbps的单位详细说明及换算

    当谈论计算机存储和数据传输时,"bit"(比特)和"Byte"(字节)是两个常见的术语,它们具有不同的含义和用途. 位(bit):"位"来自 ...

  2. VSFTPD2.3.4(笑脸漏洞)复现

    vsftpd2.3.4笑脸漏洞复现 目标服务器:metasploitable2(192.168.171.11) 渗透机:Kali(192.168.171.21) 方法一:手动复现 首先用kali扫描一 ...

  3. JNA入门(一)

    JNA入门,代码在github写得明明白白:https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md 一. ...

  4. CSS3学习笔记-动画

    CSS3中提供了许多有趣和实用的动画效果,可以使页面更加生动有趣,下面介绍一些常用的动画效果. @keyframes规则 使用@keyframes规则可以创建一系列动画帧,并定义它们的状态和样式,在页 ...

  5. 一文带你了解GaussDB(DWS) 的Roach逻辑备份实现原理

    摘要:Roach工具是GaussDB(DWS)推出的一款主力的备份恢复工具,包含物理与逻辑备份两种主要能力,本文着重于讲解Roach逻辑备份的实现原理. 一.简介 在大数据时代,数据的完整和可靠性成为 ...

  6. 一段java代码是如何执行的?

    摘要:当你学会了java语言之后,你写了一些代码,然后你想要执行你的代码,来达成某些功能.那么,你都知道这段java代码都是如何执行的吗? 本文分享自华为云社区<一段java代码是如何执行的&g ...

  7. GaussDB(for Redis)双活容灾支持4大应用场景,为业务安全保驾护航

    摘要:GaussDB(for Redis)的双活解决方案,支持同域主备.同域双主.异地主备.异地双主四大应用场景,提供了安全可靠的容灾能力. 一场火灾引发的思考 2021年3月10日,欧洲某云服务提供 ...

  8. 华为云开天aPaaS 上线,服务千万开发者,使能行业场景化创新

    摘要:9月25日,华为云在华为全联接2021发布四大生态策略,并宣布2022年投入1亿美元升级沃土云创计划.华为云开天aPaaS正式上线,实现经验即服务,使能行业场景化创新. 本文分享自华为云社区&l ...

  9. Go语言逆向技术:常量字符串

    摘要:Go语言源代码编译成二进制文件后,源代码中的字符串存放在哪里?是如何组织的? 本文分享自华为云社区<go语言逆向技术之---常量字符串解密>,作者:安全技术猿. Go语言源代码编译成 ...

  10. C#开源免费的Blazor图表库

    前言 今天分享一款基于ApexCharts.js封装的.C#开源免费的Blazor图表库:Blazor-ApexCharts. 10款值得推荐的Blazor UI组件库 全面的ASP.NET Core ...