Dantangfan

python中参数传递方式

python 参数传递方式也是老生常谈的问题,这里做个简单总结

基本概念

语言的特性决定了参数的传递方式,先回顾一下,什么是传值,什么是传引用:

一切都是对象

前面的文章里,我们多次提到:python中一切皆对象。

所以这里,变量也是对象。我们常说,python是动态语言,随之,python是动态类型的强类型语言。

动态语言的特点是它可以在运行时更改自己的结构,例如添加、删除或替换函数,以及对象/类的属性和方法等。

class C:
    pass
c = C()
c.val = 1

强类型指的是一个变量被赋值为一个对象后,这个对象的类型就固定了,不能隐式转换成另一个类型。

a = 1 #这里的1是int类型,不能转变为其他类型

动态类型是指一个变量可以替换成不同类型的对象。

a = 1
a = "I change my type"  # 这里,只是a指向的对象变了,而上面的1的地址依然是1

所以,我们姑且这样说: 变量是没有类型的,值(对象)才有类型。这很重要,这是理解下面类容的基本知识

intval = 1      # 一个指向int类型的变量intval
listval = [1]   # 一个指向list类型的变量listval

可变(mutable)和不可变(immutable)

熟悉python的同学都知道,python分为可变和不可变对象。 我们要知道的是所谓可变对象是指,对象的内容可变,而不可变对象是指对象内容不可变 python中对他们的简单分类如下:

>>> intval = 1
>>> id(intval)
140229478498760
>>> intval = 2
>>> id(intval)
140229478498736

从上面可以看出,对于不可变对象,改变变量值,只是变量指向的地址发生了变化,而原来地址中的对象并没有发生变化。

>>> listval=[1, 2, 3]
>>> id(listval)
4373130920
>>> id(listval[0])
140229478498760
>>> listval[0] = 11
>>> id(listval)
4373130920
>>> id(listval[0])
140229478498520
>>>

从上面可以看出,当改变listval中元素值的时候,listval本身的地址并没有发生变化,也就是说,listval是可变的。有趣的是,这里listval[0]的地址却发生了变化,这恰好符合了python是强类型语言的定义,对象本身不变,而是变量指向的地址改变了。

python参数传递

先说结论:对于不可变对象作为参数,看起来就好像c++中的传值;对于可变对象作参数,看起来就好像是C++中的传引用。下面举例说明

def argument_int(a):
    print id(a)
    a = 10
    print id(a)
    
intval = 2
print id(intval)
argument_int(intval)
print intval  #最后的值依然是2

这里发生了什么?首先我们初始化了一个intval变量的值为2,然后传递给函数,这个时候,函数参数a的地址和intval的地址还是一样的。然后,我们改变了a指向的对象,然而,此时的intval指向的对象依然没有发生变化。整个过程看起来就跟C++中的传值调用一样。

def argument_list(a):
    a[0] = 1000
listval = [1]
argument_list(listval)
print listval # 输出[1000]

就跟我们上一节说的一样,此时函数的参数a和listval指向的地址是一样的。函数内部改变a元素指向的对象,相应的listval值也会发生变化,看起来就好像是传引用调用一样。

对于其他对象,只要我们能定义成可变对象(如dict,class等),它的调用过程就是传引用的,反之亦然。




blog comments powered by Disqus