导航:首页 > 编程语言 > python传值和函数

python传值和函数

发布时间:2023-09-27 10:35:07

1. 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}

2. Python 定义的函数的参数传递是怎么样的

Python变量没有赋值,都是引用。

大多语言,是声明一个变量,给它分配一个空间保存一个值,也就是赋值。

Python则是给一个值分配一个空间,变量=这个值,只是这个变量引用了这个值的地址,也就是说,a=1,b=1,c=1,Python只分配了一个空间,保存这个值1。 a,b,c都引用了这个地址。

3. Python 函数中,参数是传值,还是传引用

首先还是应该科普下函数参数传递机制,传值和传引用是什么意思?
函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用传递。
值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
在python中实际又是怎么样的呢?
先看一个简单的例子:

from ctypes import *
import os.path
import sys

def test(c):
print "test before "
print id(c)
c+=2
print "test after +"
print id(c)
return c

def printIt(t):
for i in range(len(t)):
print t[i]

if __name__=="__main__":
a=2
print "main before invoke test"
print id(a)
n=test(a)
print "main afterf invoke test"
print a
print id(a)

运行后结果如下:

>>>
main before invoke test
39601564
test before
39601564
test after +
39601540
main afterf invoke test
2
39601564

id函数可以获得对象的内存地址.很明显从上面例子可以看出,将a变量作为参数传递给了test函数,传递了a的一个引用,把a的地址传递过去了,所以在函数内获取的变量C的地址跟变量a的地址是一样的,但是在函数内,对C进行赋值运算,C的值从2变成了4,实际上2和4所占的内存空间都还是存在的,赋值运算后,C指向4所在的内存。而a仍然指向2所在的内存,所以后面打印a,其值还是2.
如果还不能理解,先看下面例子

>>> a=1
>>> b=1
>>> id(a)
40650152
>>> id(b)
40650152
>>> a=2
>>> id(a)
40650140

a和b都是int类型的值,值都是1,而且内存地址都是一样的,这已经表明了在python中,可以有多个引用指向同一个内存(画了一个很挫的图,见谅),在给a赋值为2后,再次查看a的内存地址,都已经变化了

而基于最前面的例子,大概可以这样描述:

那python函数传参就是传引用?然后传参的值在被调函数内被修改也不影响主调函数的实参变量的值?再来看个例子。

from ctypes import *
import os.path
import sys

def test(list2):
print "test before "
print id(list2)
list2[1]=30
print "test after +"
print id(list2)
return list2

def printIt(t):
for i in range(len(t)):
print t[i]

if __name__=="__main__":
list1=["loleina",25,'female']
print "main before invoke test"
print id(list1)
list3=test(list1)
print "main afterf invoke test"
print list1
print id(list1)

实际值为:

>>>
main before invoke test
64129944
test before
64129944
test after +
64129944
main afterf invoke test
['loleina', 30, 'female']
64129944

发现一样的传值,而第二个变量居然变化,为啥呢?
实际上是因为python中的序列:列表是一个可变的对象,就基于list1=[1,2] list1[0]=[0]这样前后的查看list1的内存地址,是一样的。

>>> list1=[1,2]
>>> id(list1)
64185208
>>> list1[0]=[0]
>>> list1
[[0], 2]
>>> id(list1)
64185208

结论:python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。

分类: python 基础语法

4. Python 的函数是怎么传递参数的

首先你要明白,Python的函数传递方式是赋值,而赋值是通过建立变量与对象的关联实现的。
对于你的代码:
执行 d = 2时,你在__main__里创建了d,并让它指向2这个整型对象。
执行函数add(d)过程中:
d被传递给add()函数后,在函数内部,num也指向了__main__中的2
但执行num = num + 10之后,新建了对象12,并让num指向了这个新对象——12。
如果你明白函数中的局部变量与__main__中变量的区别,那么很显然,在__main__中,d仍在指着2这个对象,它没有改变。因此,你打印d时得到了2。
如果你想让输出为12,最简洁的办法是:
在函数add()里增加return num
调用函数时使用d = add(d)
代码如下:
def add(num):
num += 10
return num
d = 2
d = add(d)
print d

5. 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++中的按引用传递。

6. Python的函数和参数

parameter 是函数定义的参数形式
argument 是函数调用时传入的参数实体。

对于函数调用的传参模式,一般有两种:

此外,

也是关键字传参

python的函数参数定义一般来说有五种: 位置和关键字参数混合 仅位置参数 仅关键字参数 可变位置参数 可变关键字参数 。其中仅位置参数的方式仅仅是一个概念,python语法中暂时没有这样的设计。
通常我们见到的函数是位置和关键字混合的方式。

既可以用关键字又可以用位置调用

这种方式的定义只能使用关键字传参的模式

f(*some_list) 与 f(arg1, arg2, ...) (其中some_list = [arg1, arg2, ...])是等价的

网络模块request的request方法的设计
多数的可选参数被设计成可变关键字参数

有多种方法能够为函数定义输出:

非常晦涩

如果使用可变对象作为函数的默认参数,会导致默认参数在所有的函数调用中被共享。
例子1:

addItem方法的data设计了一个默认参数,使用不当会造成默认参数被共享。
python里面,函数的默认参数被存在__default__属性中,这是一个元组类型
例子2:

在例子1中,默认参数是一个列表,它是mutable的数据类型,当它写进 __defauts__属性中时,函数addItem的操作并不会改变它的id,相当于 __defauts__只是保存了data的引用,对于它的内存数据并不关心,每次调用addItem,都可以修改 addItem.__defauts__中的数据,它是一个共享数据。
如果默认参数是一个imutable类型,情况将会不一样,你无法改变默认参数第一次存入的值。

例子1中,连续调用addItem('world') 的结果会是

而不是期望的

阅读全文

与python传值和函数相关的资料

热点内容
java与类名相同 浏览:380
李居明八字pdf 浏览:617
电子技术基础康华光pdf 浏览:340
如何阻止迅雷下app 浏览:360
al150压缩机 浏览:600
手机文件图片怎么解压 浏览:655
分布式系统设计pdf 浏览:181
中轴线趋势指标源码 浏览:721
labview源码代码 浏览:61
15匹谷轮压缩机图片 浏览:818
bsp分割算法 浏览:22
高手选股公式源码 浏览:682
脆皮软心球解压视频十分钟 浏览:404
如何关闭苹果app同步充值 浏览:766
视频压缩发送微信 浏览:856
程序员段子大全图片 浏览:760
javaudp心跳 浏览:429
阿里卖家app如何分配询盘 浏览:828
如何拔打中国移动人工服务器 浏览:505
传奇归来为什么连不上服务器 浏览:555