Python基础 函数 高级特性
这两天就啃了这么点Pyhon的东西,感觉还是很概念。但有几个真的理解起来很抽象,但有觉得很重要,先写下来,后面看看是否被我预言中了——标红的那些。
没标题,留个爪list和tuple
list:列表,一种有序的集合,例子: ['帅哥', '靓哥', '小哥哥']
tuple:元组,和list非常类似,但tuple一旦初始化就不能修改,例子: ('帅哥', '靓哥', '小哥哥')
list有append() insert() pop() 等方法,tuple没有
哪些是tuple类型dict和set
dict:全称dictionary(其他语言:map),使用键-值(key-value)存储,具有极快的查找速度。 例子:{'Michael':95,'Bob':75,'Tracy':85}。
set:与dict类似,也有一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
为什么dict查找速度这么快?因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。
第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字。无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。
list和dict比较,dict是用空间来换取时间的一种方法。
和list比较,dict有以下几个特点:
查找和插入的速度极快,不会随着key的增加而变慢;
需要占用大量的内存,内存浪费多。
而list相反:
查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少。
递归函数
递归函数:如果一个函数在内部调用自身本身,这个函数就是递归函数。
举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:
fact(n)= n!= fact(n-1) * n
所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。
于是,fact(n)用递归的方式写出来就是:
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
可以看到,return fact_iter(num - 1, num * product) 仅返回递归函数本身, num-1 和 num*product 在函数调用前就会被计算,不影响函数调用
这两个的执行对比:
列表生成式
列表生成式,是Python内置的非常简单却强大的可以用来创建list的生成式。
一行语句代替循环 表达式x * x写在前面 for后面加判断,进行筛选if 写在 for 后面是筛选,不用带else
if 写在 for 前面是表达式,要带else
这是因为for前面的部分是一个表达式,它必须根据x计算出一个结果。因此,考察表达式:x if x % 2 == 0,它无法根据x计算出结果,因为缺少else,必须加上else。
生成器
生成器:generator,在Python中,这种一边循环一边计算的机制。
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:
当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:
迭代器
可迭代对象 与 迭代器。(Iterable vs Iterator)
iter()函数编程迭代器
网友评论