Python类和函数_规划式开发
一,规划式开发
原型+补丁模式,渐进式的开发也会产生过分复杂的代码——因为要应对很多特例情况,而且也不太靠靠——因为不好确定你是否找到了所有的错误。
另一种模式就是规划式开发,这种情况下对问题的深入透彻的理解就让开发容易很多了。
比如上节中的 Time 对象,实际上是一个三位的六十进制数字。秒数也就是个位,分数也就是六十位,小时数就是三千六百位。
如此,当我们写 add_time 和 increment 函数的时候,用60进制来进行计算就很有效率了。
这一观察表明,有另外一种方法来解决整个问题,即我们可以把 Time 对象转换成整数,然后因为计算机最擅长整数运算,这样就有优势了。
下面这个函数就把 Times(六十进制数字)转换成了整数:
>>> def time_to_int(time):
... minutes = time.hour * 60 + time.minute
... seconds = minutes * 60 + time.second
... return seconds
...
然后下面这个函数是反过来的,把整数转换成 Time(这里使用divmod函数,使用第一个数除以第二个数,返回的是除数和余数组成的元组。)
>>> def int_to_time(seconds):
... time = Time()
... minutes, time.second = divmod(seconds, 60)
... time.hour, time.minute = divmod(minutes, 60)
... return time
...
一旦你确定这些函数都没问题,就可以用它们来重写一下 add_time 这个函数了:
>>> def add_time(t1, t2):
... seconds = time_to_int(t1) + time_to_int(t2)
... return int_to_time(seconds)
...
在一定程度上,从六十进制到十进制的来回转换,远远比计算时间要麻烦的多。进制转换要更加抽象很多,而我们处理时间计算的直觉要更好些。
然而,如果我们规划性地开发,把时间值当做六十进制的数值来对待,然后写出一些转换函数(比如 time_to_int 和 int_to_time),就能让程序变得更短,可读性更好,调试更容易,也更加可靠。
二,调试
对于一个 Time 对象来说,只要分和秒的值在0-60的前闭后开区间(即可以为0但不可以为 60),并且小时数为正数,就是格式正确的。小时和分钟都应该是整数,但秒是可以为小数的。
像这些要求也叫约束条件,因为通常都得满足这些条件才行。反过来说,如果这些条件没满足,就有可能是程序中某处存在错误了。
写一些检测约束条件的代码,能够帮助找出这些错误,并且找到导致错误的原因。
例如,你可以写一个名字为 calid_time 的函数,接收一个 Time 对象,然后如果该对象不满足约束条件就返回 False:
if time.hour < 0 or time.minute < 0 or time.second < 0:
然后在每个自定义函数的开头部位,你就可以检测一下参数,来确保这些参数没有错误:
if not valid_time(t1) or not valid_time(t2):
或者也可以用一个 assert 语句,这个语句也是检测给定的约束条件的,如果出现错误就会抛出一个异常:
assert valid_time(t1) and valid_time(t2)
assert 语句是很有用的,它可以用来区分条件语句的用途,将 assert 这种用于检查错误的语句与常规的条件语句在代码上进行区分。
三,术语
原型和补丁模式: 一种开发模式,先写一个程序的草稿,然后测试,再改正发现的错误,这样逐步演化的开发模式。
设计规划开发: 这种开发模式要求对所面对问题的高程度的深刻理解,相比渐进式开发和原型增补模式要更具有计划性。
纯函数: 不修改参数对象的函数。这种函数多数是有返回值的函数。
修改器: 修改参数对象的函数。大多数这样的函数都是无返回值的,也就是返回的都是 None。
函数式编程模式: 一种程序设计模式,主要特征为大多数函数都是纯函数。
约束条件: 在程序运行过程中,应该一直为真的条件。
assert 语句: 一种检查错误的语句,检查一个条件,如果不满足就抛出异常。
结束。