1.

Python passes everything the same way, but calling it "by value" or "by reference" will not clear everything up, since Python's semantics are different than the languages for which those terms usually apply. If I was to describe it, I would say that all passing was by value, and that the value was an object reference.

Python passes references-to-objects by value (like Java), and everything in Python is an object. This sounds simple, but then you will notice that some data types seem to exhibit pass-by-value characteristics, while others seem to act like pass-by-reference... what's the deal?

It is important to understand mutable and immutable objects. Some objects, like strings, tuples, and numbers, are immutable. Altering them inside a function/method will create a new instance and the original instance outside the function/method is not changed. Other objects, like lists and dictionaries are mutable, which means you can change the object in-place. Therefore, altering an object inside a function/method will also change the original object outside.

Actually, what Python passes includes both arguments and return statements.

2.

Python中函数的参数传递问题,函数参数的传递往往是一个难以理解的概念,记得在C语言中有一个经典的例子如下所示:

 int swap(int a,int b)
{
int temp;
temp = a;
a = b;
b = temp; return ;
} int a = ,b = ;
printf("Before Swap a = %d, b = %d\n",a,b);
swap(a,b);
printf("After Swap a= %d,b = %d\n",a,b);
我想这是大部分学过C语言的人都会遇到的一段代码,printf过后两个变量的值并没有发生改变,这是为什么呢?必然知道这是因为C语言的参数是采用值传递的形式,存在形参与实参的区别,也就是将实参的值复制给形参,在函数内部操作的都只是形参的内容,并不改变实参的值,所以变量在操作过后并没有发生改变。通常采用的方法是传递指针的形式,为什么传递指针又可以解决问题呢?这是因为传递的指针是指上就是一个地址值,也就是说形参和实参都指向了一段内存区域,在函数内部对内存区域的内容进行改变,这样就会影响到实参指向的内存区域,这样就实现了内存中数据的修改,进而实现数据的交换操作,这也是C语言中指针的经典操作之一。
 
但是到Python以后,我发现与C语言存在较大的差别,Python中万物皆对象,没有指针等特性使得我有些难以理解。Python万物皆对象的特征让我逐渐有了一定的理解。首先说明一下万物皆对象的问题。
>>> IntNum =
>>> Num1 = IntNum
>>> id(IntNum),id(Num1)
(, )
>>> Num2 =
>>> id(IntNum),id(Num1),id(Num2)
(, , )
>>> intNum =
>>> Num1 =
>>> Num2 =
>>> id(IntNum),id(Num1),id(Num2)
(, , )
这段代码主要是同id(object)判断了变量的ID号,这个ID号实质上也就表明了变量指向的对象(我这样认为的)。
IntNum = 10,是指IntNum这个变量实质上是指向了一个int类型的对象10,同时Num1 = IntNum则表示Num1这个变量也指向10这个对象。同样Num2 = 10也表明了指向10这个int对象,可以通过id()判断。具体的实现原理是采用了一种叫做引用计数的技术完成的,这是解释器的实现,与使用者关系并不大。因此可以将左值看做变量,就如同10是对象,而IntNum就是对象的引用,是一个变量。变量赋值给变量相当于同一对象引用计数器增加1,而并不重新分配对象。
 
同样IntNum = 20,则是指重新分配一个对象20,让IntNum指向这个对象,这时10这个对象的引用计数器要减1,因为IntNum不在引用10这个对象啦。
 
前面单一元素的对象还比较容易理解,但是下面这个的对象就不一定能够理解啦。
#list
>>> list1 = [,,,,]
>>> list2 = [,,,,]
>>> id(list1),id(list2)
(, )
>>> list1[]=
>>> list1
[, , , , ]
>>> id(list1),id(list2)
(, ) #dict
>>> dict1 = {'a':,'b':,'c':,'d':}
>>> dict2 = {'a':,'b':,'c':,'d':}
>>> id(dict1),id(dict2)
(, )
>>> dict1['d'] =
>>> dict1
{'a': , 'c': , 'b': , 'd': }
>>> dict2
{'a': , 'c': , 'b': , 'd': }
>>> id(dict1),id(dict2)
(, )
上面的代码中我主要分析了列表和字典这两种Python中包含对对象的数据类型,我还是通过简单的id()操作判断指向的对象是否发生改变。
从结果可以看见,对于列表而言,当改变了列表中某一个局部对象后,列表的地址并没有改变,这样对象的id也就不能改变了。说明列表局部内容是可以修改的,但是列表对象的ID号(存储地址)不会发生改变。同样对于字典类型的数据也可以知道,让dict1、dict2分别指向两个字典对象,这两个字典对象的id号存在差别,当修改其中一个的内容使两个字典的内容一样,这时候判断ID,仍然是不同的,说明字典的也是可以修改的。
比如dict1['d']=5是指,原来‘d’指向的对象是4,这时候重新分配一个对象5,让‘d’指向这个对象5。这时候并不改变字典变量dict1的值(已分配字典对象的地址)。
 
综合上述,Python中的变量是一个对象的引用,变量于变量之间的赋值是对同一个对象的引用,当变量重新赋值对象时,指将这个变量指向一个新分配的对象。这是和C语言中的变量存在差别。但是Python中的变量有点类似C语言中的指针,指向的是一个对象,或者一段内存空间,这段内存空间的内容是可以修改的(这也是为什么对列表或者字典的某一个子对象进行修改并不改变字典或者列表的ID号),但是内存的起始地址是不能改变的,指针变量之间的赋值相当于两个指针变量指向同一块内存区域,在Python中就相当于同一个对象。因此可以认为Python中的变量相当于C语言中的指针变量。
 
接下来分析函数中的参数传递问题:由于在Python中函数的参数传递是值传递,同时也存在局部和全局的问题,这和C语言中的函数也存在一定的相似性。
函数的定义形式如下:
def function(args):
function_block
参数传递过程中存在两个规则:
1、通过引用将参数复制到局部作用域的对象中,意味着被用来访问函数参数的变量于提高给函数的对象无关,因为存在一个复制问题,这和C语言是相同的。而且修改局部对象不会改变原始数据。
2、可以在适当位置修改可变对象。可变对象主要就是列表和字典,这个适当位置实质上就是前面分析的局部子对象的修改不会改变字典对象或者列表对象的ID,也就是存储位置(这是我暂且这么称呼吧)。
通过两个实例说明,第一个还是交换问题:
>>> def modifier(number,string,list):
number =
string = 'GoodBye'
list = [,,]
print "Inside:", number,string,list >>> num =
>>> string = 'Hello'
>>> list = [,,]
>>> print 'Before:', num, string, list
Before: Hello [, , ]
>>> modifier(num,string,list)
Inside: GoodBye [, , ]
>>> print 'After:', num, string, list
After: Hello [, , ]
从上面的结果可以看出来数据交换前后数据并没有发生改变,虽然在函数局部区域对传递进来的参数进行了相应的修改,但是仍然不能改变实参对象的内容。这和C语言中的操作非常相似,因为传递进来的三个指针在函数内部进行了相关的修改,相当于三个指针分别指向了不同的对象(存储区域),但是这三个指针都是局部指针并不改变实际的指针,所以交换前后实参指向的对象并没有发生改变。说明如果在函数内部对参数重新赋值新的对象,这并不会改变实参的对象。这就是函数的第一个规则。
对于不可变的对象,是不可能进行修改的,但是对于可变的对象(字典、列表),局部区域的值倒是可以改变的,这和前面分析的一样,看以参看下面的例子。
>>> def modifier(list,dict):
list[] =
dict['a'] =
print 'Inside list = %s, dict = %s' %(list,dict) >>> dict = {'a':,'b':,'c':}
>>> list = [,,,,]
>>> print 'Before list = %s, dict = %s' %(list,dict)
Before list = [, , , , ], dict = {'a': , 'c': , 'b': }
>>> modifier(list,dict)
Inside list = [, , , , ], dict = {'a': , 'c': , 'b': }
>>> print 'After list = %s, dict = %s' %(list,dict)
After list = [, , , , ], dict = {'a': , 'c': , 'b': }
从上面的结果可以看出来,在函数内部修改列表、字典的局部对象或者说没有对传递进来的列表、字典变量重新赋值对象,而是修改变量的局部内容,这时候就会导致外部实参指向对象内容的修改,这就相当于在C语言中对指针指向的内存区域进行修改,这样的修改必然会导致实参指向区域内容的改变。这是函数规则的第二条,适当的位置指的是对对象进行修改,而不是重现分配一个对象,重现分配一个对象不会影响实参,而对对象的修改必然影响实参。
 
在C语言中返回多对象时必然会引入指针的操作,因为对指针的修改实质上会反映到实参,这样就实现了数据的返回操作。而在Python中采用元组的形式返回多个值。但是知道了函数参数的传递特性,我们完全可以采用函数的参数实现一些基本的操作,就比如刚开始讨论的交换问题,如下所示:
>>> def swap(list):
temp = list[]
list[] = list[]
list[] = temp >>> list = [,]
>>> list
[, ]
>>> swap(list)
>>> list
[, ]

Python中函数参数传递问题【转】的更多相关文章

  1. python中函数参数传递的几种方法

    转自  http://www.douban.com/note/13413855/ Python中函数参数的传递是通过“赋值”来传递的.但这条规则只回答了函数参数传递的“战略问题”,并没有回答“战术问题 ...

  2. python 中函数参数传递形式

    python中函数参数的传递是通过赋值来传递的.函数参数的使用又有俩个方面值得注意:1.函数参数是如何定义的 2.在调用函数的过程中参数是如何被解析 先看第一个问题,在python中函数参数的定义主要 ...

  3. Python中函数参数传递问题

    先上两个例子: http://python.jobbole.com/85231/ a = 1 def fun(a): a = 2 fun(a) print a # 结果为1 fun(a)中的a,可以看 ...

  4. Python中函数的参数传递与可变长参数

    转自旭东的博客原文 Python中函数的参数传递与可变长参数 Python中传递参数有以下几种类型: (1)像C++一样的默认缺省函数 (2)根据参数名传参数 (3)可变长度参数 示例如下: (1)默 ...

  5. python中的参数传递和返回值

    python中的参数传递类似java,有着自己的内存回收机制,这和C++有着很大的差别. 1.函数的参数传递: >>> a = [, , ] >>> def fun ...

  6. python中函数参数的引用方式

    值传递和引用传递时C++中的概念,在python中函数参数的传递是变量指向的对象的物理内存地址!!! python不允许程序员选择采用传值还是传引用.Python参数传递采用的肯定是“传对象引用”的方 ...

  7. Python中的参数传递问题

    首先需要说明python中元组,列表,字典的区别. 列表: 什么是列表呢?我觉得列表就是我们日常生活中经常见到的清单. 例如:lst = ['arwen',123] 向list中添加项有两种方法:ap ...

  8. 【Python】解析Python中函数的基本使用

    1.简介 在Python中定义函数的基本格式为: def <函数名>(参数列表): <函数语句> return <返回值> Python中的函数形式比较灵活,声明一 ...

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

    深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用 ...

随机推荐

  1. 并查集【p2700】逐个击破

    题目描述-->p2700 逐个击破 题意概括 花费最小的代价,使得一些有标记的节点不连通. 分析 我们需要花费最小代价使得原来连通的图中一些节点之间不相互连通. 贪心显然是可行的(一点也不显然 ...

  2. Windows 环境下 Redis 安装

    1.redis官方下载地址:https://redis.io/download,redis 64位下载地址:https://github.com/MicrosoftArchive/redis/rele ...

  3. HDU 6315: Naive Operations

    Naive Operations Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Other ...

  4. Android的日志工具Log

    Android中的日志工具类是Log(android.util.Log),这个类提供了以下几个方法来供我们打印日志. ♦ Log.v():这个方法用于打印那些最为琐碎的,意义最小的日志信息.对应级别v ...

  5. [Luogu P4198]楼房重建(线段树)

    题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个 ...

  6. [Atcoder SHPC2018] Tutorial

    Link: SHPC2018 传送门 C: 一道看上去有些吓人的题目,不过$1e9$规模下的$n^m$代表肯定是可以约分的 可以发现能提供贡献的数对只有$2*(n-d)$种,那么总贡献为$2*(n-d ...

  7. 【线段树】bzoj3922 Karin的弹幕

    设置一个值K. d<=K:建立多组线段树:d>K:暴力. 最优时间复杂度的伪计算: O(n*K*logn(建树)+m*logn(询问类型1)+m*n/K(询问类型2)+m*K*logn(修 ...

  8. [CEOI2017]One-Way Streets

    题目大意: 给你一个无向图,现在告诉你一些点对(u,v), 要你在保证从u到v的所有路径都不变的情况下,尽可能把所有的边变成单向边, 问你可以唯一确定哪些边的方向,以及方向是从u到v还是从v到u. 思 ...

  9. 【Python笔记】Python语言基础

    Python是一种解释性(没有编译).交互式.面向对象的语言 1.安装python编译器 版本:Python2.7比较普遍,Python不是向下兼容的软件,因此Python3.x有些东西不好找资料 2 ...

  10. weblogic下同域不同端口下的跨域问题解决

      环境:同一台服务器,同一个Weblogic应用程序,分别建两个域,两个域IP一样,端口不同.一个域里放Web应用A,一个放Web应用B. 操作:用户访问A程序的时候,A程序会返回一个链接,让用户去 ...