189 8069 5689

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中变量的引用、可变和不可变类型、局部变量和全局变量

变量的引用

变量和数据都是保存在内存中的

变量和数据是分开存储的

数据保存在内存中某个位置,通过地址来标记

变量保存的是数据的地址,通过地址可以找到数据在内存空间的位置

把变量保存数据地址的过程称为引用

变量的重新赋值修改的是变量中引用数据的内存地址

变量之间的赋值实际是引用的传递

函数参数的传递,本质也是引用的传递

函数的返回值本身也是引用的传递

可变和不可变类型

不可变类型,内存中的数据不允许被修改:数字类型(int,bool,float,complex,long(2,x)、字符串、元组(tuple)

可变类型,内存中的数据可以被修改:列表list、字典dict

无论是可变还是不可变数据类型,通过赋值语句,都会改变变量的引用

Hash函数只能接收不可变数据类型,字典的键也只能是不可变数据类型,字典的value值可以是任意数据类型

局部变量

1.在函数内部定义的变量就是局部变量(作用范围只能是当前函数内部)

2.在函数外部无法直接访问局部变量

3.不同的函数中可以定义同名的局部变量

4.局部变量的生命周期:从定义变量时开始,到函数运行结束

全局变量

1.在所有函数外边定义的变量就是全局变量

2.让所有函数都能访问到,可以作为函数通信的桥梁

3.一般情况下,为了和普通变量的区别,需要加上g_或gl_前缀

4.全局变量一般放在所有函数的最上面

5.在函数内部修改全局变量,必须要加上global关键字,如果不加global只是定义了一个同名的局部变量

函数的多个返回值

Python函数的参数类型

Python函数的参数类型主要包括必选参数、可选参数、可变参数、位置参数和关键字参数,本文介绍一下他们的定义以及可变数据类型参数传递需要注意的地方。

必选参数(Required arguments)是必须输入的参数,比如下面的代码,必须输入2个参数,否则就会报错:

其实上面例子中的参数 num1和num2也属于关键字参数,比如可以通过如下方式调用:

执行结果:

可选参数(Optional arguments)可以不用传入函数,有一个默认值,如果没有传入会使用默认值,不会报错。

位置参数(positional arguments)根据其在函数定义中的位置调用,下面是pow()函数的帮助信息:

x,y,z三个参数的的顺序是固定的,并且不能使用关键字:

输出:

在上面的pow()函数帮助信息中可以看到位置参数后面加了一个反斜杠 / ,这是python内置函数的语法定义,Python开发人员不能在python3.8版本之前的代码中使用此语法。但python3.0到3.7版本可以使用如下方式定义位置参数:

星号前面的参数为位置参数或者关键字参数,星号后面是强制关键字参数,具体介绍见强制关键字参数。

python3.8版本引入了强制位置参数(Positional-Only Parameters),也就是我们可以使用反斜杠 / 语法来定义位置参数了,可以写成如下形式:

来看下面的例子:

python3.8运行:

不能使用关键字参数形式赋值了。

可变参数 (varargs argument) 就是传入的参数个数是可变的,可以是0-n个,使用星号( * )将输入参数自动组装为一个元组(tuple):

执行结果:

关键字参数(keyword argument)允许将任意个含参数名的参数导入到python函数中,使用双星号( ** ),在函数内部自动组装为一个字典。

执行结果:

上面介绍的参数可以混合使用:

结果:

注意:由于传入的参数个数不定,所以当与普通参数一同使用时,必须把带星号的参数放在最后。

强制关键字参数(Keyword-Only Arguments)是python3引入的特性,可参考:。 使用一个星号隔开:

在位置参数一节介绍过星号前面的参数可以是位置参数和关键字参数。星号后面的参数都是强制关键字参数,必须以指定参数名的方式传参,如果强制关键字参数没有设置默认参数,调用函数时必须传参。

执行结果:

也可以在可变参数后面命名关键字参数,这样就不需要星号分隔符了:

执行结果:

在Python对象及内存管理机制中介绍了python中的参数传递属于对象的 引用传递 (pass by object reference),在编写函数的时候需要特别注意。

先来看个例子:

执行结果:

l1 和 l2指向相同的地址,由于列表可变,l1改变时,l2也跟着变了。

接着看下面的例子:

结果:

l1没有变化!为什么不是[1, 2, 3, 4]呢?

l = l + [4]表示创建一个“末尾加入元素 4“的新列表,并让 l 指向这个新的对象,l1没有进行任何操作,因此 l1 的值不变。如果要改变l1的值,需要加一个返回值:

结果:

下面的代码执行结果又是什么呢?

执行结果:

和第一个例子一样,l1 和 l2指向相同的地址,所以会一起改变。这个问题怎么解决呢?

可以使用下面的方式:

也可以使用浅拷贝或者深度拷贝,具体使用方法可参考Python对象及内存管理机制。这个问题在Python编程时需要特别注意。

本文主要介绍了python函数的几种参数类型:必选参数、可选参数、可变参数、位置参数、强制位置参数、关键字参数、强制关键字参数,注意他们不是完全独立的,比如必选参数、可选参数也可以是关键字参数,位置参数可以是必选参数或者可选参数。

另外,python中的参数传递属于对象的 引用传递 ,在对可变数据类型进行参数传递时需要特别注意,如有必要,使用python的拷贝方法。

参考文档:

--THE END--

python中的注解类,但是函数引用类型怎么注解?

自定义函数是这样做注解的

def add(x:int,y:int)-int:

return x+y

函数引用类型不用注解 由被引用的函数注解


新闻名称:python函数引用型,python类的引用
链接URL:http://cdxtjz.cn/article/hcdgjj.html

其他资讯