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. atom 插件

    来源 个人博客 http://taoquns.com/paper/59ba5627a157197cdcc0a012 输入类 autocomplete-plus emmet go-to-line ato ...

  2. 【转载】Synflood code

    ''' Syn flood program in python by Tequila/e credits to Silver Moon for base's of syn packets. r s s ...

  3. GridView的TemplateField

    BoundField只能显示一个单独的数据字段.如果我们想要在一个GridView列中显示两个或者更多的数据字段的值的时候该怎么办呢? 1. GridView的一列同时显示数据源中的两个字段 现需要显 ...

  4. MySQL的数据类型和建库策略详解

    无论是在小得可怜的免费数据库空间或是大型电子商务网站,合理的设计表结构.充分利用空间是十分必要的.这就要求我们对数据库系统的常用数据类型有充分的认识.下面我就将我的一点心得写出来跟大家分享. 一.数字 ...

  5. DP(悬线法)【P1169】 [ZJOI2007]棋盘制作

    顾z 你没有发现两个字里的blog都不一样嘛 qwq 题目描述-->p1169 棋盘制作 题目大意 给定一个01棋盘,求其中01交错的最大正方形与矩形. 解题思路: 动态规划---悬线法 以下内 ...

  6. ZOJ 2112 Dynamic Rankings (动态第 K 大)(树状数组套主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  7. [USACO Special 2007 Chinese Competition]The Bovine Accordion and Banjo Orchestra

    [原题描述以及提交地址]:http://acm.tongji.edu.cn/problem?pid=10011 [题目大意] 给定两个长度为N的序列,要给这两个序列的数连线.连线只能在两个序列之间进行 ...

  8. [BZOJ 1228] E&D

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1228 Solution: 感觉自己对博弈论的理论一直了解得不够透彻 一篇讲原理的文章:S ...

  9. 【kruscal】【最小生成树】【块状树】bzoj3732 Network

    跟去年NOIP某题基本一样. 最小生成树之后,就变成了询问连接两点的路径上的权值最大的边. 倍增LCA.链剖什么的随便搞. 块状树其实也是很简单的,只不过每个点的点权要记录成“连接其与其父节点的边的权 ...

  10. FCL研究-集合- System.Collections 接口和对象集合

    [目录] 发现自己已经有很长一段时间写代码没什么进步了,随便读读FCL的源码,看看之前一直用的方法是如何实现的,也顺便提高下自己.FCL很是庞大,很难下口,于是用最笨的办法,先看常见的命名空间,逐个展 ...