python函数

2017-03-13  本文已影响0人  bjchenli

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:
a = ab//把函数赋给一个变量a print(a(-1))

1、定义函数

在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
# 定义一个函数my_abs()求绝对值
def my_abs(x): if x > 0: return x else : return -x x = -10 print(my_abs(x))
空函数
如果想定义一个什么事也不做的空函数,可以用pass语句:
def nop(): pass

2、函数的分类

有多个默认参数时,调用的时候,既可以按顺序提供默认参数,比如调用enroll('Bob', 'M', 7),意思是,除了name,gender这两个参数外,最后1个参数应用在参数age上,city参数由于没有提供,仍然使用默认值。

也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin'),意思是,city参数用传进去的值,其他默认参数继续使用默认值。

Python 默认参数提高了变成效率,但是这里面的坑也是坑死人不偿命,使用稍微不正确,会造成致命的失误
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def test(lang=[]): lang.append('python') return lang
当老实调用时,结果如你所愿
print(test(['js','go'])) print(test(['c','java']))
结果如下
['js', 'go', 'python'] ['c', 'java', 'python'] [Finished in 0.1s]
但是如果多次使用默认参数调用时,奇迹出现了
print(test()) print(test())
结果如下:
['python'] ['python', 'python'] [Finished in 0.1s]
或许有人对此感到很困惑,为什么默认参数会记住更新过的默认参数

分析:
函数在定义的时候,默认参数lang的值就已经声明了,即空的 [],也就是说 默认参数 指向对象 [],在多次调用默认参数的情况下,就改变了默认参数指向对象的数据,默认参数 指向对象的数据变了,下次再调用时,默认参数已经变了,即不再是你希望的空的[]

为了便于理解等同下面这段:
temp = [] def test(lang=temp): lang.append('python') return lang
这样就好看多了,多次调用时,temp 也在不断的变化

注意函数默认参数和函数中的参数的上下文环境
结论

定义函数默认参数时,函数默认参数必须指向不变对象,建议使用 None,str 这些不可变对象处理

重新修改代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
`
def test(lang=None):

if lang is None:
lang = []
lang.append('python')
return lang
调用
print(test())
print(test())
结果:
['python']
['python']
[Finished in 0.2s]
`

3.递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000):
def fact(n): if n == 1: return 1 return n*fact(n-1) print(fact(1000))
结果:
RecursionError: maximum recursion depth exceeded in comparison
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num-1, num * product) print(fact(100)) print(fact_iter(100,1))
可以看到,return fact_iter(num - 1, num * product)仅返回递归函数本身,num - 1和num * product在函数调用前就会被计算,不影响函数调用。

尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。

遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。

上一篇 下一篇

猜你喜欢

热点阅读