python函数妃传参数 python函数怎么传参数
Python里面的函数怎么按引用传递参数
如果你用C给Matlab写过MEX程序,那么这个问题是很容易理解的(好像每次讨论Python问题时我总是把Matlab搬了出来…… 《在Matlab中把struct当成Python中的Dictionary使用》《Matlab和Python的几种数据类型的比较》)。
创新互联专注于于都企业网站建设,成都响应式网站建设公司,商城网站建设。于都网站建设公司,为于都等地区提供建站服务。全流程定制开发,专业设计,全程项目跟踪,创新互联专业和态度为您提供的服务
既然提到了MEX,就简单说一下:
一个Matlab可能形如
function ret=add3(a,b,c)
如果在C的层面实现这个函数,就会看到另一种景象:
void mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])
a,b,c三个参数的地址放在一个指针数组里,然后把这个指针数组的首地址作为参数prhs传递给函数,这说明Matlab函数的参数是传递指针的,而不是值传递。
纵然是传递的指针,但是却不能在函数里改变实参的值,因为标记为“const”了。
Python是开放源码的,我没有看。所以下面很多东西是猜的。
Python在函数的参数传递时用的什么手法?实验一下(使用ActivePython2.5):
首先介绍一个重要的函数:
help(id)
Help on built-in function id in module __builtin__:
id(...)
id(object) - integer
Return the identity of an object. This is guaranteed to be unique among
simultaneously existing objects. (Hint: it's the object's memory address.)
看最后括号里那句:Hint:it's the object's address.(它是对象的地址)
有了这个函数,下面的事情就方便多了。
a=0
id(a)
3630228
a=1
id(a)
3630216
可以看出,给a赋一次值,a的address就改变了。在C的层面看,(也许真实情况不是下面的样子,但作为一个类比应该还是可以的):
void * pa;
pa=malloc(sizeof(int));
*(int *)pa=0;
free(pa);
pa=malloc(sizeof(int));
*(int *)pa=1;
Python中每次赋值会改变变量的address,分配新的内存空间,所以Python中对于类型不像C那样严格要求。
下面看看Python函数参数传递时到底传的什么:
有一个函数:
def changeA(a):
... print id(a)
... a=100
... print id(a)
设定一个变量var1:
var1=10
id(var1)
3630108
changeA(var1)
3630108
3631012
var1
10
调用函数后,从两次print的结果可以看出,传递确实是地址。但是即便如此,在函数内对形参的修改不会对实参造成任何实质的影响,因为对形参的重新赋值,只是改变了形参所指向的内存单元(changeA里两次调用print id(a)得到不同的结果),却没有改变实参的指向。在C的层面看也许类似下面的情节:
void changeA(void * pa)
{
pa=malloc(sizeof(int));
*(int *)pa=100;
free(pa);
}
精通C的你一眼就看出这个函数永远也改变不了它外面的世界。
也就是说虽然传递的是地址,但像changeA这样的函数改变不了实参的值。
也许会感到困扰?不,我已经在Matlab中习惯了。
一个最典型的例子就是Matlab中删除结构体成员的rmfield函数(参见《Matlab笔记三则》),
(Matlab版本7.0.1)
如果想删除结构体patient的name成员,用
rmfield(patient, 'name');
是永远达不到目的的(就像试图用双手抓住自己的领子,把自己提到空中);
迷途知返的做法是:
patient = rmfield(patient, 'name');
python如何使用在函数中传递参数
def a(): global q q=1+2 return q def b(): a() c=2+q print(c) b()5 q3 函数中的变量在外面调用,需要申明为全局变量
Python 的函数是怎么传递参数的
对象vs变量
在python中,类型属于对象,变量是没有类型的,这正是python的语言特性,也是吸引着很多pythoner的一点。所有的变量都可以理解是内存中一个对象的“引用”,或者,也可以看似c中void*的感觉。所以,希望大家在看到一个python变量的时候,把变量和真正的内存对象分开。
类型是属于对象的,而不是变量。
这样,很多问题就容易思考了。
例如:
对象vs变量
12
nfoo = 1 #一个指向int数据类型的nfoo(再次提醒,nfoo没有类型)lstFoo = [1] #一个指向list类型的lstFoo,这个list中包含一个整数1
可更改(mutable)与不可更改(immutable)对象
对应于上一个概念,就必须引出另了另一概念,这就是可更改(mutable)对象与不可更改(immutable)对象。
对于python比较熟悉的人们都应该了解这个事实,在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。那么,这些所谓的可改变和不可改变影响着什么呢?
可更改vs不可更改
12345
nfoo = 1nfoo = 2lstFoo = [1]lstFoo[0] = 2
代码第2行中,内存中原始的1对象因为不能改变,于是被“抛弃”,另nfoo指向一个新的int对象,其值为2
代码第5行中,更改list中第一个元素的值,因为list是可改变的,所以,第一个元素变更为2。其实应该说,lstFoo指向一个包含一个对象的数组。赋值所发生的事情,是有一个新int对象被指定给lstFoo所指向的数组对象的第一个元素,但是对于lstFoo本身来说,所指向的数组对象并没有变化,只是数组对象的内容发生变化了。这个看似void*的变量所指向的对象仍旧是刚刚的那个有一个int对象的list。
如下图所示:
Python的函数参数传递:传值?引用?
对于变量(与对象相对的概念),其实,python函数参数传递可以理解为就是变量传值操作,用C++的方式理解,就是对void*赋值。如果这个变量的值不变,我们看似就是引用,如果这个变量的值改变,我们看着像是在赋值。有点晕是吧,我们仍旧据个例子。
不可变对象参数调用
12345
def ChangeInt( a ): a = 10nfoo = 2 ChangeInt(nfoo)print nfoo #结果是2
这时发生了什么,有一个int对象2,和指向它的变量nfoo,当传递给ChangeInt的时候,按照传值的方式,复制了变量nfoo的值,这样,a就是nfoo指向同一个Int对象了,函数中a=10的时候,发生什么?(还记得我上面讲到的那些概念么),int是不能更改的对象,于是,做了一个新的int对象,另a指向它(但是此时,被变量nfoo指向的对象,没有发生变化),于是在外面的感觉就是函数没有改变nfoo的值,看起来像C++中的传值方式。
可变对象参数调用
12345
def ChangeList( a ): a[0] = 10lstFoo = [2]ChangeList(lstFoo )print nfoo #结果是[10]
当传递给ChangeList的时候,变量仍旧按照“传值”的方式,复制了变量lstFoo 的值,于是a和lstFoo 指向同一个对象,但是,list是可以改变的对象,对a[0]的操作,就是对lstFoo指向的对象的内容的操作,于是,这时的a[0] = 10,就是更改了lstFoo 指向的对象的第一个元素,所以,再次输出lstFoo 时,显示[10],内容被改变了,看起来,像C++中的按引用传递。
python怎么向类中的函数传递参数
Python中函数参数的传递是通过“赋值”来传递的。但这条规则只回答了函数参数传递的“战略问题”,并没有回答“战术问题”,也就说没有回答怎么赋值的问题。函数参数的使用可以分为两个方面,一是函数参数如何定义,二是函数在调用时的参数如何解析的。而后者又是由前者决定的。函数参数的定义有四种形式:
1. F(arg1,arg2,...)
2. F(arg2=value,arg3=value...)
3. F(*arg1)
4. F(**arg1)
第1 种方式是最“传统”的方式:一个函数可以定义不限个数参数,参数(形式参数)放在跟在函数名后面的小括号中,各个参数之间以逗号隔开。用这种方式定义的函数在调用的时候也必须在函数名后的小括号中提供相等个数的值(实际参数),不能多也不能少,而且顺序还必须相同。也就是说形参和实参的个数必须一致,而且想给形参1的值必须是实参中的第一位,形参与实参之间是一一对应的关系,即“形参1=实参1 形参2=实参2...”。很明显这是一种非常不灵活的形式。比如:"def addOn(x,y): return x + y",这里定义的函数addOn,可以用addOn(1,2)的形式调用,意味着形参x将取值1,主将取值2。addOn(1,2,3)和addOn (1)都是错误的形式。
第2种方式比第1种方式,在定义的时候已经给各个形参定义了默认值。因此,在调用这种函数时,如果没有给对应的形式参数传递实参,那么这个形参就将使用默认值。比如:“def addOn(x=3,y=5): return x + y”,那么addOn(6,5)的调用形式表示形参x取值6,y取值5。此外,addOn(7)这个形式也是可以的,表示形参x取值7,y取默认值5。这时候会出现一个问题,如果想让x取默认值,用实参给y赋值怎么办?前面两种调用形式明显就不行了,这时就要用到Python中函数调用方法的另一大绝招 ──关健字赋值法。可以用addOn(y=6),这时表示x取默认值3,而y取值6。这种方式通过指定形式参数可以实现可以对形式参数进行“精确攻击”,一个副带的功能是可以不必遵守形式参数的前后顺序,比如:addOn(y=4,x=6),这也是可以的。这种通过形式参数进行定点赋值的方式对于用第1种方式定义的函数也是适用的。
上面两种方式定义的形式参数的个数都是固定的,比如定义函数的时候如果定义了5个形参,那么在调用的时候最多也只能给它传递5个实参。但是在实际编程中并不能总是确定一个函数会有多少个参数。第3种方式就是用来应对这种情况的。它以一个*加上形参名的方式表示,这个函数实际参数是不一定的,可以是零个,也可以是N个。不管是多少个,在函数内部都被存放在以形参名为标识符的tuple中。比如:
对这个函数的调用addOn() addOn(2) addOn(3,4,5,6)等等都是可以的。
与第3种方式类似,形参名前面加了两个*表示,参数在函数内部将被存放在以形式名为标识符的dictionary中。这时候调用函数必须采用key1=value1、key2=value2...的形式。比如:
1. def addOn(**arg):
2. sum = 0
3. if len(arg) == 0: return 0
4. else:
5. for x in arg.itervalues():
6. sum += x
7. return sum
那么对这个函数的调用可以用addOn()或诸如addOn(x=4,y=5,k=6)等的方式调用。
上面说了四种函数形式定义的方式以及他们的调用方式,是分开说的,其实这四种方式可以组合在一起形成复杂多样的形参定义形式。在定义或调用这种函数时,要遵循以下规则:
1. arg=value必须在arg后
2. *arg必须在arg=value后
3. **arg必须在*arg后
在函数调用过程中,形参赋值的过程是这样的:
首先按顺序把“arg”这种形式的实参给对应的形参
第二,把“arg=value”这种形式的实参赋值给形式
第三,把多出来的“arg”这种形式的实参组成一个tuple给带一个星号的形参
第四,把多出来的“key=value”这种形式的实参转为一个dictionary给带两个星号的形参。
例子:
1. def test(x,y=5,*a,**b):
2. print x,y,a,b
就这么一个简单函数,来看看下面对这个函数调用会产生什么结果:
test(1) === 1 5 () {}
test(1,2) === 1 2 () {}
test(1,2,3) === 1 2 (3,) {}
test(1,2,3,4) === 1 2 (3,4)
test(x=1) === 1 5 () {}
test(x=1,y=1) === 1 1 () {}
test(x=1,y=1,a=1) === 1 1 () {'a':1}
test(x=1,y=1,a=1,b=1) === 1 1 () {'a':1,'b':1}
test(1,y=1) === 1 1 () {}
test(1,2,y=1) === 出错,说y给赋了多个值
test(1,2,3,4,a=1) === 1 2 (3,4) {'a':1}
test(1,2,3,4,k=1,t=2,o=3) === 1 2 (3,4) {'k':1,'t':2,'o':3}
python怎么传参
Python函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递
机制有两种:值传递和引用传递。值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开
辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作
为局部变量进行,不会影响主调函数的实参变量的值。(推荐学习:Python视频教程)
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函
数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正
因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
网站栏目:python函数妃传参数 python函数怎么传参数
文章路径:http://pwwzsj.com/article/dochjdh.html