您好,欢迎访问三七文档
当前位置:首页 > IT计算机/网络 > Python > Python电子教案5-2-函数和代码复用
七段数码管绘制•数码管是一种价格便宜、使用简单的发光电子器件,广泛应用在价格较低的电子类产品中,其中,七段数码管最为常用。七段数码管(seven-segmentindicator)由7段数码管拼接而成,每段有亮或不亮两种情况,改进型的七段数码管还包括一个小数点位置,如图5.4所示。七段数码管绘制七段数码管绘制•七段数码管能形成27=128种不同状态,其中部分状态能够显示易于人们理解的数字或字母含义,因此被广泛使用。图5.5给出了十六进制中16个字符的七段数码管表示。七段数码管绘制•本节将延续实例2和第2.4节内容,通过部分turtle库函数绘制七段数码管形式的日期信息。该问题的IPO描述如下:输入:当前日期的数字形式处理:根据每个数字绘制七段数码管表示输出:绘制当前日期的七段数码管表示七段数码管绘制•每个0到9的数字都有相同的七段数码管样式,因此,可以通过设计函数复用数字的绘制过程。进一步,每个七段数码管包括7个数码管样式,除了数码管位置不同外,绘制风格一致,也可以通过函数复用单个数码段的绘制过程。这里,先给出程序的全部代码,实例代码7.1如下七段数码管绘制•实例代码7.1定义了drawDigit()函数,该函数根据输入的数字d绘制七段数码管,结合七段数码管结构,每个数码管的绘制采用图5.6所示顺序。七段数码管绘制•绘制起点在数码管中部左侧,无论每段数码管是否被绘制出来,turtle画笔都按顺序“画完”所有7个数码管。对于给定数字d,哪个数码段被绘制出来采用if…else…语句判断。drawLine(True)ifdin[2,3,4,5,6,8,9]elsedrawLine(False)七段数码管绘制•以第8行为例,代码采用了单行if…else语句,这种语句常用于if和else分别只有一行语句的情形。第8行代码含义采用普通if…else语句表达如下,可见,单行语句的实现方式能够使表达更加紧凑。ifdin[2,3,4,5,6,8,9]:drawLine(True)else:drawLine(False)七段数码管绘制•第8行代码根据输入数字判断是否要绘制七段数码管最中间的横线•当需要绘制时,调用绘制函数drawLine(),参数赋值True•当不需要绘制时,赋值参数False。根据0-9数字结构,对于2,3,4,5,6,8,9这些数字需要绘制,否则不需要绘制。为了使输出样式固定,简化设计,当不需要绘制时,turtle画笔需要抬起。drawLine()函数根据输出参数的值(True或False)决定是否抬起画笔。七段数码管绘制•为了使代码模块化更好,实例代码7.1定义了drawDate()函数和main()函数。drawDate()函数将更长数字分解为单个数字,进一步调用drawDigit()分别绘制每个数字。main()函数将启动窗体大小、画笔宽度、系统时间等功能封装在一起,但main()函数并不体现单一功能,这种封装仅从提高代码可读性角度考虑。七段数码管绘制实例代码7.1的运行效果•实例代码7.1仅给出了最基本的七段数码管绘制程序,可以看出,使用函数能大量复用代码,避免相同功能重复编写。此外,函数的好处还体现在对代码的修改方面。能否绘制更有趣的七段数码管呢?•实例代码7.2给出了图5.8的绘制风格,请读者比较实例代码7.2和实例代码7.1,进一步体会函数为编程带来的便利。七段数码管绘制实例代码7.2的运行效果代码的复用和模块化设计•程序由一系列代码组成,如果代码是顺序但无组织的,不仅不利于阅读和理解,也很难进行升级和维护。因此,需要对代码进行抽象,形成易于理解的结构。•当代编程语言从代码层面采用函数和对象两种抽象方式,分别对应面向过程和面向对象编程思想。复用和模块化•函数是程序的一种基本抽象方式,它将一系列代码组织起来通过命名供其他程序使用。函数封装的直接好处是代码复用,任何其他代码只要输入参数即可调用函数,从而避免相同功能代码在被调用处重复编写。代码复用产生了另一个好处,当更新函数功能时,所有被调用处的功能都被更新。复用和模块化•对象是程序的一种高级抽象方式,它将程序代码组织为更高级别的类。对象包括表征对象特征的属性和代表对象操作的方法。例如,汽车是一个对象,其颜色、轮胎数量、车型是属性,代表汽车的静态值;前进、后退、转弯等是方法,代表汽车的动作和行为。•在程序设计中,如果a代表对象,获取其属性b采用a.b,调用其方法c采用a.c()。对象的方法具有程序功能性,因此采用函数形式封装。复用和模块化•简单地,对象是程序拟解决计算问题的一个高级别抽象,它包括一组静态值(属性)和一组函数(方法)。从代码行数角度,对象和函数都使用了一个容易理解的抽象逻辑,但对象可以凝聚更多代码。因此,面向对象编程更适合代码规模较大,交互逻辑复杂的程序复用和模块化•面向过程是一种以过程描述为主要方法的编程方式,该方法要求程序员列出解决问题所需要的步骤,然后用函数将这些步骤一步一步实现,使用时依次建立并调用函数或编写语句即可。面向过程编程是一种基本且自然的程序设计方法,函数通过将步骤或子功能封装实现代码复用并简化程序设计难度。•面向过程和面向对象只是编程方式不同、抽象级别不同,所有面向对象编程能实现的功能采用面向过程同样能完成,两者在解决问题上不存在优劣之分复用和模块化•当程序的长度在百行以上,如果不划分模块就算是最好的程序员也很难理解程序含义。解决这一问题的最好方法是将一个程序分割成短小的程序段,每一段程序完成一个小的功能。无论面向过程和面向对象编程,对程序合理划分功能模块并基于模块设计程序是一种常用方法,被称为“模块化设计”。复用和模块化•模块化设计指通过函数或对象的封装功能将程序划分成主程序、子程序和子程序间关系的表达。模块化设计是使用函数和对象设计程序的思考方法,以功能块为基本单位,一般有两个基本要求:紧耦合:尽可能合理划分功能块,功能块内部耦合紧密;松耦合:模块间关系尽可能简单,功能块之间耦合度低。复用和模块化•对比实例代码2.1和实例代码2.3,尽管后者通过函数封装增多了代码行数,但采用drawSnake()函数封装的功能理解起来更加容易。•观察实例代码7.1,采用函数封装后,理解程序的第一层次不再是直接阅读语句,而是阅读函数及其框架,有需要时再进一步理解函数内部语句。为了增强代码可读性,复用和模块化•建议读者采用实例代码7.1中方式,将程序初始化或函数间过度语句封装为main()函数,使得全部代码都由函数组成,最后通过main()语句执行程序。•尽管函数和模块化设计使整个程序看上去篇幅更长,但所增加的封装代码十分有益,它们为程序带来了模块化的层次结构,使程序具有更好的可读性。复用和模块化函数的递归•函数作为一种代码封装,可以被其他程序调用,当然,也可以被函数内部代码调用。这种函数定义中调用函数自身的方式称为递归。就像一个人站在装满镜子的房间中,看到的影像就是递归的结果。递归在数学和计算机应用上非常强大,能够非常简洁的解决重要问题。递归的定义•数学上有个经典的递归例子叫阶乘,阶乘通常定义为:•为了实现这个程序,可以通过一个简单的循环累积去计算阶乘。观察5!的计算,如果去掉了5,那么就剩下计算4!,推广来看,n!=n(n-1)!。递归的定义)1)...(2)(1(!nnnn•实际上,这个关系给出了另一种方式表达阶乘的方式:•这个定义说明0的阶乘按定义是1,其他数字的阶乘定义为这个数字乘以比这个数字小1数的阶乘。递归不是循环,因为每次递归都会计算比它更小数的阶乘,直到0!。0!是已知的值,被称作递归的基例。当递归到底了,就需要一个能直接算出值的表达式。递归的定义10!(1)!nnnnotherwise•阶乘的例子揭示了递归的2个关键特征:(1)存在一个或多个基例,基例不需要再次递归,它是确定的表达式;(2)所有递归链要以一个或多个基例结尾。递归的定义•微实例5.1:阶乘的计算递归的使用方法•fact()函数在其定义内部引用了自身,形成了递归过程。•无限制的递归将耗尽计算资源,因此,需要设计基例使得递归逐层返回。fact()函数通过if语句给出了n为0时的基例,当n==0,fact()函数不再递归,返回数值1,如果n!=0,则通过递归返回n与n-1阶乘的乘积。递归的使用方法•由于负数和小数通过减1无法到达递归的基例,即n==0,代码第7行通过abs()和int()函数将用户输入转变成非负整数,该程序输出效果如下:递归的使用方法请输入一个整数:103628800请输入一个整数:12.345479001600•递归遵循函数的语义,每次调用都会引起新函数的开始,表示它有本地变量值的副本,包括函数的参数。图5.13给出了计算5!的递归调用过程,每次函数调用时,函数参数的副本会临时存储,递归中的各函数在运算自己的参数,相互没有影响。当基例结束函数运算并返回值时,各函数逐层结束运算,向调用者返回计算结果。递归的使用方法递归的使用方法•对于用户输入的字符串s,输出反转后的字符串。•解决这个问题的基本思想是把字符串看作一个递归对象。长字符串由较短字符串组成,每个小字符串也是一个对象。假如把一个字符串看成仅有两部分组成:首字符和剩余字符串。如果将剩余字符串与首字符交换,就完成了反转整个字符串,代码如下。defreverse(s):returnreverse(s[1:])+s[0]微实例5.2:字符串反转•观察这个函数的工作过程。s[0]是首字符,s[1:]是剩余字符串,将它们反向连接,可以得到反转字符串。执行这个程序,结果如下:递归的使用方法•这个错误表明系统无法执行reverse()函数创建的递归,这因为reverse()函数没有基例,递归层数超过了系统允许的最大递归深度。默认情况下,当递归调用到1000层,Python解释器将终止程序。•递归深度是为了防止无限递归错误而设计,当用户编写的正确递归程序需要超过1000层时,可以通过如下代码设定。递归的使用方法importsyssys.setrecursionlimit(2000)#2000是新的递归层数•reverse()超过递归深度是因为没有设计基例。字符串反转中的递归调用总是使用比之前更短的字符串,因此,可以把基例设计为字符串的最短形式,即空字符串。递归的使用方法实例5.2的完整代码和结果微实例5.2的结果请输入一个字符串:唐诗宋词词宋诗唐科赫曲线绘制•科赫曲线的基本概念和绘制方法如下:正整数n代表科赫曲线的阶数,表示生成科赫曲线过程的操作次数。科赫曲线初始化阶数为0,表示一个长度为L的直线。对于直线L,将其等分为三段,中间一段用边长为L/3的等边三角形的两个边替代,得到1阶科赫曲线,它包含四条线段。进一步对每条线段重复同样的操作后得到2阶科赫曲线。继续重复同样的操作n次可以得到n阶科赫曲线,如图5.14所示。科赫曲线绘制科赫曲线绘制•科赫曲线属于分形几何分支,它的绘制过程体现了递归思想,绘制过程代码如下科赫曲线绘制科赫曲线绘制•n阶科赫曲线的绘制相当于在画笔前进方向的0度、60度、-120度和60度分别绘制n-1阶曲线。实例代码8.1中main()函数设置了一些初始参数,如果希望控制绘制科赫曲线的速度,可以采用turtle.speed()函数增加或减少速度。•科赫曲线从一条直线绘制开始,如果从等边三角形开始将更有趣。替换实例代码8.1中的main()函数,代码如下。在给定初始图形后,通过科赫曲线可以生成很多漂亮的图形,请读者探索和尝试。科赫曲线绘制科赫曲线绘制Python内置函数•Python解释器提供了68个内置函数,这些函数不需要引用库直接使用,如表5.4所示。其中,前36个已经或将在本书中出现,需要读者掌握。Python内置函数Python内置函数abs()id()round()all()input()set()any()int()sorted()asci()len()str()bin()list(
本文标题:Python电子教案5-2-函数和代码复用
链接地址:https://www.777doc.com/doc-869807 .html