Python参数传递机制传值和传引用原理详解

首先还是应该科普下函数参数传递机制,传值和传引用是什么意思?

   函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用传递。

  值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

  引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

在python中实际又是怎么样的呢?

先看一个简单的例子

from ctypes import *
import os.path
import sys

def test(c):
  print "test before "
  print id(c)
  c+=2
  print "test after +"
  print id(c)
  return c

def printIt(t):
  for i in range(len(t)):
    print t[i]

if __name__=="__main__":
  a=2
  print "main before invoke test"
  print id(a)
  n=test(a)
  print "main afterf invoke test"
  print a
  print id(a)

运行后结果如下:

>>>
main before invoke test
test before
test after +
main afterf invoke test
39601564

id函数可以获得对象的内存地址.很明显从上面例子可以看出,将a变量作为参数传递给了test函数,传递了a的一个引用,把a的地址传递过去了,所以在函数内获取的变量C的地址跟变量a的地址是一样的,但是在函数内,对C进行赋值运算,C的值从2变成了4,实际上2和4所占的内存空间都还是存在的,赋值运算后,C指向4所在的内存。而a仍然指向2所在的内存,所以后面打印a,其值还是2.

如果还不能理解,先看下面例子

>>> a=1
>>> b=1
>>> id(a)
>>> id(b)
>>> a=2
>>> id(a)

  a和b都是int类型的值,值都是1,而且内存地址都是一样的,这已经表明了在python中,可以有多个引用指向同一个内存(画了一个很挫的图,见谅),在给a赋值为2后,再次查看a的内存地址,都已经变化了

而基于最前面的例子,大概可以这样描述:

那python函数传参就是传引用?然后传参的值在被调函数内被修改也不影响主调函数的实参变量的值?再来看个例子。

from ctypes import *
import os.path
import sys

def test(list2):
  print "test before "
  print id(list2)
  list2[1]=30
  print "test after +"
  print id(list2)
  return list2

def printIt(t):
  for i in range(len(t)):
    print t[i]

if __name__=="__main__":
  list1=["loleina",25,'female']
  print "main before invoke test"
  print id(list1)
  list3=test(list1)
  print "main afterf invoke test"
  print list1
  print id(list1)

实际值为:

>>>
main before invoke test
test before
test after +
main afterf invoke test
['loleina', 30, 'female']

发现一样的传值,而第二个变量居然变化,为啥呢?

实际上是因为python中的序列:列表是一个可变的对象,就基于list1=[1,2] list1[0]=[0]这样前后的查看list1的内存地址,是一样的。

>>> list1=[1,2]
>>> id(list1)
>>> list1[0]=[0]
>>> list1
[[0], 2]
>>> id(list1)

字典也是可变对象:

>>> def fun2(num1,l1,d1):
...   num1=123
...   l1[0]=123
...   d1['a']=123
...   print("inside:","num1=%f,l1=%s,d1=%s"%(num1,l1,d1))
...
>>> num=111
>>> l=[1,1,1]
>>> d={'a':111,'b':0}
>>> print("before:","num=%f,l=%s,d=%s"%(num,l,d))
before: num=111.000000,l=[1, 1, 1],d={'a': 111, 'b': 0}
>>> fun2(num,l,d)
inside: num1=123.000000,l1=[123, 1, 1],d1={'a': 123, 'b': 0}
>>> print("after:","num=%f,l=%s,d=%s"%(num,l,d))
after: num=111.000000,l=[123, 1, 1],d={'a': 123, 'b': 0}

结论:python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。

如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。

如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • python进行参数传递的方法

    在分析python的参数传递是如何进行的之前,我们需要先来了解一下,python变量和赋值的基本原理,这样有助于我们更好的理解参数传递. python变量以及赋值 数值 从几行代码开始 In [1]: a = 1 In [2]: b = a In [3]: a = a + 1 我们先将1赋值给a,也就是a指向了1这个对象,在python中一切皆对象.接着b=a,则表示让b也指向了1这个对象,python中一个对象是可以被多个引用所指向.最后执行的a=a+1,这里需要注意一点,python的数据类

  • 深入理解python中函数传递参数是值传递还是引用传递

    目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用"的方式.实际上,这种方式相当于传值和传引用的一种综合.如果函数收到的是一个可变对象(比如字典 或者列表)的引用,就能修改对象的原始值--相当于通过"传引用"来传递对象.如果函数收到的是一个不可变对象(比如数字.字符或者元组)的引用,就不能 直接修改原始对象--相当于通过"传值"来传递对象. 你可以在很多讨论该问题

  • python 引用传递和值传递详解(实参,形参)

    python中函数参数是引用传递(不是值传递).对于不可变类型,因变量不能被修改,所以运算时不会影响到变量本身:而对于可变类型来说,函数体中的运算有可能会更改传入的参数变量. 形参: 函数需要传递的参数 实参:调用函数时传递的参数 补充知识:python函数方法实参给形参传值时候的隐形'陷阱' 众所周知,在python函数里面参数分为形参,实参两种.形参当然了就是形式参数,而实参是我们需要给这个函数传入的变量,在我们给实参传入变量之后,调用函数,实参则自动会把数值或则变量赋予形参,从而通过函数得

  • Python的形参和实参使用方式

    形参可以设置参数默认值,设置遵循从右至左原则 例如:fun(x=0,y=1),fun(x,y=1),但不可以是fun(x=1,y) 形参设置可以为数字字符串变量.元组和字典等任意类型数据,元组形参是在变量名前加*,字典形参是在变量名前加** 例如:fun(var),fun(*tuple),fun(*list),fun(**dict) 实参接受也可以是任意类型数据,当接收数据为元组列表或者字典时,同样是在数据变量前加*和** 例如:fun(x),fun(*seq),fun(*list),fun(*

  • Python参数传递机制传值和传引用原理详解

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传递. 值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本.值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值. 引用传递(pass-

  • Go语言参数传递是传值还是传引用

    目录 什么是传值(值传递) 什么是传引用(引用传递) 迷惑Map chan类型 和map.chan都不一样的slice 小结 对于了解一门语言来说,会关心我们在函数调用的时候,参数到底是传的值,还是引用? 其实对于传值和传引用,是一个比较古老的话题,做研发的都有这个概念,但是可能不是非常清楚.对于我们做Go语言开发的来说,也想知道到底是什么传递. 那么我们先来看看什么是值传递,什么是引用传递. 什么是传值(值传递) 传值的意思是:函数传递的总是原来这个东西的一个副本,一副拷贝.比如我们传递一个i

  • go reflect要不要传指针原理详解

    目录 正文 什么时候传递指针? 1. 通过传递指针修改变量的值 传值无法修改变量本身 传指针可以修改变量 2. 通过传递指针修改结构体的字段 3. 结构体:获取指针接收值方法 4. 变量本身包含指向数据的指针 通过值反射对象修改 chan.map 和 slice slice 反射对象扩容的影响 slice 容量够的话是不是就可以正常追加元素了? map 也不能通过值反射对象来修改其元素. chan 没有追加 结构体字段包含指针的情况 5. interface 类型处理 interface 底层类

  • python函数声明和调用定义及原理详解

    这篇文章主要介绍了python函数声明和调用定义及原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 函数是指代码片段,可以重复调用,比如我们前面文章接触到的type()/len()等等都是函数,这些函数是python的内置函数,python底层封装后用于实现某些功能. 一.函数的定义 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回:

  • Python深度强化学习之DQN算法原理详解

    目录 1 DQN算法简介 2 DQN算法原理 2.1 经验回放 2.2 目标网络 3 DQN算法伪代码 DQN算法是DeepMind团队提出的一种深度强化学习算法,在许多电动游戏中达到人类玩家甚至超越人类玩家的水准,本文就带领大家了解一下这个算法,论文的链接见下方. 论文:Human-level control through deep reinforcement learning | Nature 代码:后续会将代码上传到Github上... 1 DQN算法简介 Q-learning算法采用一

  • 对python csv模块配置分隔符和引用符详解

    如下所示: file = open('./abc.csv') csv.reader(file, delimiter=',', quotechar='"') 说明:delimiter是分隔符,quotechar是引用符,当一段话中出现分隔符的时候,用引用符将这句话括起来,就能排除歧义. 以上这篇对python csv模块配置分隔符和引用符详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • Python秒算24点实现及原理详解

    什么是24点 我们先来约定下老王和他媳妇玩的24点规则:给定4个任意数字(0-9),然后通过+,-,*,/,将这4个数字计算出24. 小时候玩的都是这个规则,长大了才有根号,才有各种莫名其妙的高级算法,不好玩了,因为我不会. 可能有人会觉得很简单,但是真的简单吗? 比如: 8,3,3,3 7,3,3,3 你能一眼看出来答案吗?好像真的可以-- 大致思路 这样想,将四个数字进行全排列,在他们之间添加运算符号. 运算符我们需要进行排列组合,因为只有四个数字,所以只需要三个运算符,而且算法符可能会重复

  • python列表删除和多重循环退出原理详解

    在学习python的时候,会有一些梗非常不适应,在此列举列表删除和多重循环退出的例子: 列表删除里面的坑 比如我们有一个列表里面有很多相同的值,假如:nums=[1,6,6,3,6,2,10,2,100],我想去掉6,可以这样写: nums=[1,6,6,3,6,2,10,2,100] for n in nums: if n==6: nums.remove(n) nums.sort() print(nums)#输出结果:[1, 2, 2, 3, 6, 10, 100] 排序显示后列表中还有一个6

  • Python selenium使用autoIT上传附件过程详解

    1.首先打开AutoIt Windows Info 工具,鼠标点击Finder Tool(按住左键不松手),鼠标将变成一个小风扇形状的图标,移动到目标控件上:如图 2.通过AutoIt Windows Info 获得以下信息. 窗口的title为"打开",标题的Class为"#32770". 文件名输入框的class 为"Edit",Instance为"1" ,ClassnameNN为"Edit1". 打开

  • python 函数传参之传值还是传引用的分析

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传递. 值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本.值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值. 引用传递(pass-

随机推荐