Python 基础 -- 文件和异常

  • 学习处理文件,能让程序快读地分析大量的数据;
  • 学习处理错误,避免程序在面对意外情形时崩溃;
  • 学习异常:可以管理程序运行时出现的错误;
  • 学习模块 json:保存用户数据,避免程序停止运行后丢失数据;

1. 从文件中读取数据

  • 要使用文本文件中的信息,首先需要将信息读取到内存中;
  • 读取方式:
    • 一次性读取全部内容;
    • 每次一行的方式逐步读取;

1.1 读取整个文件

  • 要读取文件,需要一个包含几行文本的文件;

  • 首先创建一个文件,包含精确到小数点后 30 位的圆周率值,且在小数点后每 10 位都换行:

    3.1415926535
      8979323846
      2643383279
    
  • 编写 file_reader.py 读取,并打印文件:

    with open(pi_digits.txt) as file_object:
    	contents = file_object.read()
    	print(contents)
    
    • 第 1 行 open() 函数,是打开文件的一个内置函数,需要传递一个文件名称参数,这个文件名称是你要打开的文件的名称;

    • Python 在当前执行的文件所在的目录中查找指定的文件;

    • 函数 open 返回的是一个表示文件的对象;

    • Python 将对象存储在变量 file_object 中;

    • 在这个程序中调用了 open() 函数,但是没有调用 close() 函数关闭文件;

    • 也可以调用 close() 函数,但是当程序存在 bug 时,导致 close() 语句未执行,文件将不会关闭,这个看起来微不足道,但是未妥善地关闭文件可能导致数据丢失或受损;

    • 如果在程序中过早的调用 close(),会发现需要使用文件时它已经关闭,这会导致更多的错误;

    • 一般情况下,Python 自己会在合适的时候将其自动关闭;

    • 第 2 行, read() 方法读取这个文件的全部内容,并将其作为一个字符串存储在变量 contents 中;

    • 第 3 行,打印文本文件;

      3.1415926535
        8979323846
        2643383279
      
      
      
      ------------------
      (program exited with code: 0)
      Press return to continue
      
    • 在第 6 行,多出来一行空行,是因为 read() 到文件末尾时返回一个空字符串,而这个空字符串显示出来时就是一个空行;

    • 要删除末尾的空行,可以使用 strip() 函数:

      with open((pi_digits.txt) as file_object:
      	contents = file_object.read()
      	print(contents.rstrip())
      

      结果:

      3.1415926535
        8979323846
        2643383279
      
      
      ------------------
      (program exited with code: 0)
      Press return to continue
      

1.2 文件路径

  • 简单的文件名传递给函数 open() 时,Python 将在当前执行的文件所在的目录查找文件;

  • 要让 Python 打开不与程序文件位于同一目录中的文件,需要提供文件路径,Python 会到系统特定的位置寻找;

  • 相对路径:指的是文件相对于当前工作目录所在的位置;

    • 例如,当前的程序 file_reader.py 所在的目录为:/home/sudong/python_work/day09/;而文件 pi_digits.txt 就位于这个文件夹下,所以 pi_digits.txt 的相对路径可以表示为:/pi_digits.txt
  • 绝对路径:从跟文件夹开始,一直到当前文件名;

    • pi_digits.txt 的绝对路径可以表示为:/home/sudong/python_work/day09/pi_digits.txt
  • 在 Linux 中,文件路径中使用斜杆 /

  • 在 Windows 中,文件路径中使用反斜杠 \

    # 绝对路径
    file_path = '/home/sudong/python_work/day09/pi_digits.txt'
    # 相对路径 file_path = 'pi_digits.txt'
    
    
    with open(file_path) as file_object:
    	contents = file_object.read()
    	print(contents.strip())
    

1.3 逐行读取

  • 当需要在文件中查找特定的信息,或者要以某种方式修改文件中的文本时,需要检查文本中的每一行;

  • 要以每次一行的方式检查文件,可以对文件对象使用 for 循环;

    file_path = '/home/sudong/python_work/day09/pi_digits.txt'
    
    # 逐行读取
    with open(file_path) as file_object:
    	for line in file_object:
    		print(line.rstrip())
    
  • 结果:

    3.1415926535
      8979323846
      2643383279
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

1.4 创建一个包含文件各行内容的列表

  • 使用 readlines() 从文件中读取每一行,并将其存储在一个列表中;

  • 然后再 with 代码模块外,使用 for 循环遍历字符串;

    file_path = '/home/sudong/python_work/day09/pi_digits.txt'
    
    # 创建一个包含文件各行内容的列表
    with open(file_path) as file_object:
    	lines = file_object.readlines()
    
    for line in lines:
    	print(line.rstrip())
    
  • 结果:

    3.1415926535
      8979323846
      2643383279
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

1.5 使用文件的内容

  • 读取文本文件时,Python 将其中的所有文本都解读为字符串;

    file_path = '/home/sudong/python_work/day09/pi_digits.txt'
    
    # 使用文件的内容
    with open(file_path) as file_object:
    	lines = file_object.readlines()
    
    pi_string = ''
    for line in lines:
    	pi_string += line.strip()
    
    print(pi_string)
    print(len(pi_string))
    
    • 读取操作与之前相同;
    • 在第 7 行创建一个变量 pi_string,用于存储圆周率的值;
    • 使用 for 循环将各行都加入到 pi_string 中,并删除前后的空格;
    • 输出打印;
  • 结果:

    3.141592653589793238462643383279
    32
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    
  • 如果需要将读取的数字作为数值使用,则必须使用函数 int() 或者 float()

1.6 包含 100 万的大型文件

  • 包含 100 万数据的文件,操作和三行的一样,只需要将这个包含 100 万数据的文件传输给程序即可;

    file_name = '/home/sudong/python_work/day09/pi_million_digits.txt'
    
    # 输出一百万位的大文件
    with open(file_name) as file_object:
    	lines = file_object.readlines()
    
    pi_string = ''
    for line in lines:
    	pi_string += line.strip()
    
    print(pi_string[:100] + "...")
    print(len(pi_string))
    
  • 当然这个只输出了前 100 位:

    3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706...
    1000002
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

1.7 圆周率是否包含生日

  • 可将生日表示为一个由数字组成的字符串,在检查这个字符串是否包含在 pi_string 中;

    file_name = '/home/sudong/python_work/day09/pi_million_digits.txt'
    
    # 你的生日是否包含再圆周率值中
    with open(file_name) as file_object:
    	lines = file_object.readlines()
    
    pi_string = ''
    for line in lines:
    	pi_string += line.strip()
    
    msg = "Enter your birthday, in the form mm-dd-yy: "
    birthday = input(msg)
    if birthday in pi_string:
    	msg = "Your birthday appears in the first million digits of pi!"
    	print(msg)
    else:
    	msg = "Your birthday does not appear in the first million digits of pi."
    	print(msg)	
    
  • 结果:

    Enter your birthday, in the form mm-dd-yy: 960512
    Your birthday does not appear in the first million digits of pi.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

1.8 练习

1. Python 学习笔记

  • 在文本编辑器中新建一个文件,写几句话来总结一下你至此学到的 Python 知识,其中每一行都以 "In Python you can"打头;

  • 将这个文件命名为 learning_python.txt,并将其存储到为完成本章练习而编写的程序所在的目录中;

  • 编写一个程序,它读取这个文件,并将你所写的内容打印三次:

  • 第一次打印时读取整个文件;

  • 第二次打印时遍历文件对象;

  • 第三次打印时将各行存储在一个列表中,再在 with 代码块外打印他们;

    In python you can blabla1
    In python you can blabla2
    In python you can blabla3
    In python you can blabla4
    In python you can blabla5
    

    file_name = 'learning_python.txt'
    
    # 读取整个文件
    with open(file_name) as file_object:
    	contents = file_object.read()
    	print(contents)
    
    # 遍历文件对象
    with open(file_name) as file_object:
    	for line in file_object:
    		print(line.strip())
    
    # 存入列表并打印
    
    with open(file_name) as file_object:
    	lines = file_object.readlines()
    
    for line in lines:
    	print(line.strip())
    

    In python you can blabla1
    In python you can blabla2
    In python you can blabla3
    In python you can blabla4
    In python you can blabla5
    
    
    In python you can blabla1
    In python you can blabla2
    In python you can blabla3
    In python you can blabla4
    In python you can blabla5
    
    In python you can blabla1
    In python you can blabla2
    In python you can blabla3
    In python you can blabla4
    In python you can blabla5
    
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

2. C 语言学习笔记

  • 可使用方法 replace() 将字符串中的特定单词都替换为另一给单词;

  • 下面是一个简单的示例,演示了如何将句子中的 dog 替换为 cat;

    message = "I really like dogs."
    message = message.replace('dog', 'cat')
    
  • 读取你刚创建的文件 learning_python.txt 中的每一行,将其中的 Python 都替换成 C 语言;

  • 将修改后的各行都打印到屏幕上;

    file_name = 'learning_python.txt'
    
    with open(file_name) as file_object:
    	lines = file_object.readlines()
    	
    for line in lines:
    	line = line.replace('python', 'C')
    	print(line.strip())
    

    In C you can blabla1
    In C you can blabla2
    In C you can blabla3
    In C you can blabla4
    In C you can blabla5
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

2. 写入文件

  • 保存数据最简单的方式之一就是将其写入到文件中;
  • open() 函数,提供的另一个参数可以将消息存入文件中;
    • open(filename, [para])
    • parar:表示,读取模式
    • paraw:表示,写入模式
      • 当以写入模式打开文件时,如果之前文件已经存在,则会将原文件覆盖;
    • paraa:表示,附加模式
      • 当以附加模式打开文件时,Python 会将写入的行添加到文件末尾,不会覆盖文件;
    • parar+:表示,读取和写入模式
    • 如果该参数被省略,将默认为读取模式;

2.1 写入空文件

  • 使用写入模式,将消息存储到文件中;

    file_name = 'programming.txt'
    
    with open(file_name, 'w') as file_object:
    	file_object.write("I love programming")
    
    • 使用写入模式将消息写入文件中,如果文件之前不存在,将会被创建;
    • Python 只能将字符串写入文本文件,若需要将数值存储到文本文件中,必须先使用函数 str() 将之转换为字符串格式;
  • 结果:

    I love programming
    

2.2 写入多行

  • 函数 write() 不会在你写入的文本末尾添加换行符;

  • 需要自己指定换行符;

  • 如果不添加换行符:

    file_name = 'programming.txt'
    
    with open(file_name, 'w') as file_object:
    	file_object.write("I love programming.")
    	file_object.write("I love creating new games.")
    

    I love programming.I love creating new games.
    
  • 添加换行符:

    file_name = 'programming.txt'
    
    with open(file_name, 'w') as file_object:
    	file_object.write("I love programming.\n")
    	file_object.write("I love creating new games.\n")
    

    I love programming.
    I love creating new games.
    

2.3 附加到文件

  • 如果需要给文件添加内容,而不是覆盖原有的内容,可以使用附加模式

  • w 换成 a,在刚才的基础上,重新编译程序:

    file_name = 'programming.txt'
    
    with open(file_name, 'a') as file_object:
    	file_object.write("I love programming.\n")
    	file_object.write("I love creating new games.\n")
    

    I love programming.
    I love creating new games.
    I love programming.
    I love creating new games.
    

2.4 练习

1. 访客

  • 编写一个程序,提示用户输入其名字;

  • 用户作出响应后,将其名字写入到文件 guest.txt 中;

    msg = "Please input your name: "
    user_input = input(msg)
    
    file_name = 'guest.txt'
    with open(file_name, 'w') as file_object:
    	file_object.write(user_input)
    

    lili
    

2. 访客名单

  • 编写一个 while 循环,提示用户输入其名字;

  • 用户输入其名字之后,在屏幕打印一句问候语,并将一条访问记录添加到文件 guest_book.txt 中;

  • 确保这个文件中的每条记录都独占一行;

    # 用来录入宾客姓名
    active = True
    while active:
    	# 提示输入姓名
    	msg = "\nPlease input your name : "
    	user_input = input(msg)
    	
    	# 问候语
    	msg = "Hello, " + user_input.title() + ". Welcom to come!"
    	print(msg)
    	
    	# 将名字添加到 guest_book.txt 中
    	file_name = 'guest_book.txt'
    	with open(file_name, 'a') as file_object:
    		msg = "User : " + user_input.title() + "\n"
    		file_object.write(msg)
    		
    	# 用来判断是否需要继续输入名单
    	while True:
    		msg = "Are there any more guests?(yes/no)"
    		print(msg)
    		msg_judgment = input()
    		if msg_judgment == 'yes':
    			active = True
    			break
    		elif msg_judgment == 'no':
    			msg = "All guests have arrived!"
    			print(msg)
    			active = False
    			break
    		else:
    			msg = "Input errors, please re-enter."
    			print(msg)
    			continue
    

    User : Mieba
    User : Alice
    User : Pan Gu
    

3. 关于编程的调查

  • 编写一个 while 循环,询问用户为何喜欢编程;

  • 每当用户输入一个原因后, 都将其添加到存储所有原因的文件中。

    active = True
    while active:
    	
    	msg = "- Why do you like programming?\n"
    	msg_ask = input(msg)
    	
    	file_name = 'reason_for_program.txt'
    	with open(file_name, 'a') as file_object:
    		msg_reason = "- " + msg_ask + ".\n"
    		file_object.write(msg_reason)
    	
    	while True:
    		msg = "- Is there any other reason?(yes/no)"
    		msg_ask = input(msg)
    		
    		if msg_ask == 'yes':
    			active = True
    			break
    		elif msg_ask == 'no':
    			msg_prompt = "Inquiry finished!"
    			print(msg_prompt)
    			active = False
    			break
    		else:
    			msg = "Input errors, please re-enter."
    			print(msg)
    			continue
    

    - because i like.
    - because i want.
    - because balabala.
    

3. 异常

  • Python 使用被称为异常的特殊对象来管理程序执行期间发生的错误;
  • 每当发生一个让 Python 不知所措的错误时,它都会创建一个异常对象;
  • 如果编写了处理该异常的代码,程序将继续运行;
  • 如果未对异常进行处理,程序将停止,并显示一个 traceback ,其中包含有关异常的报告;
  • 异常是用 try-except-else 代码块处理的;
  • try-except-else 代码块让 Python 执行指定的操作,同时告诉 Python 发生异常时怎么处理;
  • 使用了 try-except-else 代码块,即使出现异常,程序也能继续运行;
  • Python 尝试执行 try 代码块中的代码,只有可能引发异常的代码才需要放在 try 语句中;
  • 有时候,有一些仅在 try 代码块执行成功时才需要运行的代码,会放在 else 代码块中;
  • except 告诉 Python 如果 try 中代码发生指定的异常,该怎么处理;

3.1 处理 ZeroDivisionError 异常

  • ZeroDivisionError 异常是指除数为 0 而导致程序错误;

    print(3/0)
    
  • 显然,这样是错误的,将会在终端返回一个 Traceback

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: division by zero
    

3.2 使用 try-except 代码块

  • 使用 try-except 代码块处理发生的异常,可以返回友好的信息,而不是返回一个 Traceback

    try:
        print(3/0)
    except ZeroDivisionError:
        msg = "You can't divide by zero!"
        print(msg)
    

    You can't divide by zero!
    
  • 如果 try-except 代码块后面还有其他代码,程序将接着运行;

  • 因为 Python 已经处理了这种错误;

3.3 使用异常避免崩溃

  • 发生错误时,如果程序还有工作没有完成,妥善的处理错误就尤为重要;

  • 下面创建一个只执行除法运算的简单计算器:

    msg = "Give me two numbers, and I'll divide them.(Enter 'q' to quit)"
    print(msg)
    
    while True:
    	first_number = input("\nFirst number: ")
    	if first_number == 'q':
    		break
    	second_number = input("Second number: ")
    	if second_number == 'q':
    		break
    		
    	answer = int(first_number) / int(second_number)
    	print(answer)
    

    Give me two numbers, and I'll divide them.(Enter 'q' to quit)
    
    First number: 5
    Second number: 0
    Traceback (most recent call last):
      File "division.py", line 12, in <module>
        answer = int(first_number) / int(second_number)
    ZeroDivisionError: division by zero
    
    
    ------------------
    (program exited with code: 1)
    Press return to continue
    
    • 当除数为 0 时,程序将会崩溃;
  • 通过将可能引发错误的代码放在 try-except-else 代码块中,可提高程序抵御错误的能力;

  • 错误是执行除法运算的代码导致的,因此需要将它放到 try-except 代码块中;

  • 依赖于 try 代码块成功执行的代码都应放到 else 代码块中:

    msg = "Give me two numbers, and I'll divide them.(Enter 'q' to quit)"
    print(msg)
    
    while True:
    	first_number = input("\nFirst number: ")
    	if first_number == 'q':
    		break
    	second_number = input("Second number: ")
    	if second_number == 'q':
    		break
    	
    	try:
    		answer = int(first_number) / int(second_number)
    	except ZeroDivisionError:
    		msg = "You can't divide by 0!"
    		print(msg)
    	else:
    		print(answer)
    

    Give me two numbers, and I'll divide them.(Enter 'q' to quit)
    
    First number: 5
    Second number: 0
    You can't divide by 0!
    
    First number: 3
    Second number: 2
    1.5
    
    First number: q
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

3.4 处理 FileNotFoundError 异常

  • FileNotFoundError 这是一种找不到文件的异常;

    file_name = 'alice.txt'
    
    with open(file_name) as file_object:
    	contents = file_object.read()
    

    Traceback (most recent call last):
      File "alice.py", line 3, in <module>
        with open(file_name) as file_object:
    FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
    
    
    ------------------
    (program exited with code: 1)
    Press return to continue
    
    • traceback 中,第 4 行报告了 FileNotFoundError 异常,这是 Python 找不到要打开文件时返回的异常;
  • 使用 try-except 处理异常:

    file_name = 'alice.txt'
    
    try:
    	with open(file_name) as file_object:
    		contents = file_object.read()
    except FileNotFoundError:
    	msg = "Sorry, the file " + file_name + " does not exit."
    	print(msg)
    

    Sorry, the file alice.txt does not exit.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

3.5 分析文本

  • split() 函数以空格为分隔符将字符串拆分成多个部分,并将这些部分都存储到一个列表中;

    >>> title = "Alice in Wonderland"
    >>> title.split()
    ['Alice', 'in', 'Wonderland']
    
  • 可以使用 split() 方法将整篇小说拆分,在计算得到的列表包含多少个元素,从而确定整篇童话的单词数:

    file_name = 'alice.txt'
    
    try:
    	with open(file_name) as file_object:
    		contents = file_object.read()
    except FileNotFoundError:
    	msg = "Sorry, the file " + file_name + " does not exit."
    	print(msg)
    
    else:
    	words = contents.split()
    	num_words = len(words)
    	msg = "The file " +  file_name + " has about " + str(num_words) + " words."
    	print(msg)
    

    The file alice.txt has about 29461 words.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

3.6 使用多个文本

  • 当分析的文本比较多时,先将这个程序的大部分代码移动到一个名为 count_words() 的函数中;

    def count_words(file_name):
    	"""计算一本书大致包含多少个单词"""
    	try:
    		with open(file_name) as file_object:
    			contents = file_object.read()
    	except FileNotFoundError:
    		msg = "Sorry, the file " + file_name + " does not exit."
    		print(msg)
    
    	else:
    		words = contents.split()
    		num_words = len(words)
    		msg = "The file " +  file_name + " has about " + str(num_words) + " words."
    		print(msg)
    		
    file_name = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
    for f_name in file_name:
    	count_words(f_name)
    

    The file alice.txt has about 29461 words.
    The file siddhartha.txt has about 42172 words.
    Sorry, the file moby_dick.txt does not exit.
    The file little_women.txt has about 189079 words.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

3.7 对异常处理为视而不见

  • Python 有一个 pass 语句,可以在代码中使用它来让 Python 什么都不做:

    def count_words(file_name):
    	"""计算一本书大致包含多少个单词"""
    	try:
    		with open(file_name) as file_object:
    			contents = file_object.read()
    	except FileNotFoundError:
    		pass
    
    	else:
    		words = contents.split()
    		num_words = len(words)
    		msg = "The file " +  file_name + " has about " + str(num_words) + " words."
    		print(msg)
    		
    file_name = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
    for f_name in file_name:
    	count_words(f_name)
    

    The file alice.txt has about 29461 words.
    The file siddhartha.txt has about 42172 words.
    The file little_women.txt has about 189079 words.
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

3.8 决定报告哪些错误

  • 如果用户知道要分析哪些文件,他们可能希望在有文件没有分析时出现一条消息,将其中的原因告诉他们;
  • 如果用户只想看到结果,而并不知道要分析哪些文件,可能就不用告诉哪些文件不存在;

4. 存储数据

  • 用户关闭程序时,需要保存他们所提供的信息;
  • 最简单的方式是使用模块 json 来存储数据;
  • 模块 json 可以将简单的 Python 数据结构转存到文件中,并在程序再次运行时加载该文件中的数据 ;
  • JSON(JavaScript Object Notation) 格式最初是为 JavaScript 开发的,但是后来成了一种常见的格式,被包括 Python 在内的众多语言采用;

4.1 使用 json.dump() 和 json.load()

  • json.dump() 可以存储数据;

    • 需要接受两个实参:存储的数据存储数据的文件对象
  • json.load() 可以读取数据;

  • 编写一个使用 json.dump() 函数存储一组数据的简单程序;

    import json
    
    numbers = [2, 3, 4, 5, 7, 13]
    
    file_name = 'number.json'
    with open(file_name, 'w') as file_object:
    	json.dump(numbers, file_object)
    
    • 第 1 行,先导入模块 json
    • 第 3 行,创建一个数字列表;
    • 第 5 行,指定将数字列表存储到其中的文件的名称;
    • 通常使用文件扩展名 .json 来指出文件存储数据为 JSON 格式;
    • 第 6 行,以写入模式打开这个文件;
    • 第 7 行,使用 json.dump() 方法将数字列表存储到文件 number.json 中;
  • 再编写一个程序,使用 json.load()number.json 中的文件读取到内存中;

    import json
    
    file_name = 'number.json'
    
    with open(file_name) as file_object:
    	numbers = json.load(file_object)
    
    print(numbers)
    
    • 第 1 行,先导入模块 json
    • 第 3 行,确保读取的是前面写入的文件;
    • 第 5 行,以读取方式打开文件;
    • 第 6 行,使用 json.load() 加载存储在 number.json 中的信息,并将其存储到 numbers 变量中;
    [2, 3, 4, 5, 7, 13]
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    

4.2 保存和读取用户生成的数据

  • 对于用户生成的数据,使用 json 保存它们大有裨益;

  • 如果不以某种方式进行存储,等程序停止运行时用户的信息将丢失;

  • 假设,用户首次运行程序时被提示输入自己的名字,这样再次运行程序时就记住他了;

  • 存储用户的名字:

    import json
    
    username = input("What's your name? ")
    
    file_name = 'username.json'
    with open(file_name, 'w') as f_obj:
    	json.dump(username, f_obj)
    	msg = "We'll remember you when you come back, " + username + "!"
    	print(msg)
    
    • 第 3 行,提示用户输入用户名,并将其存储在变量中;
    • 第 7 行,使用 json.dump() 函数,将用户名和一个文件对象传递给他,从而将用户名存储到文件中;
    What's your name? Eric
    We'll remember you when you come back, Eric!
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    
  • 编写一个向被存储用户发出问候的程序;

    import json
    
    file_name = 'username.json'
    
    with open(file_name) as f_obj:
    	username = json.load(f_obj)
    	msg = "Welcome back, " + username + "!"
        print(msg)
    

    Welcome back, Eric!
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    
  • 将两个程序合并在一起;

  • 在程序运行时,将尝试从文件 username.json 中获取用户名;

  • 因此,需要先编写一个尝试恢复用户名的 try 代码块;

  • 如果这个文件不存在,就在 except 代码块中提示用户输入用户名,并将其存储在 username.jsom 中,以便程序再次运行时能够获取它;

    import json
    
    file_name = 'username.json'
    
    try:
    	with open(file_name) as f_obj:
    		username = json.load(f_obj)
    except FileNotFoundError:
    	username = input("What's your name? ")
    	with open(file_name, 'w') as f_obj:
    		json.dump(username, f_obj)
    		msg = "We'll remember you when you come back, " + username + "!"
    		print(msg)
    else:
    	msg = "Welcome back, " + username + "!"
    	print(msg)
    
    • 这个程序没有任何新的代码,只是将前两个示例的代码进行了合并;

    • 第 6 行,我们尝试打开文件 username.json

    • 如果文件存在,就将其中的用户名读取到内存中,再执行 else 代码块;

    • 用户首次运行程序时,文件 username.json 不存在,将引发 FileNotFoundError 异常,进入第 8 行;

    • 然后使用 json.dump() 进行存储;

      Welcome back, Eric!
      
      
      ------------------
      (program exited with code: 0)
      Press return to continue
      

      删除之前存储信息,现在没有 username.json 文件:

      What's your name? Eric
      We'll remember you when you come back, Eric!
      
      
      ------------------
      (program exited with code: 0)
      Press return to continue
      

4.3 重构

  • 代码可以正确运行,但是需要进一步改进;

  • 将代码划分为一系列完成具体工作的函数;

  • 这样的过程称为重构

  • 重构让代码更清晰、更易于理解、更容易扩展;

  • 重构上述代码,可将大部分逻辑放在多个函数中;

    import json
    
    def get_sorted_username():
    	"""如果用户存储了用户名,就获取它"""
    	file_name = 'username.json'
    	try:
    		with open(file_name) as f_obj:
    			username = json.load(f_obj)
    	except FileNotFoundError:
    		return None
    	else:
    		return username
    
    def get_new_username():
    	"""提示用户输入用户名"""
    	username = input("What's your name? ")
    	file_name = 'username.json'
    	with open(file_name, 'w') as f_obj:
    		json.dump(username, f_obj)	
    	return username
    
    
    def greet_user():
    	"""问候用户,并指出其名字"""
    	username = get_sorted_username()
    	if username:
    		msg = "Welcome back, " + username + "!"
    		print(msg)	
    	else:
    		username = get_new_username()
    		msg = "We'll remember you when you come back, " + username + "!"
    		print(msg)	
    				
    greet_user()	
    

    Welcome back, Eric!
    
    
    ------------------
    (program exited with code: 0)
    Press return to continue
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值