python@可变对象和不可变对象@按值传递和引用传递@python运行可视化工具

文章目录

    • 可变对象和不可变对象🎈
      • 可视化工具🎈
      • 可变对象和id
      • eg
      • eg
      • 变量名和内存地址🎈
      • 函数调用对参数的修改😂
      • Note
    • 按值传递vs引用传递
      • note🎈
      • 如何借助函数修改外部变量的值?
      • Note

可变对象和不可变对象🎈

  • 在Python中,对象可以分为可变对象和不可变对象两种类型。

    不可变对象:在创建后无法被修改的对象,例如数字、字符串、元组等。

    可变对象:在创建后可以被修改的对象,例如列表、字典、集合等。

    可变对象和不可变对象的区别主要在于它们的赋值和传递方式不同。对于不可变对象,赋值或传递时会创建一个副本,而对副本的修改不会影响原对象,例如:

    a = 1
    b = a # 创建a的副本赋值给b
    b = 2 # 修改b的值,不会影响a的值
    print(a) # 输出:1
    print(b) # 输出:2
    

    而对于可变对象,赋值或传递时只是创建了一个引用,即两个变量指向同一个对象,因此对其中一个变量的修改会影响另一个变量,例如:

    a = [1, 2, 3]
    b = a # 创建a的引用赋值给b
    b[0] = 0 # 修改b中的元素,会影响a中的元素
    print(a) # 输出:[0, 2, 3]
    print(b) # 输出:[0, 2, 3]
    
  • Python官方文档中有一些关于可变对象和不可变对象的说明,可以参考以下链接:

    • Python官方文档:数据模型
    • Python官方文档:不可变序列
    • Python官方文档:可变序列

可视化工具🎈

  • Python Tutor: Learn Python, JavaScript, C, C++, and Java programming by visualizing code
    • Online Python compiler and debugger - Python Tutor - Learn Python by visualizing code
    • Python Preview - Visual Studio Marketplace
  • Debug Visualizer - Visual Studio Marketplace

可变对象和id

  • id()|Built-in Functions — Python documentation

  • 在Python中,id()函数用于获取对象的唯一标识符。每个对象都有一个唯一的标识符,可以用于比较对象是否相等。这个标识符是一个整数,可以被认为是对象的内存地址。

    以下是一些示例代码,演示如何使用id()函数:

    # 获取整数对象的标识符
    x = 10
    print(id(x))  # 输出一个整数
    
    # 获取字符串对象的标识符
    s = "hello"
    print(id(s))  # 输出一个整数
    
    # 获取列表对象的标识符
    lst = [1, 2, 3]
    print(id(lst))  # 输出一个整数
    
    # 获取自定义对象的标识符
    class MyClass:
        pass
    
    obj = MyClass()
    print(id(obj))  # 输出一个整数
    

    在上面的代码中,我们分别定义了一个整数、一个字符串、一个列表和一个自定义类对象,并使用id()函数获取它们的标识符。需要注意的是,即使两个对象的值相同,它们的标识符也可能不同,因为它们可能位于不同的内存位置。

    id()函数通常用于比较对象是否相等。如果两个对象的标识符相同,则它们是同一个对象。如果两个对象的标识符不同,则它们是不同的对象。例如:

    a = [1, 2, 3]
    b = [1, 2, 3]
    c = a
    
    print(id(a))  # 输出一个整数
    print(id(b))  # 输出一个不同的整数
    print(id(c))  # 输出与a相同的整数
    
    print(a == b)  # 输出True,因为a和b的值相等
    print(a is b)  # 输出False,因为a和b是不同的对象
    print(a is c)  # 输出True,因为a和c是同一个对象
    

    在上面的代码中,我们定义了三个列表对象abc,其中ab的值相同,但它们是不同的对象。ca相同,是同一个对象。我们使用id()函数获取它们的标识符,并使用is运算符比较它们是否相同。需要注意的是,==运算符比较的是值是否相等,而is运算符比较的是对象是否相同。

eg

  • 下面提到的例子中的python指针仅仅标识地址(类比于c语言中的指针)

    ##
    a,b=[1,2],34
    
    ## 利用成组赋值初始化c,d两个新变量(指针)
    #c和a指向相同内存区域,d和b指向相同区域
    c,d=[a,b]
    
    ##尝试通过指针c来修改c,和a共同指向的区域,值从[1,2]变为[1,2,3,4]
    c+=[11,22]
    
    ##尝试将指针d指向另一个内存区域(保存着100)(不同于b所指向的内存区域(保存着34))
    d=100
    
    ##
    a,b,c,d
    #([1, 2, 11, 22], 34, [1, 2, 11, 22], 100)
    #可以发现,a,c由于始终指向同一片内存,所以通过其中的一个指针(c或a)来修改同一片内存,通过a,c访问到的内容是始终保持一样
    #因为list是可变对象,对这类对象执行+=操作不会改变指针所指的内存区域(首地址)
    #(如果是str这类不可变对象,使用+=会导致指针指向其他内存区域!)
    ##
    #这几个变量指向的地址一致性分析:a,c指向相同的区域,b,d指向不同的区域
    [id(x) for x in[a,b,c,d]]
    #[2363406317120, 2363321642320, 2363406317120, 2363321832912]
    
    
    • s="abc"
      id(s)#2363326296880
      s+="d"	
      id(s)#2363407021040
      
      • 可以看到s指向的内存首地址(id)发生了改变
  • 如果您对以下内容有所了解,那么理解起来回简单一些:

    • 操作系统上的硬链接(hardlink)
    • c语言中的指针
  • 以硬链接为例,假设

    • 您在A目录有一个文件X(理解为名字或者指针),它在硬盘上的地址记为idx
    • B目录下建立了一个指向磁盘的idx的名为X'的指针
    • 但是通过XX'均可以找到磁盘上的位置idx,也就是说,通过X或X’都可以打开/修改idx开始的一片区域
    • 也就是说,X,X'访问到的内容始终是一样的
    • 但是,您无法通过修改X'指向到idy的新区域,同时将X也指向idy
    • X,X'各自不知道对方的存在
    • 在python编程中(尤其是面向对象中),要注意这些东西
  • 再形象点说,假设公司派了2个人(设为a,b)去一个同一个地方P1办事,a先受到具体通知(a=P1),a将地点告诉b(类似于执行语句b=a)

  • 假设b再执行任务的过程中被公司紧急改派到另一个地方P2执行任务(b=P2)

  • 此时a并没有因为b绑定的任务发生变化而跟着变化

  • 假设公司由派遣了第3个人c去协助a到P1地方(对象)去工作

  • 如果P1是一个可变对象(比如列表),比如修改P1的某个成员P[i],a,c两个人都可以看到相同的变化

  • P1=[1,2,3]
    a
    c
    • a[1]=100,c[1]=100,P1[1]=100效果是一样的,也就是说,修改对象内部的东西,对于所有引用了这个对象的变量是可见的,但是如果形如c=P2这样的语句直接使得c不再指向P1,而是指向P2,那么对c的后续的任何使用和修改都对立与a,P1

eg

  • a,b=[1,2],34
    t=[a,b]
    t[1] is b#true
    t[1]=8 
    id(t[1]),id(b)#(2363321641488, 2363321642320)
    
    • t[1]b最开始指向同一片区域,但是后来t[1]被修改指向其他区域,不再和b有相同的取值
    • b的取值也无法直接通过t[1]来修改(只能是直接将b)作为左值,才能使其指向其他地方
    • 反之也一样,修改b无法直接影响到t[1](除非,b指向一个可变对象(比如list,同时做的是原地修改))

变量名和内存地址🎈

  • 在 Python 中,变量名是用于引用对象的标识符,而对象则是存储在内存中的数据结构。

  • 每个对象都有一个唯一的标识符,即对象的内存地址。

  • 变量名引用了对象的内存地址,而不是对象本身

  • 当我们创建一个变量并为其赋值时,Python 解释器会在内存中创建一个对象,并将变量名与对象的内存地址进行绑定。

    • 注意访问变量/创建变量/给变量赋值的差异
  • 当我们引用变量时,Python 解释器会查找变量名对应的内存地址,然后返回存储在该地址中的对象。

  • python中的变量名和c语言中的指针有所不同

  • print(f"{id(10)=}")
    a=10
    print(f"{id(a)=}")
    
    def f(x):
        print(f"{id(x)=}")
        x=20
        print(f"{id(20)=}")
        print(f"{id(x)=}")
    
    f(a)
    a
    print('a: ', a)#10
    
    • id(10)=3207627500112
      id(a)=3207627500112
      id(x)=3207627500112
      id(20)=3207627500432
      id(x)=3207627500432
      a:  10
      
  • 上面的语句b=a将a所引用的内存地址告诉了b,从而b指向的和a所指的空间一致

    • 尽管如此,b,a还是相对独立的
    1
    a
    b
  • 修改a,使其指向别处

    1
    100
    b
    a

函数调用对参数的修改😂

  • a=10
    def f(x):
        x=20
    f(a)
    a
    print('a: ', a)#10
    
  • 初学者可能会认为最后打印的会是20,但实际上会是10

  • 在这段代码中,首先将值10赋给变量a

  • 然后定义了一个名为f的函数,它有一个参数x,在函数内部,将值20赋给参数x

  • 当你以a做为实参,执行f(a),python会分别一个变量x,并且x绑定到一个同为20的值

  • 因此,当你调用函数后打印a的值,你会得到10,也就是a的原始值。

  • print(f"{id(10)=}")
    a=10
    print(f"{id(a)=}")
    
    def f(x):
        print(f"{id(x)=}")
        x=20
        print(f"{id(20)=}")
        print(f"{id(x)=}")
    
    f(a)
    a
    print('a: ', a)#10
    

Note

  • 在 Python 中,函数参数是按值传递的,因此在函数内部修改参数的值不会影响函数外部的变量。

  • 但是,你可以使用可变对象作为参数来达到修改参数值的目的。

  • 例如,你可以将参数 x 设计成一个列表或字典,然后在函数内部修改列表或字典元素的值,这样就可以修改参数的值了。

    以下是一个示例代码:

    def f(x):
        x[0] = 20
    
    a = [10]
    f(a)
    print(a[0])  # 输出 20
    
  • 在这个示例中,我们将参数 x 设计成一个列表 a

  • 在函数 f 内部,我们将列表 a 的第一个元素修改为 20。这样,在函数外部打印 a[0] 的值时,会输出 20,因为参数 a 的值已经被修改了。

  • 上述例子中,可以理解为,f(a)执行了x=a,从而一个和a不同的变量x就被创建,他们此时指向相同的内存区域

  • 进入函数内部这个过程中,只有x进入,而a没有受到影响,x被修改不会影响a

  • 需要注意的是,这种方式修改参数值的做法并不是很常见,因为它可能会导致代码难以理解和维护。通常来说,我们更倾向于使用函数的返回值来传递函数处理后的结果。

按值传递vs引用传递

  • 按值传递和引用传递是两种不同的函数参数传递方式。
  • 按值传递(call by value)是将参数的复制一份,然后传递给函数。
    • 在函数内部,对参数进行修改不会影响函数外部的变量。这种方式是最常见的参数传递方式,也是 Python 中默认的参数传递方式
  • 引用传递(call by reference)是将参数的引用或地址传递给函数。
    • 在函数内部,对参数进行修改会影响函数外部的变量。这种方式通常是通过指针或引用来实现的,比如在 C 语言中,可以通过指针来实现引用传递。
  • 在 Python 中,函数参数默认是按值传递的
  • 但是当参数是可变对象时(比如列表或字典),即使(看起来和按值传递一样),但可以在函数内部被修改参数的值,因为可变对象是引用传递的。

note🎈

  • 注意区分:

    a=[1,2,3]
    def f(x):
    	x=100
    f(a)
    print(f"{a=}")#[1,2,3]
    
    b=[1,2,3]
    def g(x):
    	x[0]=100
    g(b)
    print(f"{b=}")#[100,2,3]
    
    
    
    • 这里a,b是两个独立的列表,只是他们的内容是一样的,都是1,2,3

    • 运行结果:

    • a=[1, 2, 3]
      b=[100, 2, 3]
      
    • a没有被修改;而b被修改了

    • 因为a是值,而b[0]是引用

    • 在这里插入图片描述在这里插入图片描述
      函数g(x)的参数x传入实参列表对象b
      在这里插入图片描述在这里插入图片描述
      函数f内部执行了x=100,x从list这个Object断开,而指向一个常量100
  • 当我们将一个列表或字典等可变对象作为函数参数传递时,实际上传递的是对象的引用或地址,而不是对象的值。这意味着,在函数内部对参数进行修改时,实际上修改的是对象本身,而不是对象的副本。因此,修改后的对象的值将在函数外部可见。

    当我们将一个整数、字符串等不可变对象作为函数参数传递时,实际上传递的是对象的值的副本。这意味着,在函数内部对参数进行修改时,实际上修改的是参数的副本,而不是原始对象。因此,在函数外部,原始对象的值不会受到影响。

  • 在第一个示例中,函数 f 接收参数 x 并将其赋值为 100,但是在函数外部调用 f 并不会改变变量 a 的值,因为在函数内部的赋值语句 x=100 只是将参数 x 的引用指向了一个新的对象(100),并不会影响变量 a 的引用。因此,变量 a 的值仍然是 [1, 2, 3]

    • 这里x,a都是指向同一个内存区域的指针
    • 我们修改x指向其他地方,不会影响到a,a依然指向原来的内存
  • 但是,如果a,x所指的是可变对象,那么a[i],x[i]始终是一样的(指向相同内存)

  • 在第二个示例中,函数 g 接收参数 x 并将其第一个元素赋值为 100,由于列表是可变对象,所以在函数内部修改参数 x 的第一个元素也会影响到变量 b。因此,变量 b 的值被修改为 [100, 2, 3]

    需要注意的是,Python 中的列表、字典等可变对象是引用传递的,而整数、字符串等不可变对象则是按值传递的。在函数内部对可变对象进行修改时,可能会影响到函数外部的变量,而对不可变对象进行修改时则不会。

如何借助函数修改外部变量的值?

  • 根据上述的讨论,如果您确实需要根据某个函数修改某个变量,在python中,使用返回值是一个不错的选择

    • 例如:python中最常用的是

    • x=[]
      def square(n):
      	res=[x**2 for x in range(n)]
          return res
      x=square(10)
      
    • 而不是:

      • x=[]
        def square(n,x):
        	x=[x**2 for x in range(n)]
        square(10,x)
            
        
  • 另一方面,有一个关键字叫global,使用它可以修改外部变量

    • x=[]
      def square(n):
          global x
          x=[x**2 for x in range(n)]
      square(10)
      
      

Note

  • a=[11,22,33]
    b=[11,22,33]
    print(id(a),"@{id(a)}")
    print(id(b),"@{id(b)}")
    ida=id(a[0])
    idb=id(b[0])
    ida,idb
    
    • 3207784112768 @{id(a)}
      3207784126592 @{id(b)}
      (3207627500144, 3207627500144)
      
  • id(a[0])==id(b[0])#True
    a[0] is b[0]#True
    
  • 这个例子表示a,b是不同的两个列表对象,他们有共同点,就是内容是一样的

  • 既然内容一样为什么还要强调a,b是不同对象?

  • 因为对a的修改不会引起b的变化,反之也一样

    • 就好像两个不同的平台a,b请了同一个专家x做同样的工作
    • 后来其中的平台a请了专家y代替专家x,这不会影响平台b保持聘用专家x
  • 最后注意,这里是显式的各自为a赋值[11,22,33],而不是通过b=a这种方式赋值,后者方式使得b对列表的修改对a是可见的

  • a=[11,22,33]
    b=[11,22,33]
    a[0]=100
    a=[11,22,33]
    b=a
    a[0]=100
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库的概念?怎么在linux内安装数据库?怎么使用?

目录 一、概念 二、mysql安装及设置 1.安装mysql 2.数据库服务启动停止 三、数据库基本操作 1、数据库的登录及退出 2、数据表的操作 3、mysql查询操作 一、概念 数据库:是存放数据的仓库,它是一个按数据结构来存储和管理数据的计算机软件系统。数据库管理…

SQLServer的内存管理架构

内存管理架构说明 一、Windows的虚拟内存管理器二、SQL Server 内存体系结构2.1、传统(虚拟)内存2.2、地址窗口扩展 (AWE) 内存 三、从 SQL Server 2012 (11.x) 开始发生的改变3.1、对内存管理的更改3.2、对…

安装多个NodeJS windows上安装多个Nodejs版本 解决vue2/vue3同时运行

第一步下载nvm-windowsnvm-windows 下载地址:Github最新下载地址 进入之后直接下载 第二步 安装NVM 注意路径一定不要包含空格 中文否则会报错 点击安装之后 如果之前安装了nodejs的话会提示 希望nvm管理已安装node 版本吗 点击 是 即可 安装完成后 打开 cmd 输入 n…

Bito:一款 iead/webstorm 神级插件,由 ChatGPT 团队开发,堪称辅助神器

前言: idea(后端),webstorm(前端)中可以用的一款辅助插件:Bito 个人尝试体验效果: 优点是:可以自动完成一些场景代码。 缺点:太慢了,大部分时间一直转圈 摘取文档: 什么是Bito&…

TDA4VM/VH 芯片硬件 mailbox

请从官网下载 TD4VM 技术参考手册,地址如下: TDA4VM 技术参考手册地址 概述 (Mailbox 的介绍在 TRM 的第7.1章节) Mailbox 使用邮箱中断机制实现了 VM 芯片的核间通信。 Mailbox 是集成在 NAVSS0 域下的一个外设(NAVSS0 的说明可以查看&a…

flink on k8s提交任务

目录 相关文档前置准备构建镜像提交任务 相关文档 https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/resource-providers/native_kubernetes/ 前置准备 flink的lib目录下放入两个依赖 bcpkix-jdk15on-1.68.jar bcprov-jdk15on-1.69.jar 创建用户…

CRM客户关系管理系统主要有哪些功能?

一、CRM客户管理系统是什么 客户关系管理(Customer Relationship Management,简称CRM),是指企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与顾客间在销售、营销和服务上的交互,从而提升…

关于HTML5画布canvas的功能

一、画布的使用 1、首先创建一个画布&#xff08;canvas&#xff09; <canvas id”myCanvas” width”200” height”100” style”border:1px solid #000000”></canvas> 2、使用JavaScript来绘制图像 <script> Var cdocument.getElementByID(“myCanv…

AlgoC++第八课:手写BP

目录 手写BP前言1. 数据加载2. 前向传播3. 反向传播总结 手写BP 前言 手写AI推出的全新面向AI算法的C课程 Algo C&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考。 本次课程主要是手写 BP 代码 课程大纲可看下面的思维导图 1. 数据加载 我们首先来实现下MNIST…

【别再困扰于LeetCode接雨水问题了 | 从暴力法=>动态规划=>单调栈】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

用 ChatGPT 进行阅读理解题目的问答

阅读理解出题 阅读理解题是语言学习过程中一种重要的练习方式。无论语文还是英语考试中&#xff0c;阅读理解题都占有相当大的分值。ChatGPT 作为一种大语言模型&#xff0c;在处理自然语言理解任务中具有很大的优势。广大教师和学生家长们&#xff0c;都可以尝试用 ChatGPT 进…

springboot使用mybatis

扫描mapper接口的位置&#xff0c;生成代理对象 在application.properties配置数据源 测试: 在application.properties配置mybaits&#xff0c;支持驼峰命名&#xff0c;下划线 结果映射: Insert语句例子 在application.properties配置日志 更新 总结: 结果复用 ResultMap第二种…

Oracle-12c版本之后替换OCR磁盘组步骤

背景: 用户有一套Oracle12.2的RAC集群&#xff0c;在安装配置的时候&#xff0c;OCR磁盘只使用了单块磁盘external的模式&#xff0c;想替换成包含三块磁盘组成员normal模式的磁盘组 OCR磁盘组存储的对象: 在替换OCR磁盘之前&#xff0c;我们先确认需要迁移的OCR磁盘组存储的对…

五分钟学会在微信小程序中使用 vantUI 组件库

前言 我们在开发微信小程序时&#xff0c;设计和实现好用的用户界面无疑是至关重要的一步。但是微信小程序官方自带的 UI 组件库无法满足很多使用场景&#xff0c;这个时候就需要我们使用一些第三方的 UI 组件库。而 vant Weapp 作为一款优秀的前端 UI 组件库&#xff0c;可以帮…

【软件测试】项目测试—MySQL数据库操作应用场景?必会知识详全(超详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 数据库在软件测试…

微软的“牛头怪时刻”

2014年&#xff0c;当萨提亚纳德拉接任微软CEO时&#xff0c;他面对的是一家停滞且难以在快速发展的技术领域保持竞争优势的公司。自那以后&#xff0c;纳德拉将其重点从传统操作系统和生产力软件&#xff0c;转向云计算和人工智能&#xff0c;被认为重振了微软。​ 让我们以O…

AI思维导图来了,让活动策划更加简单!

每当有活动的时候&#xff0c;都会让策划的小伙伴绞尽脑汁&#xff01; ProcessOn一直致力于提升大家的办公效率。新增的AI功能&#xff0c;可以帮助我们一键生成思维导图、流程图。让一切变得更加简单。 没有灵感&#xff1f;没有关系。不知道怎么做&#xff0c;没有关系&a…

【两个月算法速成】day03-链表

目录 203. 移除链表元素 题目链接 思路 代码 206. 反转链表 题目链接 思路 代码 总结 203. 移除链表元素 题目链接 力扣 思路 如下图所示就是移除链表的过程 但是值得注意的是&#xff0c;移除头节点和其他位置的节点是不一样的&#xff0c;以为头结点前面没有节点。…

hvv培训的流量分析题

题目如下 1 找扫描器的特征 常见的扫描器 使用过滤语句http contains "acunetix" 2 要找到黑客的登录后台 我们可以考虑搜搜看常见的后台路径admin ip.src 192.168.94.59 && http contains "admin" 追踪下tcp流,302说明大概就是对的 3 h…

Linux运维:推荐八款Linux远程连接工具

目录 2、XShell 3、SecureCRT 4、PuTTY 5、WindTerm 6、iTerm2 7、MobaXterm 8、Termius 今天给大家推荐八款Linux远程连接工具&#xff0c;非常实用&#xff0c;希望对大家能有所帮助&#xff01; 1、NxShell NxShell是一款开源的Linux远程管理工具&#xff0c;是我日…