代码复用技术—函数

函数的定义与使用

基本语法

  • 应尽量减少使用直接复制代码的方式来实现复用
  • def 函数名([参数列表]):
    ‘’‘注释’’’
    函数体
  • 函数形参不需要声明其类型,也不需要指定函数的返回值类型
  • 即时该函数不需要接收任何参数,也必须保留一对空括号
  • 括号后面的冒号必不可少
  • 函数体相对于def关键字必须保持一定的空格缩进
  • 开头的部分注释并不是必须的,若加上,可为用户提供友好的提示和使用帮助
  • 可以使用内置函数help()来查看函数的使用帮助
>>> def fib(n):
	'''接收一个参数n,判断n与a的大小'''
	a=1
	if n>a:
		print(n)
	else:
		print(a)

>>> fib(3)
3
>>> help(fib)
Help on function fib in module __main__:

fib(n)
    接收一个参数n,判断n与a的大小

>>> 

函数嵌套定义

  • Python允许函数的嵌套定义,在函数内部可以再定义另外一个函数
>>> def myMap(iterable,op,value):
	if op not in '+ - * /':
		return '出错'
	def nested(item):
		return eval(repr(item)+op+repr(value))
	return map(nested,iterable)

>>> list(myMap(range(5),'+',5))
[5, 6, 7, 8, 9]
>>> 
  • repr()函数:是用来将任意值转为字符串,转化为供解释器读取的形式
  • str()函数:用于将值转化为字符串,具有良好的可读性

函数参数

  • 函数定义时括号内是使用逗号分隔开的形参列表,参数可以有多个参数,也可以没有参数,但定义和调用时一对括号必须有
  • 定义函数时不需要声明参数类型,解释器会根据实参的类型自动推断形参类型
  • 一般来说,在函数内部直接修改形参的值不会影响实参
>>> def addOne(a):
	a+=1

	
>>> a=3
>>> addOne(a) #调用函数
>>> a
3
  • 但是对于列表、字典、集合这样的可变序列类型作为函数参数时,如果在函数内部通过列表、字典或集合对象自身的方法修改参数中的元素时,同样的作用也会体现到实参上
>>> def modify(v,item): #为列表增加元素
	v.append(item)

	
>>> a=[2]
>>> modify(a,3)
>>> a
[2, 3]
  • Python采用基于值的自动内存管理模式,变量并不直接存储值,而是存储值的引用
  • 在Python中调用函数是,实参到形参都是传递的引用,也就是说Python不存在传值调用

位置参数

  • 位置参数是函数调用时比较常用的形式
  • 调用函数时实参和形参的顺序必须严格一致,并且实参和形参的数量必须相同
>>> def demo(a,b,c):
	print(a,b,c)

	
>>> demo(1,2,3)
1 2 3
>>> demo(1,2,3,4)
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    demo(1,2,3,4)
TypeError: demo() takes 3 positional arguments but 4 were given
>>> 

默认值参数

  • 在定义函数时,Python支持默认值参数,在定义函数时可以为形参设置默认值
  • 在调用带有默认值函数时,不需要给设置了默认值的形参传递参数,此函数会直接默认使用默认值
  • 但也可以通过显示赋值来替换其默认值
  • 需要注意的是,在定义带有默认值函数时,任何一个默认值参数右边都不能再出现没有默认值的普通位置参数
  • 可以使用“函数名.defaults”随时查看函数所有的默认值参数的当前值,其返回为一个元组
>>> def say(message,times=1):
	print((message+' ')*times)

	
>>> say.__defaults__
(1,)
>>> say('hellow') #使用默认值
hellow 
>>> say('hellow',3) #显示传递值
hellow hellow hellow 
>>> 
  • 要避免使用列表、字典、集合或其他可变序列作为函数参数默认值,因为会导致严重的逻辑错误

关键参数

  • 关键参数主要指调用函数时的参数传递方式,通过关键参数可以按参数名字传递值,明确指定哪个值传递给哪个参数
  • 实参顺序可以和形参顺序不一致,但不影响参数的传递结果
>>> def demo1(a,b,c=5):
	print(a,b,c)

	
>>> demo(c=8,a=9,b=0)
9 0 8
>>> 

可变长度参数

  • 可变长度参数在定义函数时主要有两种形式:*parameter和 **parameter
  • 前者用来接收任意多个实参并将其放在一个元组中
  • 后者接收类似于关键参数一样显示赋值形式的多个实参并将其放入字典中
>>> def demo2(*p): #输出的值放在元组中
	print(p)

	
>>> demo2(1,2,3,4,5,6,7,8,9)
(1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> def demo3(**p): #输出的值放于字典中
	for item in p.items():
		print(item)

		
>>> demo3(x=1,y=2,z=3)
('x', 1)
('y', 2)
('z', 3)

传递参数时的序列解包

  • 与可变长度的参数相反,传递参数时的序列解包是指的是实参
  • 同样有两种形式*与**
  • 调用含有多个位置参数的函数时,可以使用Python列表、元组、集合、字典以及其他可迭代对象作为实参,并在实参名称前加一个星号,Python解释器将自动进行解包,然后把序列中的值分别传递给多个单变量形参
>>> def demo4(a,b,c):
	print(a,b,c)

	
>>> seq=[1,2,3]
>>> demo4(*seq) #对列表进行解包
1 2 3
  • 如果实参是个字典,可以使用两个星号对其进行解包,会把字典转换成类似于关键参数传递
  • 对于这种形式的序列解包,要求实参字典中的所有键都必须是函数的形参名称,或者与函数中两个星号的可变长度参数相对应
>>> p={'a':1,'b':2,'c':3} #要解包的字典
>>> def f(a,b,c=5):
	print(a,b,c)

	
>>> f(**p)
1 2 3
  • 如果一个函数需要以多种形式来接收参数,定义时一般把位置参数放在最前面,然后是默认值参数,接下来时一个星号的可变长度参数,最后是两个星号的可变长度参数
  • 调用函数时,一般也按照这个顺序进行参数传递
  • 调用函数时如果对实参使用一个星号*进行序列解包,那么这些解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号**进行序列解包的参数之前进行处理
>>> def demo5(a,b,c):
	print(a,b,c)

	
>>> demo5(a=1,*(1,2)) #一个星号的序列解包相当于位置参数,优先处理,引发异常
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    demo5(a=1,*(1,2))
TypeError: demo5() got multiple values for argument 'a'
>>> 
>>> demo5(c=1,*(2,3)) #优先处理
2 3 1

变量作用域

  • 一个变量已在函数外定义,如果在函数内需要修改这个变量的值,并将修改的结果反映到函数之外,可以在函数内用关键字global明确声明要使用已定义的同名全局变量
  • 在函数内部直接使用global关键字将一个变量声明为全局变量,如果在函数外没有定义该全局变量,在调用这个函数之后,会创建新的全局变量

lambda表达式

  • lambda表达式常用声明匿名函数,即没有函数名字的临时使用的小函数
  • 常用在临时需要一个类似于函数的功能但又不想定义函数的场合
>>> f=lambda x,y,z:x+y+z #也可给lambda表达式起个名字
>>> print(f(1,2,3)) #把lambda表达式当成函数使用
6
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页