1.函数
定义函数
语法:
def 函数名(参数):
函数体
return参数
在Python交互环境中定义函数时如下,在连续按两回回车后,函数定义结束。
形参实参return等语法和其他语言没有不同
a.内置函数
可以去官网帮助文档查找
http://docs.python.org/3/library/functions.html#abs
通过help(函数名)查看函数的帮助信息。
如果传入的参数数量不对,会报TypeError的错误。
max( ) 返回最大值
float( ) 返回浮点数
int( ) 返回整数
str( ) 返回字符串
bool( ) 返回True和False
b.空函数
通过使用pass语句定义,函数在运行的时候不报错。
pass还可以用在其他语句里,比如if。
c.返回多个值
其实这只是一种假象,Python函数返回的仍然是单一值。返回的其实是一个tuple。
b.函数的参数
传入多个参数
def 函数名(参数1, 参数2, …):
默认参数
def 函数名(参数1, 参数2=值, …):
注意:
一是必选参数在前,默认参数在后。
二是如何设置默认参数。
(当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。)
作用:
默认参数降低了函数调用的难度,提升了效率。
默认参数最需要注意的一点:
定义默认参数要牢记一点:默认参数必须指向不变对象!
例子:
先定义一个函数,传入一个list,添加一个END再返回:
def add_end(L=[]):
L.append('END')
return L
当你正常调用时,结果似乎不错:
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']
当你使用默认参数调用时,一开始结果也是对的:
>>> add_end()
['END']
但是,再次调用add_end()时,结果就不对了:
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
因为默认参数L也是一个变量,每一回的改变都改变了参数L的值。
要修改上面的例子,我们可以用None这个不变对象来实现:
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
可变参数
def 函数名(*参数):
定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:
如果已有一个list或者tuple,要调用一个可变参数时
例子:
nums = [1, 2, 3]
calc(*nums)
在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
关键字参数
而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
例子:def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
限制关键字参数的名字,就可以用命名关键字参数
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错
命名关键字参数可以有缺省值,从而简化调用:
如果没有可变参数,就必须加一个*作为特殊分隔符。
e.递归函数
函数对自身进行反复调用,直到满足某个条件而停止调用并且返回结果。
递归调用的次数过多,会导致栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化
把上例改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中。
针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
2.高级特性
python独有的特性
a.切片
取一个list或tuple的部分元素使用切片,以获得我们需要的结果。
b.迭代
如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
在Python中,迭代是通过for ... in来完成的,而很多语言比如C语言,迭代list是通过下标完成的,比如Java代码。
Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。
list这种数据类型虽然有下标,但很多其他数据类型是没有下标的,但是,只要是可迭代对象,无论有无下标,都可以迭代,比如dict就可以迭代。
当我们使用for循环时,只要作用于一个可迭代对象,for循环就可以正常运行,而我们不太关心该对象究竟是list还是其他数据类型。
如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
c.列表生成式
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来。
for循环后面还可以加上if判断
还可以使用两层循环
列表生成式的使用:
Python 字典 items() 方法以列表返回可遍历的(键, 值) 元组数组。
列表生成式可以使用两个变量来生成
d.生成器
列表容量肯定是有限的,如果列表有很多元素,而我们仅访问前面几个,那后面的空间就会被浪费。如果列表元素可以按照某种算法推算出来,我们为了节省空间,可以利用这种一边循环一边计算的机制:生成器:generator。
创建生成器 第一种方法
把一个列表生成式的[]改成()
创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值,没有更多的元素时,抛出StopIteration的错误。
因为generator也是可迭代对象,所以可以使用for循环来打印。
创建生成器 第二种方法
在一个函数的函数体中,把需要的变量或者是需要不断规律变化并且需要显示或者之后使用的变量前面加上yield关键字即可建立一个生成器的结构。
但是有结构并不等于有这个对象了,所以必须先生成一个对象。
注意:generator在执行过程中,遇到yield就中断,下次又继续执行。
用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
e.迭代器和生成器的一些关键内容
可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象:
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象。
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
Python的for循环本质上就是通过不断调用next()函数实现的。