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语言中有一个经典的例子如下所示:

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

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. 怎么将string list 转成有特殊字符分开字符串

    https://stackoverflow.com/questions/4021851/join-string-list-elements-with-a-delimiter-in-one-step Y ...

  2. [BZOJ2730][HNOI2012]矿场搭建 点双 割点

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2852  Solved: 1344[Submit][Stat ...

  3. scrapy 工作流程

    Scrapy的整个数据处理流程由Scrapy引擎进行控制,其主要的运行方式为: 引擎打开一个域名,蜘蛛处理这个域名,然后获取第一个待爬取的URL. 引擎从蜘蛛那获取第一个需要爬取的URL,然后作为请求 ...

  4. shell脚本学习(二)

    shell传递参数 shell脚本在执行是可以传递参数,脚本内获取参数的格式为:$n,n为一个数字,1为第一个参数,2为第二个参数,以此类推 其中,$0代表了要执行的文件名 实例: 代码如下: #!/ ...

  5. Dart类

    Dart中没有访问控制符,无论类还是方法默认都是public 1.构造函数 构造函数可以没有方法体,并且this可以直接在传参时直接对实例赋值 Bicycle(this.cadence, this.s ...

  6. 基于JS的event-manage事件管理库(一步一步实现)

    关于文章 最近在提升个人技能的同时,决定把自己为数不多的沉淀记录下来,让自己理解的更加深刻,同时也欢迎各位看官指出不足之处. 随着node.js的盛行,引领着Javascript上天下地无所不能啊,本 ...

  7. amq笔记:记一个关于PooledConnectionFactory的问题

    替人排查一个关于amq连接数的问题,使用PooledConnectionFactory进行连接池管理,设置了连接数上限为3,但部署到服务器之后,瞬间建立了几百个连接,用netstat -an 查看,发 ...

  8. numeric column can contains null

  9. AxureRP7超强部件库打包下载

    摘要: 很多刚刚开始学习Axure的朋友都喜欢到网上搜罗各种部件库(组件库)widgets library ,但是网络中真正实用的并且适合你使用的少之又少,最好的办法就是自己制作适合自己工作内容的部件 ...

  10. 线程协作-CountDownLatch

    CountDownLatch允许一个或多个线程等待其他线程完成操作.