ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 4.3.3 第三层设计 首先考虑函数 leapyears 的实现,该函数的功能是计算从 1900 到 year(不含)之间 的闰年个数。这可以用逐年检验的方法来实现①:对从 1900 到 year-1 的每一年,测试该 年是否闰年,如果是则为计数变量 count 加 1。于是得到如下代码: ``` def leapyears(year): count = 0 for y in range(1900,year): if y%4 == 0 and (y%100 != 0 or y%400 == 0): count = count + 1 return count ``` 其中 if 语句的布尔表达式是根据闰年的规定得到的:年份能被 4 整除并且不能被 100 整除(除非该年能被 400 整除)。 再考虑函数 heading 的实现,该函数用于打印每个月日历的标题部分(月份和星期名 称)。我们将月份名称放在一个列表中,然后通过传递给 heading 函数的月份值作为索引 来查找月份名称。代码如下: ``` def heading(m): months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"] print " %s " % (months[m]) print "Mon Tue Wed Thu Fri Sat Sun" ``` > ① 如果从公元 1 年算起,到 year 年为止的闰年个数可用公式 year/4 ? year/100 + year/400 计算。 第三层的最后一个函数是 oneMonth(),其功能是输出一个月的日历。由于日历输出要求在合适的位置上显示合适的日期,这个用于输出的子程序反而是整个程序最费功夫的部 分。为了安排日历布局,需要了解每月 1 日是星期几和每月有多少天,还需要确定何时换行显示。我们采用一个长度为 6×7=42 的列表①作为日历布局框架(每行 7 天,一个月最多占用 6 行),只需将一个月的每一天存入这个框架的合适位置,然后输出这个列表即可。图4.9 是日历框架的示意图。 ![](https://box.kancloud.cn/2016-02-22_56cafcdf873be.png) 图 4.9 每个月的日历布局 由于问题有点复杂,我们再次分解任务,用三个子程序来实现 oneMonth():days() 函数计算该月份的天数,layout()函数用于布置该月每一天在日历框架中的位置 ,printMonth()用于输出日历。即: ``` def oneMonth(year,month,first): d = days(year,month) frame = layout(first,d) printMonth(frame) return (first + d) % 7 ``` oneMonth 函数有三个参数:year 表示年份,month 表示月份,first 表示该月 1 日是星期几(0~6)。对于一月份,first 由上层模块 printCalendar 的参数 w 提供; 对于其他月份,first 可由上一个月的 first 和天数确定,因此我们让 oneMonth 在打印 本月日历后返回下个月 1 日的星期序号。 > ① 使用二维列表或许会更直观。 设计至此,结构图演变为图 4.10 所示的情况。 ![](https://box.kancloud.cn/2016-02-22_56cafcdfc93b5.png) 图 4.10 calendar 程序的第三层结构图