首页 > 代码库 > python基础10(函数二)

python基础10(函数二)

 

一、函数形参实参的区别

  形参全称是形式参数,在用def关键字定义函数时函数名后面括号里的变量称作为形式参数。

     实参全称为实际参数,在调用函数时提供的值或者变量称作为实际参数。

>>> def add(a,b):   #这里的a和b是形参      return a+b>>> add(1,2)       # 这里的1和2是实参3>>> x=2            # 这里的x和y是实参>>> y=3>>> add(x,y)5

 

 

二、参数的传递和改变

在Python中一切皆对象,变量中存放的是对象的引用。

例子:

print id(5)   # id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象print id(python)x = 2print id(x)print id(2)y = Helloprint id(y)print id(Hello)

 

 

 代码的运行结果:

 从运行结果中可以看到,id(x)和id(2)的值是一样的,id(y)和id(‘Hello‘)的值也是一样的。

在Python中一切皆对象,像2,‘hello‘这样的值都是对象,只不过5是一个整型对象,而‘hello‘是一个字符串对象。上面的x=2,在Python中实际的处理过程是这样的:先申请一段内存分配给一个整型对象来存储整型值2,然后让变量x去指向这个对象,实际上就是指向这段内存(这里有点和C语言中的指针类似)。而id(2)和id(x)的结果一样,说明id函数在作用于变量时,其返回的是变量指向的对象的地址。因为变量也是对象,所以在这里可以将x看成是对象2的一个引用。

 

再看一个例子:

x=2print id(x)y=2print id(y)s=helloprint id(s)t=sprint id(t)

 

代码运行结果:

从运行结果可以看到id(x)和id(y)的结果是相同的,id(s)和id(t)的结果也是相同的。这说明x和y指向的是同一对象,而t和s也是指向的同一对象。

x=2这句让变量x指向了int类型的对象2,而y=2这句执行时,并不重新为2分配空间,而是让y直接指向了已经存在的int类型的对象2。

这个很好理解,因为本身只是想给y赋一个值2,而在内存中已经存在了这样一个int类型对象2,所以就直接让y指向了已经存在的对象。

这样一来不仅能达到目的,还能节约内存空间。t=s这句变量互相赋值,也相当于是让t指向了已经存在的字符串类型的对象‘hello‘(这个原理和C语言中指针的互相赋值有点类似)。

 

下面再看个例子:

x=2print id(2)print id(x)x=3print id(3)print id(x)L=[1,2,3]M=Lprint id(L)print id(M)print id(L[2])L[0]=2print id(L)print M

 

代码运行结果:

两次的id(x)的值不同,这个可能让人有点难以理解。注意,在Python中,单一元素的对象是不允许更改的,比如整型数据、字符串、浮点数等。

x=3这句的执行过程并不是先获取x原来指向的对象的地址,再把内存中的值更改为3,而是新申请一段内存来存储对象3,再让x去指向对象3,所以两次id(x)的值不同。

然而为何改变了L中的某个子元素的值后,id(L)的值没有发生改变?在Python中,复杂元素的对象是允许更改的,比如列表、字典、元组等。

Python中变量存储的是对象的引用,对于列表,其id()值返回的是列表第一个子元素L[0]的存储地址。

就像上面的例子,L=[1,2,3],这里的L有三个子元素L[0],L[1],L[2],L[0]、L[1]、L[2]分别指向对象1、2、3,id(L)值和对象3的存储地址相同。

因为L和M指向的是同一对象,所以在更改了L中子元素的值后,M也相应改变了,但是id(L)值并没有改变,因为这句L[0]=2只是让L[0]重新指向了对象2,而L[0]本身的存储地址并没有发生改变,所以id(L)的值没有改变( id(L)的值实际等于L[0]本身的存储地址)。

 

结合例子看看函数的参数传递和改变这个问题

在python中参数传递采用的是值传递,这个和C语言有点类似。

 1 def modify1(m,k): 2     m = 2  3     k = [4,5,6] 4     return  5      6 def modify2(m,k): 7     m = 2  8     k[0] = 0 9     return10     11 n = 10012 L = [1,2,3]13 modify1(n,L)14 print n15 print L 16 modify2(n,L)17 print n18 print L

 

代码运行结果:

从结果可以看出,执行modify1( )之后,n和L都没有发生任何改变;执行modify2( )后,n还是没有改变,L发生了改变。因为在Python中参数传递采用的是值传递方式,在执行函数modify1时,先获取n和L的id( )值,然后为形参m和K分配空间,让m和K分别指向对象100和对象[1,2,3]。

m=2这句让m重新指向对象2,而K=[4,5,6]这句让K重新指向对象[4,5,6]。这种改变并不会影响到实参n和L,所以在执行modify1之后,n和L没有发生任何改变;在执行函数modify2时,

同理,让m和K分别指向对象2和对象[1,2,3],然而K[0]=0让K[0]重新指向了对象0(注意这里K和L指向的是同一段内存),所以对K指向的内存数据进行的任何改变也会影响到L,因此在执行modify2后,L发生了改变。

 

三、变量的作用域

局部变量 当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。

def func(x):    print x is, x    x = 2    print Changed local x to, xx = 50func(x)print x is still, x

 

输出:

原理:在函数中,我们第一次使用x 的时候,Python使用函数声明的形参的值。

        接下来,我们把值2赋给xx是函数的局部变量。所以,当我们在函数内改变x的值的时候,在主块中定义的x不受影响。

        在最后一个print语句中,我们证明了主块中的x的值确实没有受到影响。

 

全部变量 它是在函数外部定义的,作用域是整个文件,全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用 global 关键字进行声明。

def func():    global x    print x is, x    x = 2    print Changed local x to, xx = 50func()print Value of x is, x

 

 输出:

 原理:global语句被用来声明x是全局的——因此,当我们在函数内把值赋给x的时候,这个变化也反映在我们在主块中使用x的值的时候。

 

python基础10(函数二)