函数

定义

        格式为——def  函数名(参数列表):其中冒号指的是代码块的开始,函数本身也是一个代码块,所以需要以冒号开始。

        通过return定义函数的返回值,如果没有return则默认返回提None。

        python中万物皆对象,包括函数,而函数名就是一个指向函数对象的变量而已,因此可以把函数名赋值给另一个变量。如下:

print abs(-32432)
a = abs # 将函数名赋值给另一个变量,此时a就具有求绝对值的功能
print a(-32432)

        因为函数名是一个变量,所有也可以把函数名存储到map,list等序列中。

math = (abs,max,'min') # 元组的元素为函数
print math[0](-2342) # 2342
print math[1](2,0,10,8) # 10
print math[2] # min 第三个元素为字符串

空函数

        内部不进行任何操作的函数叫空函数。java中空函数就是{}中不写代码的函数。python中空函数的定义如下:

def emtpyFunction():
	pass # 这个pass一定不能省略,否则报语法错误

注意:其中的pass关键字一定不能省略,省略就会报错。

作为返回值

        由于函数名本身就是一个指向函数对象的变量,所以函数的返回值可以是一个函数。如下:

def f(x, n):
    return x % n > 0
def getfunc():
    return f
print(getfunc()(10, 5))  # False

        可以根据传入getfunc()中的参数决定具体返回的函数。

        另外,也可将lambda表达式当作返回值。如:

def getfunc(n):
    return lambda x: x % n > 0
print(list(filter(getfunc(3), range(11))))

        首先getfunc()它返回一个lambda表达式,式中的n为3,也就是返回的是lambda x:x%3>0,即不是3的倍数。

        其次filter(),将函数作用于iterable的每一个元素,返回True则保留该元素,否则不保留。它返回的是一个iterator。

        最后是list(),将filter()返回的iterator转换成list,并通过print()进行输出。

        从这可以看出,使用lambda表达式作为返回值时,可以指定表达式中的一部分参数。

函数嵌套

        python中,可以在函数内部定义另一个函数。内部函数引用了外部外部作用域内的变量,那么内部函数就被称为闭包。多次调用外部函数,得到的内部函数并不是同一个。如:

outer(n):
    o = 3  
    def inner(x):
        return n+x+o  # 引用了外层函数的参数n以及变量o
    return inner  # 将内部函数作为返回值返回
f = outer(10)  # 再调用一次outer(10)得到的函数并不会与f一样。
print(f)  # f是一个function,它表示inner(),并且没有立即执行
print(f(1))  # 首先使用outer()获取一个函数,再调用该函数

        简单理解:返回的是一个变量,只不过这个变量指向的是函数而已,而函数是可以执行的但返回的时候只是返回变量,并不会执行函数,直到程序执行这个函数(也就是在代码中调用函数名+(参数))时才执行。

        由于函数在返回时并没有执行,并且使用了外界的,所以当外界变量发生变化时,会影响返回函数的最终执行结果。如:

def outer():
    L = []
    for i in range(1, 4):
        def inner():
            return i * i
        L.append(inner)
    return L
f1,f2,f3 = outer()
print("f1 = %d,f2 = %d,f3 = %d" % (f1(), f2(), f3()))  # f1 = 9,f2 = 9,f3 = 9
        函数返回时并没有立即执行,而当所有的函数都返回结束后,i变成了3。所以f1,f2,f3的结果都是一样的。因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量

如果真要引用循环变量或者后继会发生变量的变量,可以再定义一个函数。如下:

def outer():
    L = []

    def inner(x):
        def g():
            return x*x
        return g
    for i in range(1, 4):
        L.append(inner(i))
    return L
f1,f2,f3 = outer()
print("f1 = %d,f2 = %d,f3 = %d" % (f1(), f2(), f3()))  # f1 = 1,f2 = 4,f3 = 9
        循环时,i的值被存储到inner()的参数x中,而g引用的是inner中的参数x,已经与原来的i没有关系了。当再次调用inner时参数变成了新的i,返回的g是一个新的函数,它引用的是当前inner()的参数,与上一个g完全不同。所以输出的结果就是不同的。

返回值

        python中函数可以返回多个值——这只是表象——实际上是将多个值放在一个元组内,并将该元组返回。如下:
def moreReture():
	return 2,5,'return' # 返回多个值,其实是将这些值封装成一个元组返回,只不过表象上是返回多个值
print moreReture() # (2, 5, 'return') 是一个元组
x,y,z = moreReture() # 返回的是一个元组,而元组又可以拆解,所以表面上看一个函数可以返回多个值
print x # 2
print y # 5
print z # return
        之所以这么写,是因为方便。

参数

默认值

        在定义形参时,可以为形参赋值,该值就是形参的默认值。具有默认值的形参,可以不传入实参,并且必须处于所有参数的后面。如:

def add(a,b=3):  # 为形参b赋值默认值3
	return a+b
print(add(3))  #  此处可以只传入一个参数,则第二个参数b就取默认值3,所以输出结果为6

        1,有默认值的形参可以不传入实参,也可以传入实参。有实参时取实参的值,无实参时取默认值。

        2,有默认值的形参必须处于没有默认值的形参后面,即参数列表的最后面。

        3,有多个默认值的形参时,想为某个指定的形参传值而别的形参使用默认值,可以在写实参时使用形参名=参数值。如下:

def add(a=5,b=3):
	print("a =",a,",b =",b)
add(b=15) # 如果不写b=,则15会传给形参a

        要注意的是:形参的名一定要中方法中定义的一样。

问题

        当函数被定义时,默认参数的值就会被计算出来,以后每一次使用该函数默认参数都是同一个。也就是说,在整个应用的生命周期中,函数的默认参数只会被计算一次,以后无论调用多少次函数,默认参数都不变,都是第一次计算出来的值。因此,当使用可变参数为默认参数时,就会出现如下问题:

def function(L=[]):
	L.append('END')
	return L
print function() # ['END']
print function() # ['END', 'END']
        这是因为在函数定义时,L指向的列表对象已经确定,所以每调用一次函数后,L指向的列表都会被修改,这就导致了列表中的元素不断地增加。
        为避免该问题,可以使用None做为默认参数,并且在方法内部显式地为其赋值。如下:
def function(L=None): # 使用None做为默认参数
	if L is None: # 每调用该函数时,L都是None
		print 'L is None'
		L = [] # 每调用该函数,L都被重新赋值为空列表
	L.append('END')
	return L

        总结:禁止使用可变参数做为函数的默认参数

局部变量与全局变量与global

        函数内部是局部变量,其余的为全局变量。如下:

#coding:utf-8
x = "outter"
def fun():
	x = 10 # 局部变量,虽然它的变量名与外界的x相同
	if x:
		print("fun innter",x) # fun innter 10
	print("fun",x)
if x:
	x = "xxxx"
	print("if----",x) # if---- xxxx
fun() # fun 10
print("#"*40)
print(x) # xxxx

        可以将整个python代码理解为一个函数,同一个函数内部是可以相互使用、修改,不同的函数内部的是重新定义的,没有办法直接相互影响。如第二个if判断是和x="outer"定义在同一函数中,所以使用的时x就是outer;第一个if判断是和x=10处于同一个函数中的,所以使用时x=10。

        global:将一个变量定义为全局变量。如果已有同名的全局变量,则指的就是该全局变量;如果没有定义,就相当于新定义一个全局变量。如:

#coding:utf-8
x = "outter"
def fun():
	global y,x
	y = "fun"
	print(x) # outter
fun()
print(y) # fun

        global定义了新全局变量y,所以外界可以使用y。而global又在fun中引用了全局变量x,所以fun中可以使用全局变量x。

参数与元组

        元组可以拆解(如a,b=("aaa","bbb")给变量a,b赋值),对于有多个参数的函数时,所以可以将元组拆分赋值给不同的形参。如下:

def fun(a,b):
	print("%s=%s" % (a,b))
fun(*(3,5))

        *:将list或tuple变成可变参数传入到函数中,或者说将list或tuple拆解传入到函数中。这时不能直接传入一个元组,因为会将元组当作一个具体的参数,而不会将元组进行拆解赋值给两个形参。

        %s:与c中%s,%d等表示法完全一致,都表示将参数按相应的类型进行格式化。

        %():括号中的参数表示格式化时使用到的数据。也就是说print()函数中的参数完全是和c中一样的,都是将参数进行格式化后输出。如

>>> def f(x,y):
...     print("%d-%d=%d" % (x,y,x-y))
...
>>> f(3,5)
3-5=-2

        元组中元素的个数必须与函数的参数一致。

参数与字典

        与元组类似,只不过传入的时候需要使用**。将dict中的键值对以key=value的形式传入函数中。在python中,可以通过赋值的方式为某一个具体的参数传值。如下:

def function(a,b):
	return a**b
print function(b=2,a=3) # 9,为指定的参数传值,而不需要考虑形参的顺序

        因此,**dict的作用就是将字典中的key当作形参名,value当作实参传递到函数中。如果函数中有相应的形参名,那该形参就会接收对应的value,如果没有就会报错(除非形参中定义了可变参数)。

        字典的Key与参数的参数名一致——名一致、个数一致,但顺序可以不一致。如:

def function(a,b,**c):
	for k,v in c.items():
		print 'k = %s,v=%s'%(k,v) # k = d,v=dddd
	return a**b
p ={'b':3,'a':4,'d':'dddd'}
print function(**p)  # 64
        有名为a,b的形参,所以p中的a,b对应的value就会传给函数中形参a,b。而没有形参名为d的形参,所以d的value就会存储到可变参数c中。

处理多余的实参

        一般来说,函数定义结束后形参的个数已经固定了,但有时候可能传入的实参个数比形参个数多,此时会报错。

可变参数——使用元组存储多余参数

def fun(a,*b): # *表示b是一个元组,用于存储多余的实参
	print("%s's age is %s" % (a,b))
fun("zhangsan",34,343) # zhangsan's age is (34, 343)

        在定义形参时以*+参数名形式,则该参数代表的就是一个元组,是一个可变参数,调用函数时传入的多余实参就会存储到可变参数中。

        上面调用函数时,除了第一个参数传给了形参a,其余两个参数都存储到了元组b中。同样,在调用的时候还可以再多传入一些参数。

关键字参数——**以字典存储多余参数

        在传参时,可以为指定的形参赋值(arg=value就是为形参名为arg的形参赋值为value),此时接收多余的参数就需要使用字典,用**表示。如下:

def fun(a,*b,**c): # **表示c是一个字典
	print("%s's age is %s and %s" % (a,b,c))
fun("zhangsan",34,343,x=10,name="xxx") # zhangsan's age is (34, 343) and {'name': 'xxx', 'x': 10}

        在定义形参时以**+参数名形式定义,则该参数代表的是一个dict,是一个关键字参数,调用函数时传入的多余的key=value形式的实参就会传入到dict中。

        可以看出将最后的x=10,name="xxx"全部存储到字典c中。

        将字典与元组添加到函数中后,该函数就可以接收任意的参数——无论是个数还是形式。

定义关键字参数

        3.5版本才可以用。

        虽然可以通过**kw将用户传入的多余的关键字给保存起来,但这也允许了用户随意传入关键字——有些关键字并不是想要的。因此,可以指定关键字。注意:如果定义了关键字,传参时必须为该关键字传值。有两种方法。

        1,如果参数中有可变参数,则在可变参数之后关键字参数之前,定义自己指定的关键字。

        2,如果参数中没有可变参数,则在默认参数之后,跟一个*号,并在*之后,关键字参数之前,定义自己指定的关键字。如:

def test(a,b=3,*c,city): # city就是指定的关键字
    print(a,b,c,city)
test(3,4,6,'a','b',city='bijing') # 传入参数时,只能传入city,如果写别的就会出错。除非参数中有定义的有关键字参数

        上述中有可变参数,所以关键字定义在*c之后。在传参时,除了city='',不能再写别的Key=value。因为没有定义关键字参数。

总结

        实参中含有*,**,代表着该实参进行拆解。有相应的形参的就传递给相应的形参,没有的就传递给相应的可变参数,也没有用报错。

        形参中含有*,**,代表该形参是可变参数,可以接收多余的实参。

        几种参数的顺序为:必选参数(又叫位置参数),有默认值的参数,可变参数,关键字参数。大致为def f(a,b=2,*c,**d)。

lambda表达式

        冒号前是参数,多个参数通过逗号隔开,冒号左边是返回值,不需要写return。如:

>>> g=lambda x,y:x**y # lambda表达式
>>> g(2,3)
8




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值