最近一直在自学 Python ,学习过一段时间后,为了方便以后自己的记忆。写一些学习过程中的东西,用来来记录之前的学习过程,本篇通过杨辉三角来记录下之前的学习经历。
平时主要在廖雪峰老师的教程网站上进行学习,这里要感谢廖雪峰老师的无私分享。
杨辉三角:
前提:每行端点与结尾的数为1.
- 每个数等于它上方两数之和。
- 每行数字左右对称,由1开始逐渐变大。
- 第n行的数字有n项。
- 第n行数字和为2n-1。
还有其他各种特性。
这里我们主要利用第一点的特性来实现该算法。
先贴代码:
12345678910111213def triangles():L = [1]while True:yield LL = [1] + [L[i] + L[i+1] for i in range(0,len(L)-1) if len(L) >= 2]L.append(1)n = 0for t in triangles():print(t)n = n + 1if n == 6:break
代码块说明:
def : 这在 Python 中代表一个方法,triangles()就是一个方法,可以在后面的程序用直接调用,如:
1for t in triangles():该段直接调用了该方法,跟其他高级语言中调用,是大同小异。
yield : 带有 yield 的函数在 Python 中被称之为 generator(生成器),生成器的内容就不在此累赘,不了解的同学可以 google 一下。根据我自学过程,统一采用我 google 到的答案进行描述。这里将用如何生成斐波那契數列来进行一系列说明。
斐波那契(Fibonacci)数列是一个非常简单的递归数列,除了第一个第二个数外,任意一个数都可由两个数相加得到。用计算机程序输出菲波那切数列的前 N 个数是一个非常简单的问题,许多初学者都可以轻易写出如下函数:
- 方法1:
123456789def fab(max):n, a, b = 0, 0 ,1while n < max:print(b)a, b = b, a + bn = n + 1# 执行fab(5):fab(5)得到:
1234511235结果没问题,但是这里会有一个问题产生,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为无法获取该函数生成的数列。
而为了提高 fab 函数的可复用性,最好不要直接打印数列,而是返回一个list.
- 方法2:
123456789101112def fab(max):n, a, b = 0, 0 ,1L = []while n < max:L.append(b)a, b = b, a + bn = n + 1return L# 执行fab(5),并循环输出fab(5)for n in fab(5):print(n)得到结果:
123456711235***Repl Closed***改写后的 fab 函数通过返回的 List 能满足复用性的要求,但是这里又会出现另一个问题,该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,就最好不要用 List 来保存中间结果,而是用过 iterable 对象来迭代。
- 方法3:
1234567891011121314151617181920212223242526class Fab(object):def __init__(self,max):self.max = maxself.n, self.a, self.b = 0, 0, 1def __iter__(self):return selfdef next(self):if self.n < self.max:r = self.bself.a, self.b = self.b, self.a + self.bself.n = self.n + 1return rraise StopIteration()s = Fab(5);#通过执行next得到r每次r的值print(s.next())print(s.next())print(s.next())print(s.next())print(s.next())print(s.next())#因为只是Fab(5),所以这是第六次,会终止结果得到
1234567891011121311235Traceback (most recent call last):File "fibonacci.py", line 25, in <module>print(s.next())File "fibonacci.py", line 16, in nextraise StopIteration()StopIteration***Repl Closed***然而,使用 calss 改写的这个版本,代码明显没有方法一使用 fab 函数来的简洁。这时候为了保证具有代码的简洁性的同时又可以获得 iterable 的效果,yield 就派上用场了。
- 方法4:
123456789def fab(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1for n in fab(5):print(n)得到:
123456711235***Repl Closed***结果跟上面的方法都是一样的。但是这里仅仅是把 方法一的 print 改成 yield 就实现了代码简洁和获取 iterable 的效果。
总结:yield 的作用就是把一个函数变成一个 generator(生成器),带有 yield 的函数也不再是一个简单的函数,Python 解释器会将其视为一个 generator ,调用 fab(5) 不会执行 fab 函数内部的代码,而是返回一个额iterable 对象。
for i in range(0,len(L)-1) if len(L) >= 2: 这是一个列表生成式(List Conprehensions),是 Python 内置的非常简单却强大的可以用来创建 List 的生产式。举个栗子:要生成 list [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 可以:
1234print(list(range(1,11)))结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]但是如果要得到一个 [1x1, 2x2, 3x3, …, 10x10] 怎么做呢?不用列表生成器的话就是用循环完成:
12345678L=[]for x in range(1,11):L.append(x*x)print(L)结果:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]但是这种循环一看就感觉比较繁琐,而用列表生成式就可以这样使用:
1print([x*x for x in range(1,11)])结果和上面循环是一样的,同时我们还可以在后面加上 判断语句,比如现在只输出偶数的结果:
1234print([x*x for x in range(1,11) if x%2==0])结果:[4, 16, 36, 64, 100]并且,这里面还可以进行两层循环:
1234print([x*y for x in range(1,11) for y in range(2,6) if x%2==0])结果:[4, 6, 8, 10, 8, 12, 16, 20, 12, 18, 24, 30, 16, 24, 32, 40, 20, 30, 40, 50]在本次算法中,灵活运用到列表生成式,省去了很多代码,但是同时,代码的可读性变差了,当然熟悉 python 之后这点可读性可以去掉。
输出说明
算法代码片段的后面输出中,因为 L 定义是一个数组,而在 def 中没有加判断终结条件,所以在后面的 for 语句下,加入了 break ,终结代码。
函数 triangles 执行后,在函数 triangles里面包含了很多个 L 数组,使用print(t) 则每次输出一个 L 数组,就会形成所以需要的杨辉三角。
本次算法学习到此结束。