python中的形参和实参_Python中的函数:实参与形参

在上一篇文章中提到了Python中函数的定义和使用,在这篇文章里我们来讨论下关于函数的一些更深的话题。在学习C语言函数的时候,遇到的问题主要有形参实参的区别、参数的传递和改变、变量的作用域。同样在Python中,关于对函数的理解和使用也存在这些问题。下面来逐一讲解。

一.函数形参和实参的区别

相信有过编程语言经验的朋友对形参和实参这两个东西并不陌生。形参全称是形式参数,在用def关键字定义函数时函数名后面括号里的变量称作为形式参数。实参全称为实际参数,在调用函数时提供的值或者变量称作为实际参数。举个例子:

copycode.gif

#这里的a和b就是形参

defadd(a,b):return a+b#这里的1和2是实参

add(1,2)

x=2y=3

#这里的x和y是实参

add(x,y)

copycode.gif

二.参数的传递和改变

在大多数高级语言当中,对参数的传递方式这个问题的理解一直是个难点和重点,因为它理解起来并不是那么直观明了,但是不理解的话在编写程序的时候又极其容易出错。下面我们来探讨一下Python中的函数参数的传递问题。

首先在讨论这个问题之前,我们需要明确一点就是在Python中一切皆对象,变量中存放的是对象的引用。这个确实有点难以理解,“一切皆对象”?对,在Python中确实是这样,包括我们之前经常用到的字符串常量,整型常量都是对象。不信的话可以验证一下:

print id(5)print id('python')

x=2

printid(x)

y='hello'

print id(y)

这段代码的运行结果是:

14163157-ee21e29425e24a6bbd4fc9b67582a66b.jpg

先解释一下函数id( )的作用。下面这段话是官方文档对id()函数的解释:

15092647-c4d1733dfd5b4088897eeae04d2a9f7e.jpg

显而易见,id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象,因此对于这个语句

id(2)没有报错,就可以知道2在这里是一个对象。下面再看几个例子:

x=2

print id(2)printid(x)

y='hello'

print id('hello')print id(y)

其运行结果为:

15092818-a89842296d7a496893ce49237b06649f.jpg

从结果可以看出,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的一个引用。

下面再看几个例子:

copycode.gif

x=2

printid(x)

y=2

printid(y)

s='hello'

printid(s)

t=sprint id(t)

copycode.gif

其运行结果为:

15150356-ea919540bb6e45b687cfc16000766d67.jpg

从运行结果可以看到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语言中指针的互相赋值有点类似)。

看这幅图就理解了:

15155442-4f2d077a181e4c37bc8691c2739a911f.jpg

下面再看几个例子:

copycode.gif

x=2

print id(2)printid(x)

x=3

print id(3)printid(x)

L=[1,2,3]

M=Lprintid(L)printid(M)print id(L[2])

L[0]=2

printid(L)print M

copycode.gif

运行结果为:

15162514-5a2fc84a6047426fb906cc05e36a4310.jpg

下面来分析一下这个结果,两次的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的存储地址相同,看下面这个图就明白了:

15162702-c783bec88969421ebc16950714812a06.jpg

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

下面就来讨论一下函数的参数传递和改变这个问题。

在Python中参数传递采用的是值传递,这个和C语言有点类似。先看几个例子:

copycode.gif

defmodify1(m,K):

m=2K=[4,5,6]return

defmodify2(m,K):

m=2K[0]=0returnn=100L=[1,2,3]

modify1(n,L)printnprintL

modify2(n,L)printnprintL

copycode.gif

程序运行结果为:

15202445-c09327b6b87b41f4b726df1fc53853d8.jpg

从结果可以看出,执行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发生了改变。

三.变量的作用域

在Python中,也存在作用域这个问题。在Python中,会为每个层次生成一个符号表,里层能调用外层中的变量,而外层不能调用里层中的变量,并且当外层和里层有同名变量时,外层变量会被里层变量屏蔽掉。举个例子:

copycode.gif

deffunction():

x=2count=2

while count>0:

x=3

printx

count=count-1function()

copycode.gif

在函数function中,while循环外面和while循环里面都有变量x,此时,while循环外面的变量x会被屏蔽掉。注意在函数内部定义的变量作用域都仅限于函数内部,在函数外部是不能够调用的,一般称这种变量为局部变量。

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

copycode.gif

x=2

deffun1():printxdeffun2():globalx

x=3

printx

fun1()

fun2()print x

copycode.gif

关于函数的形参和实参、参数的传递以及变量的作用域问题这里就讨论这么多了,关于函数参数的类型问题会在《Python中的函数(三)》中继续讲解。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值