用新知识解决旧问题

用新知识解决旧问题

在上一章节中,我们编写的程序还有很大的改进空间,在这一章节中,我们将逐一解决这些问题。

首先,之前的程序永远只会执行一次判断,如果用户输错了格式,也没有机会修正。我们应该要让程序不断的尝试获取输入,直到输入格式确实符合要求为止。我们在编写时并不知道何时输入值是合法的,这时就需要循环语句了。

循环语句

先来看一个最简单的 while 循环示例:

1
2
3
4
5
6
7
i = 1 # 初始化申明一个变量

while(i <= 3): # 当 i 的值小于等于 3 时
print("这是第 %d 次打印" % i)
i = i + 1 # 让 i 增加,如果没有这一句,将成为死循环

print("循环已完毕!")

程序的运行结果为:

1
2
3
4
这是第 1 次打印
这是第 2 次打印
这是第 3 次打印
循环已完毕!

为了便于理解 while 循环,我做了个图解:

利用循环语句,我们将之前的程序改写为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name = input("请输入你的姓名:")
age = input("请输入你的年龄:")

while not age.isdigit(): # 当 age 不为纯数字时
age = input("输入有误,请重新输入你的年龄:") # 重新获取 age 的值

age = int(age)

if name == "莉莉":
print("小姐里面请!")
elif age > 60:
print("大爷先回家歇歇吧!")
elif age == 40:
print("贡献您,今日消费全免,里面请!")
elif age >= 18: # 当 age 小于等于 60 并且 大于等于 18 时
print("欢迎您的到来,里面请!")
else: # 其余情况
print("小孩子回家玩去")

逻辑运算符

while not age.isdigit(): 语句表示当 age 不为纯数字时循环。

在编程语言中,通常用 ! 表示”否“,如用 != 表示“不等于”,相应的,上面的语句则要用 while (!age.isdigit()) 表示;而 Python 则支持用 not 关键字表示“否”,这非常直观并且人性化,同时体现了 Python 的优雅之处。

除了 not 外,Python 中还有“并”: and 、“或”: or,分别对应 &&||,这些被称为逻辑运算符。

经过循环语句后,我们可以确保 age 的值已为纯数字,可以放心的使用 int() 函数将其转换为整数类型;原本用于处理格式不正确的 else 语句也要去掉。

解决了上面的问题,我们再来看如何更严谨的确定年龄。

直接让用户输入年龄的形式并不合适,一种更好的方法是从身份证号中确定年龄。我们知道,身份证号由确定的格式组成,从身份证号中我们可以获取很多信息。具体来说,身份证号前六位表示地址,接下来的八位表示出生日期,再接下来三位为顺序码,最后一位为校验码。

身份证的最后一位是根据前 17 位通过校验算法计算出来的,改变原本的任何一位都会导致校验码不符。通过身份证号,我们就可以较严谨的确定年龄了。

程序处理时间和日期,可能会比大多数人想象的要复杂,为了降低学习的心智负担,这里我们会尽可能简化从身份证号中获取年龄的算法。

假定现在获取的身份证号为 510101200106180395,我们只提取 2001 这个年份,直接与当前的年份 2020 相减计算出年龄。

字符串截取

该如何获取 "510101200106180395" 中的字符呢,其实“字符串”顾名思义就是由“字符”连成的串,我们直接通过位次就可以获取到其中的字符

1
2
3
4
5
6
word = "hello"
print(word[0]) # h
print(word[1]) # e
print(word[2]) # l
print(word[3]) # l
print(word[4]) # o

没错,程序员就是从 0 开始数数的 😅

可以看到,上面的代码非常繁琐,而且假如需要提取 1000 位,难道还写 1000 行吗?这显然是不可能的,我们可以借助刚学的循环来完成:

1
2
3
4
5
word = "hello"
i = 0
while i < len(word):
print(word[i])
i += 1
  • len() 函数用于获取数据长度,len("hello") 的结果自然是 5
  • i += 1i = i + 1 的简写,二者等价。

那么,结合之前所学的条件语句,提取出生年份的代码就可以这样写:

1
2
3
4
5
6
7
id = "510101200106180395"
i = 0

while i < len(id):
if i in (6, 7, 8, 9): # 当 i 为 6, 7, 8, 9 中的任何一个时
print(id[i])
i += 1

if i in (6, 7, 8, 9): 语句用到了 Python 的一些高级特性,我们还没有学,没关系,光这么看就已经非常直观。它和下面的代码等价:

1
2
if i == 6 or i == 7 or i == 8 or i == 9:
pass # 表示忽略

高下立判, 再一次赞叹 Python 的简洁优雅 👏

能不能再简洁一点,更优雅一点?

Python 告诉你:还真能!

1
2
3
id = "510101200106180395"

print(id[6:10]) # 2001

id[6:10] 用到了 Python 的“切片”操作符,它可以用于截取字符串。为了便于理解,我又做了个图解:

现在,改写之前的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name = input("请输入你的姓名:")
id = input("请输入你的身份证号:")

while not id.isdigit() or len(id) != 18: # 当 id 不为纯数字时或不满 18 位时
id = input("输入有误,请重新输入身份证号:") # 重新获取 id 的值

birth_year = int(id[6:10])

age = 2020 - birth_year

if name == "莉莉":
print("小姐里面请!")
elif age > 60:
print("大爷先回家歇歇吧!")
elif age == 40:
print("恭喜您,今日消费全免,里面请!")
elif age >= 18: # 当 age 小于等于 60 并且 大于等于 18 时
print("欢迎您的到来,里面请!")
else: # 其余情况
print("小孩子回家玩去")
1
2
3
> 请输入你的姓名:王花花
> 请输入你的身份证号:510101200106180395
欢迎您的到来,里面请!

很好的实现了我们的需求 🥳

小结

不要忘了,我们将判断年龄的算法尽可能简化了,如果以后我们想让算法更完善,或是给程序添加更多的功能,就需要不断的在中间新插入代码,其中有实现我们业务逻辑的部分,也有具体算法实现的部分,相互耦合在一起,非常琐碎复杂。

管理和维护这样的代码,是我们不愿接受的,该如何解决这种问题呢?

将在下一章节中详细展开 😘