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 = 2 print id(x) print id(2) y = ‘Hello‘ print 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=2 print id(x) y=2 print id(y) s=‘hello‘ print id(s) t=s print 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=2 print id(2) print id(x) x=3 print id(3) print id(x) L=[1,2,3] M=L print id(L) print id(M) print id(L[2]) L[0]=2 print 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 return 10 11 n = 100 12 L = [1,2,3] 13 modify1(n,L) 14 print n 15 print L 16 modify2(n,L) 17 print n 18 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‘, x x = 50 func(x) print ‘x is still‘, x
输出:
原理:在函数中,我们第一次使用x
的 值 的时候,Python使用函数声明的形参的值。
接下来,我们把值2
赋给x
。x
是函数的局部变量。所以,当我们在函数内改变x
的值的时候,在主块中定义的x
不受影响。
在最后一个print
语句中,我们证明了主块中的x
的值确实没有受到影响。
全部变量 它是在函数外部定义的,作用域是整个文件,全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用 global 关键字进行声明。
def func(): global x print ‘x is‘, x x = 2 print ‘Changed local x to‘, x x = 50 func() print ‘Value of x is‘, x
输出:
原理:global
语句被用来声明x
是全局的——因此,当我们在函数内把值赋给x
的时候,这个变化也反映在我们在主块中使用x
的值的时候。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。