今天在编写注册功能函数时发现,注册成功的用户可以将数据以字典的形式轻松保存至文档,但却无法在 for 循环遍历之后通过 key 取值:
def register():
"""注册函数"""
user_id = input("请设置您的账号>>>: ")
with open('user_data.txt', 'rt', encoding='utf-8') as f:
data = f.read()
for j in data:
if j["id"] == user_id:
print("此用户已存在,换一个")
break
错误:
File "/Users/creambluea/PycharmProjects/ATM/core/111.py", line 8, in register
if j["id"] == user_id:
TypeError: string indices must be integers
原因是写入文档时用户信息数据虽然是字典格式,但在保存为文档之后,其格式转变为字符串格式,因此需要先转换为字典格式,但是由于各字典之间都是独立的,并不是键值对形式,因此不能直接使用 dict 转换格式。
有以下几种方式可以将字符串格式的字典还原为字典:
1.使用 json 模块
import json
user_info= '{"name" : "john", "gender" : "male", "age": 28}'
user_dict = json.loads(user_info)
user_dict >>> {u'gender': u'male', u'age': 28, u'name': u'john'}
但是 json 转换需要注意一个潜在问题: json 语法规定,数组或对象之中的字符串必须使用双引号,不能使用单引号
2.使用 eval 函数
usr_info = '{"name" : "john", "gender" : "male", "age": 28}'
user_dict = eval(user_info)
user_dict >>> {'gender': 'male', 'age': 28, 'name': 'john'}
user_info = "{'name' : 'john', 'gender' : 'male', 'age': 28}"
user_dict = eval(user_info)
user_dict >>> {'gender': 'male', 'age': 28, 'name': 'John'}
通过 eval 进行转换就不存在上面使用 json 进行转换的问题。但是eval虽然方便,但是要注意安全性,可以将字符串转成表达式并执行,就可以利用执行系统命令,删除文件等操作。
3.使用 ast 模块中的 literal_eval
import ast
user = '{"name" : "john", "gender" : "male", "age": 28}'
user_dict = ast.literal_eval(user)
user_dict >>> {'gender': 'male', 'age': 28, 'name': 'john'}
user_info = "{'name' : 'john', 'gender' : 'male', 'age': 28}"
user_dict = ast.literal_eval(user)
user_dict >>> {'gender': 'male', 'age': 28, 'name': 'John'}
使用 ast.literal_eval 进行转换既不存在使用 json 进行转换的问题,也不存在使用 eval 进行转换的 安全性问题。
但是单纯使用以上三种方法均只能转换单个字符串,若是文档中有多个字符串则会报错
Traceback (most recent call last):
File "/Users/creambluea/PycharmProjects/ATM/core/111.py", line 12, in <module>
register()
File "/Users/creambluea/PycharmProjects/ATM/core/111.py", line 5, in register
data = eval(f.read())
File "<string>", line 1
{'id': '1', 'password': '1'}{'id': '1', 'password': '1'}
SyntaxError: invalid syntax
因此,以 ast 模块为例,可以做如下处理
def register():
"""注册函数"""
user_id = input("请设置您的账号>>>: ")
with open('user_data.txt', 'rt', encoding='utf-8') as f:
data = [ast.literal_eval(i) for i in f]
for j in data:
if j["id"] == user_id:
print("此用户已存在,换一个")
break
通过列表生成式逐个转化即可避免语法错误