Python进阶:构建一个简单的斐波那契数列函数

目录

一、写在前面的话:

二、代码实现

2.1 简介

2.2 构思

2.3 代码实现与剖析

2.3.1 def语句、命名规范以及为什么要使用函数

2.3.2 关于形参与实参

2.3.3 文档字符串

2.3.4 简洁的赋值方式:a, b = 0, 1

2.3.5 while循环与print函数

2.3.6 try...except...语句,以及关于多态的简单介绍

2.4 改进方案

2.5 其他的解法(关于递归)


 

一、写在前面的话:

        作为一个可怜的中学生,做什么事情都三分钟热度,因此写下这个强迫自己坚持(作为初三学生也只有周末有空啊),,,

        PS:文章内容属原创,如有雷同纯属偶然,部分引用或转载会说明出处,如侵权请联系删除(邮箱:cdcos@outlook.com/cdcos@qq.com)

print("-"*40)

--------------------------------------------------------------------------------------

二、代码实现

        废话少说,上正文:

        今天的任务就是构建一个简单的函数,这个函数生成一个斐波那契数列。

2.1 简介

        首先介绍一下:

        斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(≥ 2,∈ N*)在现代物理、准晶体结构、化学等领域,斐波那契数列都有直接的应用,为此,美国数学会从 1963 年起出版了以《斐波那契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。 (引自百度百科)

        简单概括一下:1,1,1+1=2,1+2=3,2+3=5,3+5=8......

2.2 构思

        了解定义之后,首先构思一下如何写代码:定义开始的两项,后面每项等于前两项之和。还要增加一个判断条件,达到某个值就停止,不然停不下来了。

2.3 代码实现与剖析

        上代码: 

def fib(n): #定义函数
    """Print a Fibonacci series up to 'n'.""" #文档字符串
    a, b = 0, 1 #先定义第一,二项
    while a < n: #判断是否满足条件
        print(a, end=" ") #输出第一项
        a, b = b, a + b #计算紧接着的下一项(前两项之和)

if __name__ == "__main__":
    try:
        foo = int(input()) #循环的最大数值由用户决定
        fib(foo) #调用函数
    except: #当输入的不是整数时:
        foo = int(input("Please input an integer!")) #输出提醒
        fib(foo)

这是一个示例,如果有优化建议可以评论或者私信。

下面开始剖析这个函数:

2.3.1 def语句、命名规范以及为什么要使用函数

def fib(n):

这是用来定义一个函数的语句,其中

def Function(parameter) 

用来定义一个函数,Function为函数名。注意函数的命名应符合一定规范(你不符合也可以,但是这会使你的代码缺乏可读性,且会给他人阅读带来不便):

类:

总是使用首字母大写单词串。如MyClass。内部类可以使用额外的前导下划线。

函数&方法:

小写+下划线

注意:混合大小写仅被允许用于这种风格已经占据优势的时候,以便保持向后兼容。

函数和方法的参数(形参):

如果一个函数的参数名称和保留的关键字冲突,通常使用一个后缀下划线

全局变量

对于from M import *导入语句,如果想阻止导入模块内的全局变量可以使用旧有的规范,在全局变量上加一个前导的下划线。

注意:应避免使用全局变量

变量

小写,由下划线连接各个单词。如color = WHITE,this_is_a_variable = 1

大致概括了一下,这方面异议很多,所以并没有一个死的规范;比如你是Windows用户,那你的编程习惯会与Linux用户有很大不同。注意函数(方法)的命名除了上述规范,还应简洁且清晰地体现此函数的作用/功能。

为什么要使用函数?原因仅供参考:1、函数可以使一个大问题分化为多个小问题(化整为零),每个函数负责一个问题,再化零为整,组合起来。作者就尝试过不用函数编程,两个小时不是这里报错就是这里报错,几乎要了我的键盘的命(差点把键盘摔了);

2、使用函数能够避免一段代码的反复重用(即”DRY“,Don't repeat yourself),进而提高代码可读性与简洁程度。


2.3.2 关于形参与实参

“parameter”是参数(更准确地说,形参),用来向函数主体传递值(实参);

对形参和实参做一个简单的区分:形参就相当于一个标签,可以贴在不同的值上,后面的函数方法体可以通过此标签找到对应的值,所以说形参的作用就是传递值,真正传递的是形参所代表的实参。一个形参可以接受不同的值。

如果一头雾水,看这里:有一个停车位,编号为021(一个形参);停车场的主机里有一段程序,用伪代码描述:

def 控制停车位上的灯(停车位编号x):

        if 编号为x停车位有车 == True:

                亮对应编号为x的灯

 形参x将实参"021"传入方法体,方法体根据实参的值执行相应的程序。编号并不只有"021"一个,因此形参x可以对应不同的值(实参)。

参数实际上就是变量,而变量的本质就是占位符,表示这里有个东西,至于是什么则等待一个值(对象)被赋给此变量。或者也可以理解为可以到处乱贴的标签,贴在某个对象(值)上就被赋予了该对象的意义。

如果还没有理解,也并不影响你编程,以后会慢慢理解的。


2.3.3 文档字符串

    """Print a Fibonacci series up to 'n'."""

这是可选的文档字符串(docstrings) ,由三个引号包裹,大概解释了此函数的作用/功能。如果有多行,第一行应该为简单的概括性描述,随后空一行,下接详细描述。多行的文档字符串格式如下:

"""................... #简单描述
 #空一行
.......... #详细描述,可以有多行
...............................
..............................."""

在你的代码中包含文档字符串是一个好的实践,让它成为习惯吧。


2.3.4 简洁的赋值方式:a, b = 0, 1

    a, b = 0, 1

 a, b = 0, 1是Python特有的一种简洁的赋值方式,等效于a = 0, b = 1。


2.3.5 while循环与print函数

    while a < n:
        print(a, end=" ")
        a, b = b, a + b

while引导一个循环,条件是判断斐波那契数列的结尾数字小于某个值(这里的某个值在下面定义)。

print() 函数将打印出圆括号内的值。end = ” “表示打印出的数列以空格隔开,如果不写则会分行打印。加引号或双引号表示打印字符串的内容。

a, b = b, a + b与上面是一样的。


2.3.6 try...except...语句,以及关于多态的简单介绍

if __name__ == "__main__":
    try:
        foo = int(input())
        fib(foo)
    except:
        foo = int(input("Please input an integer!"))
        fib(foo)

try....except...... 语句用于可能出现的错误。这里你无法确保用户输入的是一个整数,所以使用此语句可以避免报错。

try子句后跟可能报错的代码,如果不出错则只执行try子句,如果出错则跳到except子句。

int() 函数用于将某个值的类型转化为整数,如果交给int()函数的值不是整数就会报错。其实这里体现了Python与C语言不同之处,C需要在任一函数声明前限制输入类型,而Python则不需要,判断类型的任务交给后面的函数体执行。这就是所谓的”多态“。其实Python的多态不仅仅体现在这里,还体现在关于类的继承方面,这是后面的内容了。

input() 用于导入由用户决定的值(不单单指数字),括号内用于说明用户需要输入什么:

name = input("Please input your name.")
print("Your name is ", name)

#运行结果:
Please input your name.
Harry
Your name is Harry.

fib()实现了对函数fib的调用,即执行打印斐波那契数列的程序。

if __name__ == "__main__":这里就不赘述了,不然太长了。注意的地方就是有两个等号,Python中一个等号表示赋值(给变量),两个等号才是相等。下面有关于其解释:https://blog.csdn.net/sgzqc/article/details/124849467?spm=1001.2014.3001.5506


2.4 改进方案

剖析完毕。也许你会发现这里可以改进:此函数不返回值(实际上它返回None)。因此可以这样改进:

def fib(n): #定义函数
    """Return a list containing the Fibonacci series up to 'n'.""" #文档字符串
    result = [] #创建接受返回值的列表
    a, b = 0, 1 #对第一、二项赋值
    while a < n: #条件
        result.append(a) #向列表内加入值
        a, b = b, a + b #计算数列
    return result #返回值


if __name__ == "__main__":
    try:
        foo = int(input()) #确定循环的上限
        fibfoo = fib(foo) #创建一个对象接受函数的返回值
        print(fibfoo) #打印值
    except: #当输入不是整数时:
        foo = int(input("Please input an integer!")) #输出提醒
        fibfoo = fib(foo)
        print(fibfoo)

其中由于此时函数fib返回值,因此找了一个变量(也可以叫对象或者实例)来接受这个值,再用print语句打印出来。

result是一个列表,append是列表的一个方法,我们用点表示法来调用对象result下的一个方法append(result.append())。append方法用于向列表内加入值,且此值的位置在列表的最后(堆栈顶)。result = [] 用来定义一个空列表。列表还可以使用列表解析列表推导式)。

另一种不使用函数的方案:

try:
    up_num = int(input())
    a, b = 0, 1
    while a < up_num:
        print(a, end=",")
        a, b = b, a + b
except:
    print("Please input an integer!")

2.5 其他的解法(关于递归)

也许你认为到此就结束了。不然。问一问自己是否还有其它解法?如果有,和上面的程序相比哪个运行效率高?

下面解法采用了递归的方式,不懂的可以自己查一查:

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n - 1) + fib(n - 2) #调用程序本身,即递归


if __name__ == "__main__":
    f = fib(10) #调用函数
    print(f)

这个例子不是打印出数列,而是打印出n=10时数列的值。

解析:假设n=3:

1.n=3,fib(3),走return fib(n - 1) + fib(n - 2)分支;

2.fib(3-1),即fib(2),也走else分支,计算fib(2-1)+fib(2-2);

3.fib(2-1)即fib(1),走elif 分支,返回1,fib(2-2)返回0,即fib(3-1)=1+0=1;

4.再计算fib(3-2)=1;

5.fib(3-1)+fib(3-2)=1+1=2,即返回值为2(fib(3)=2)。

 

比较一下两者运行的时间(可以用time模块中的clock()函数,用来计算程序运行时间的。注意Python3.8往后已经没有此函数,可以用

time.process_time()

代替)。可以发现,示例一是0.046875秒,示例二是0.0625秒(循环上限均取10且示例一没有执行except 子句),效率差别很明显了。


 

PS. 示例二的代码引自《跟老齐学Python——从入门到精通》,如有侵权请联系删除,邮箱:cdcos@outlook.com/cdcos@qq.com。

 

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值