一、函数的成员
- Python是一种高级动态编程语言,变量类型是随时可以改变的。Python中的函数和自定义对象的成员也是可以随时发生改变的,可以为函数和自定义对象动态增加新成员。
>>> def func():
print(func.x) #查看函数func的成员x
>>> func() #现在函数func还没有成员x,出错
AttributeError: 'function' object has no attribute 'x'
>>> func.x = 3 #动态为函数增加新成员
>>> func()
3
>>> func.x #在外部也可以直接访问函数的成员
3
>>> del func.x #删除函数成员
>>> func() #删除之后不可访问
>AttributeError: 'function' object has no attribute 'x'
二、函数参数
- Python在定义函数时不需要指定形参的类型,完全由调用者传递的实参类型以及Python解释器的理解和推断来决定。
- Python函数定义时也不需要指定函数的类型,这将由函数中的return语句来决定,如果没有return语句或者return没有得到执行,则认为返回空值None。
(一)、形参与实参
对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参。
在有些情况下,可以通过特殊的方式在函数内部修改实参的值,例如下面的代码。
>>> def modify(v): #修改列表元素值
v[0] = v[0]+1
>>> a = [2]
>>> modify(a)
>>> a
[3]
>>> def modify(v, item): #为列表增加元素
v.append(item)
>>> a = [2]
>>> modify(a,3)
>>> a
[2, 3]
修改形参的值会影响实参的要求:
- 可变序列
- 使用下标或序列自身支持的方法
也就是说,如果传递给函数的是可变序列,并且在函数内部使用下标或可变序列自身的方法增加、删除元素或修改元素时,修改后的结果是可以反映到函数之外的,实参也得到相应的修改。
(二)、位置参数
- 位置参数(positionalarguments)是比较常用的形式,调用函数时实参和形参的顺序必须严格一致,并且实参和形参的数量必须相同。
>>> def demo(a, b, c):
print(a, b, c)
>>> demo(3, 4, 5) #按位置传递参数
3 4 5
>>> demo(3, 5, 4)
3 5 4
>>> demo(1, 2, 3, 4) #实参与形参数量必须相同
TypeError: demo() takes 3 positional arguments but 4 were given
(三)、默认值参数
- 默认值参数必须出现在函数参数列表的最右端,且任何一个默认值参数右边不能有非默认值参数。
- 调用带有默认值参数的函数时,可以不对默认值参数进行赋值,也可以赋值,具有较大的灵活性。
>>> def f(a=3,b,c=5):
print a,b,c
Syntaxerror:non-default argument follows default argument
>>> def f(a=3,b):
print a,b
Syntaxerror:non-default argument follows default argument
>>> def f(a,b,c=5):
print a,b,c
>>>f(1,2)
1 2 5
- 连续多次调用该函数而不给参数传值时,再次调用时将保留上一次调用的结果。当使用可变序列作为参数默认值时,一定要谨慎操作。
- 默认值参数只在函数定义时被解释一次
def demo(newitem,old_list=[]):
old_list.append(newitem)
return old_list
print(demo('5',[1,2,3,4]))
print(demo('aaa',['a','b']))
print(demo('a'))
print(demo('b'))
输出结果:
[1, 2, 3, 4, '5']
['a', 'b', 'aaa']
['a']
['a', 'b']
(四)、关键参数
- 关键参数主要指实参,即调用函数时的参数传递方式。
- 通过关键参数,实参顺序可以和形参顺序不一致,但不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦。
>>> def demo(a,b,c=5):
print(a,b,c)
>>> demo(3,7)
3 7 5
>>> demo(a=7,b=3,c=6)
7 3 6
>>> demo(c=8,a=9,b=0)
9 0 8
(五)、可变长度参数
可变长度参数主要有两种形式:
- *parameter用来接受多个实参并将其放在一个元组中
- **parameter接受关键参数并存放到字典中
# *parameter 放在元组中
>>> def demo(*p):
print(p)
>>> demo(1,2,3)
(1, 2, 3)
>>> demo(1,2)
(1, 2)
>>> demo(1,2,3,4,5,6,7)
(1, 2, 3, 4, 5, 6, 7)
#**parameter存入字典
>>> def demo(**p):
for item in p.items():
print(item)
>>> demo(x=1,y=2,z=3)
('y', 2)
('x', 1)
('z', 3)
三、参数传递的序列解包
传递参数时,可以通过在实参序列前加星号将其解包,然后传递给多个单变量形参。
>>> def demo(a, b, c):
print(a+b+c)
>>> seq = [1, 2, 3]
>>> demo(*seq)
6
>>> tup = (1, 2, 3)
>>> demo(*tup)
6
>>> dic = {1:'a', 2:'b', 3:'c'}
>>> demo(*dic)
6
>>> Set = {1, 2, 3}
>>> demo(*Set)
6
>>> demo(*dic.values())
abc
调用函数时如果对实参使用一个星号*
进行序列解包,这么这些解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号**
进行序列解包的参数之前进行处理。
*
对字典解包默认解包出键(key)
**
对字典解包默认解包出是键值对组成的关键参数,如{‘a’:1}解包出为a=1的关键参数
四、变量作用域
如果想要在函数内部修改一个定义在函数外的变量值,可以通过global来定义。这分为两种情况:
- 一个变量已在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内用global声明这个变量,将其声明为全局变量。
- 在函数内部直接将一个变量声明为全局变量,在函数外没有声明,该函数执行后,将增加为新的全局变量。(难点)
>>> x = 5
>>> def demo():
global x
x = 3
y =4
print(x,y)
>>> demo()
3 4
>>> x
3
>>> y
NameError: name 'y' is not defined
- 除了局部变量和全局变量,Python还支持使用nonlocal关键字定义一种介于二者之间的变量。关键字nonlocal声明的变量会引用距离最近的非全局作用域的变量,要求声明的变量已经存在,关键字nonlocal不会创建新变量。
- nonlocal适用于嵌套函数中内部函数修改外部变量的值
五、lambda表达式
lambda 表达式可以用来声明匿名函数,也就是没有函数名字的临时使用的小函数,尤其适合需要一个函数作为另一个函数参数的场合。
格式:
- 冒号左边放原函数参数,可以有多个参数,用逗号隔开
- 冒号右边为返回值。
>>> f = lambda x,y,z:x+y+z #可以给lambda表达式起名字
>>> f(1,2,3) #像函数一样调用
6
>>> g = lambda x, y=2,z=3: x+y+z #参数默认值
>>> g(1)
6
>>> g(2, z=4, y=5) #关键参数
11
lambda 表达式只可以包含一个表达式,该表达式的计算结果可以看作是函数的返回值,不允许包含其他复杂的语句,但在表达式中可以调用其他函数。
>>> def demo(n):
return n*n
>>> demo(5)
25
>>> a_list = [1,2,3,4,5]
>>> list(map(lambda x: demo(x), a_list)) #在lambda表达式中调用函数
[1, 4, 9, 16, 25]