2016年度WEB开发实验室第三次Seminar.

主讲人:马名骏

课件下载: python函数.pdf (下载488)

调用函数

1、什么是函数

函数:

  • 是可以实现一些特定功能的小方法或是小程序。

举个小例子:

  • 计算3的二次方

【2016年度Seminar】(三)Python 函数-Web开发实验室

普通写法

【2016年度Seminar】(三)Python 函数-Web开发实验室

定义“函数”并调用

2、调用函数

Python有很所内置函数,供用户使用:

详细参考:http://docs.python.org/3/library/functions.html#abs

【2016年度Seminar】(三)Python 函数-Web开发实验室

 

调用函数时,一定要注意出入的参数个数及类别,否则极易出错:

>>> ord(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ord() expected string of length 1, but int found
>>>

>>> ord('a','b')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ord() takes exactly one argument (2 given)
>>>

 

定义函数

1、定义函数

如果Python现有函数满足不了要求,那么你可以自己定义你的函数,依次写出函数名、括号、参数和冒号,并用return语句返回函数的返回值。

【2016年度Seminar】(三)Python 函数-Web开发实验室

自定义求平方的函数

【2016年度Seminar】(三)Python 函数-Web开发实验室

自定义求绝对值的函数

2、参数检查

传入了不恰当的参数时,内置函数abs会检查出参数错误,而我们定义的my_abs没有参数检查,会导致if语句出错,出错信息和abs不一样。所以,这个函数定义不够完善。我们可以使用内置函数isinstance()

【2016年度Seminar】(三)Python 函数-Web开发实验室

3、返回多个值

以上所讲的函数中,都只有一个参数,返回也只有一个,那么如果要返会多个参数又会是什么样子?

【2016年度Seminar】(三)Python 函数-Web开发实验室

原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。

Let’s have a test:

自己定义一个函数,计算1²+2²+3²+…+10²

def my_sum(k):
	total = 0
	i = 1
	while i<=k:
		total = total + i*i
		i = i+1
	return total

print(my_sum(10))

 

函数的参数

1、位置参数

Python函数的参数,除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数。

再举个小例子:

如何分别计算x²,x3 ,x4 …

【2016年度Seminar】(三)Python 函数-Web开发实验室

其实,我们采用两个参数(x,n),来表示xn

def my_power(x,n):
	total = 1
	while n>0:
		n=n-1
		total = total * x
	return total

2、默认参数

顾名思义,就是我们在定义方法时,把方法的某些参数固定。好处在于我们调用方法时不需要再把默认参数写出

def my_power(x,n = 2):
	total = 1
	while n>0:
		n=n-1
		total = total * x
	return total

此时:my_power(3)就与my_power(3,2)的值相等

 

思考题:如果将默认参数放在必选参数之前,结果是否一致?

def my_power(x,y = 2,z)

调用my_power(1,2),是想要my_power(1,2,2)还是没有给z设定值?

下面大家再来思考这个问题:

def add_end(L=[]):
    L.append('END')
    return L

输出add_end()是什么?

再输一次呢?

答案:

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

所以,定义默认参数要牢记一点:默认参数必须指向不变对象!

解决方法是把默认参数指向一个不可变对象

def add_end(L=None): 
	if L is None: 
		L = [] 
		L.append('END')
		return L

3、可变参数

指方法中传入的参数数量是可以变化的。

计算a²+b²+c²

def calc(numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

但是调用的时候,需要传入出一个list或tuple:

calc([1, 4, 3])

或者

calc((1, 4, 3))

【2016年度Seminar】(三)Python 函数-Web开发实验室

但如果是使用可变参数,就可以得到简化:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
>>>calc(1,4,6)
53

但是如果已经给了一个list或者tuple,还要用可变参数该怎么做呢?

这个时候就要把list或tuple中的内容转化为可变参数传进去,具体做法如下:

lt = [1,4,6]
def calc(*numbers):
   sum = 0
   for n in numbers:
      sum = sum + n * n
   return sum

>>>clac(*lt)
53

上述两种发法所得结果是相同的。

4、关键词参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def player(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

【2016年度Seminar】(三)Python 函数-Web开发实验室

函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数,也可以传入任意个数的关键字参数.

目的是为了除了填写以固定的参数,还可以让使用者自行添加参数

和可变参数类似,这里也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

【2016年度Seminar】(三)Python 函数-Web开发实验室

5、命名关键词参数

如果想给限定使用者使用哪些关键词参数,需要用*作为分隔,*后面的参数被视为命名关键字参数。【2016年度Seminar】(三)Python 函数-Web开发实验室

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。

def player(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)
player('messi',30,'FC Barcelona')

将会报错:

TypeError: player() takes 2 positional arguments but 3 were given

同默认参数一样,若命名关键词参数有默认值,则调用时可以不传对应参数

def player(name, age, *,club = 'FC Barcelona'):
    print('name:', name, 'age:', age, 'club:',club)

此时player(‘messi’,30)结果与player(‘messi’,30,’ club = ‘FC Barcelona’)相同

6、参数组合

python中定义函数,以上几种参数都可以同时使用,但是一定注意参数顺序必须为:

必选参数、默认参数、可变参数、命名关键字参数和关键字参数

 

递归函数

1、什么是递归函数?

如果一个函数在内部调用自身本身,这个函数就是递归函数:

【2016年度Seminar】(三)Python 函数-Web开发实验室

 

计算10的阶乘:

def rec(n):
	if(n==1):
		return 1
	else:
		return n*rec(n-1)

rec(10)

其实rec(10)在执行时是这样的:

rec(10)
---10*rec(9)
---10*9*rec(8)
---10*9*8*rec(7)
...
---10*9*8*7*6*5*4*3*2*1

2、尾递归

什么是尾递归?

对于递归函数:

def rec(n):
	if(n==1):
		return 1
	else:
		return n*rec(n-1)

可以看出,在每次递归调用的时候,都会产生一个临时变量,导致进程内存占用量增大一些。这样执行一些递归层数比较深的代码时,除了无畏的内存浪费,还有可能导致著名的堆栈溢出错误。

归调用的时候不会产生一系列逐渐增多的中间变量了,而是将状态保存在 tem这个变量中。

而这种形式的递归,就叫做尾递归

函数调用中最后返回的结果是单纯的递归函数调用(或返回结果),不包含任何其他的运算,这种形式的递归称为尾递归:

def rec(n,tem = 1):
	if(n==1):
		return 1
	else:
		return rec(n-1,n*tem)

 

练习

Test1:

  • 自己定义函数,计算第28项斐波那契数列的值是多少(1,1,2,3,5,8,13......)

Test2:

  • 自己定义函数,获取完成8级汉诺塔游戏所需的步骤

参考网站