python3

Head First Python 读书笔记(四)

2018-07-10  本文已影响2人  icessun

第六章:存储和管理数据

打开,处理,关闭文件
模式参数
with open('py.txt', 'w') as file_object:
    file_object.write('I love programming.')
with语句
tasks = open('todos.txt')
for ch in tasks:
    print(ch, end='')
tasks.close()

# 使用with语句
with open('todos.txt') as tasks:
    for ch in tasks:
        print(ch, end='')

使用了with语句,可以不用考虑调用close()方法,充当着管理上下文的作用。符合上下文管理协议的约定。

print(file_object)

# 读取的文件名称  模式为:read  编码为 cp936 GBK编码
<_io.TextIOWrapper name='py.txt' mode='r' encoding='cp936'>
with open('py.txt') as file_object:
    contents = file_object.read()
    print(contents)

print(file_object.read())
with语句外,访问文件流对象
with open('py.txt') as file_object:
    lines = file_object.readlines()   # readlines() 返回一个列表
    print(type(lines))  # list

for line in lines:
    print(line.rstrip()) # 清除右边空格
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as file_object:
    json.dump(numbers, file_object)    # 以原有的格式保存数据
import json
filename = 'numbers.json'
with open(filename) as file_object:
    numbers = json.load(file_object)

print(numbers)   # 读取原有的格式数据

这是一种程序之间共享数据的方法

import json

filename = 'username.json'
try:
    with open(filename) as file_object:      # 如果文件存在就读取到内存里面
        username = json.load(file_object)
except FileNotFoundError:                 #  否则就等待用户的输入,创建文件
    username = input('What is your name?')
    with open(filename, 'w') as file_object:
        json.dump(username, file_object)
        print('we`ll remember you when you come back, '+username+'!')
else:
    print('welcome back,'+username+'!')     # 最后都会执行这条语句

上面的代码重构一下


import json

# 获取存储在username.json文件里面的姓名
def get_stored_username():
    filename = 'username.json'
    try:
        with open(filename) as file_object:
            username = json.load(file_object)
    except FileNotFoundError:
        return None
    else:
        return username

# 存入新名字到username.json
def get_new_username():
    username = input('what is your name?')
    filename = 'username.json'
    with open(filename, 'w') as file_object:
        json.dump(username, file_object)
    return username

# 问候用户
def greet_user():
    username = get_stored_username()
    if username:
        print('Welcome back, '+username+'!')
    else:
        username = get_new_username()
        print('we`ll remember you when you come back,'+username+'!')


greet_user()

日志记录

结合笔记三做的WEB应用,现在需要记录其web请求的详细信息和结果。

# req:是当前Flask请求对象  res:查询结果
def log_request(req: 'flask_request', res: str)->None:
    with open('vsearch.log', 'a') as log:
        print(req, res, file=log)
日志记录结果
@app.route('/viewlog')
def view_log()->str:
    with open('vsearch.log') as log:
        contents = log.read()  # 一次性读取整个文件
    return contents
网页访问结果
转义数据

根据上面的结果,发现:网页显示的和日志文件不一样;那是因为浏览器会自动把一些标记隐藏。可以使用escape函数去转义,对从日志文件读取出来的内容转义

>>> from flask import escape
>>> escape('this is a request')
Markup('this is a request')
>>> escape('this is a <html>')
Markup('this is a &lt;html&gt;')
@app.route('/viewlog')
def view_log()->str:
    with open('vsearch.log') as log:
        contents = log.read()
    return escape(contents)

就算在网页上面显示了web请求对象,但是目前来说,这些请求对象都是一样的,要查看请求对象的内部,可以使用dir内置方法,查看它的方法和属性列表。

def log_request(req: 'flask_request', res: str)->None:
    with open('vsearch.log', 'a') as log:
        print(str(dir(req)), res, file=log)
网页显示的详细web请求
记录特定的web请求属性

一般来说,有三个属性是日志记录比较重要的:

修改我们的日志记录函数:

def log_request(req: 'flask_request', res: str)->None:
    with open('vsearch.log', 'a') as log:
        print(req.form, file=log)
        print(req.remote_addr,  file=log)
        print(req.user_agent, file=log)
        print(res, file=log)

最后日志记录的结果是这样的:

ImmutableMultiDict([('phrase', 'this is my first python'), ('letters', 'aeiou')]) # 提交的数据
127.0.0.1 # ip地址
Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 # 浏览器版本
{'o', 'i'} # 查询结果

这样虽然记录了一次web请求的比较关键的信息,但是却要从日志文件里面读取4次,应该想能不能一次web请求,记录一行数据,然后读取一次呢?

def log_request(req: 'flask_request', res: str)->None:
    with open('vsearch.log', 'a') as log:
        print(req.form, file=log, end='|')
        print(req.remote_addr,  file=log, end='|')
        print(req.user_agent, file=log, end='|')
        print(res, file=log)
可读的输出
>>> names=['terry','john','michael']
>>> pythons = '|'.join(names)
>>> pythons
'terry|john|michael'

>>> s =pythons.split('|')       
>>> s       
['terry', 'john', 'michael']
# 列表的嵌套  contents  就数据读入嵌套列表里面
@app.route('/viewlog')
def view_log()->str:
    contents = []  # 空列表
    with open('vsearch.log') as log:
        for line in log:
            contents.append([])  # 追加一个新的空列表
            for item in line.split('|'):  # 根据 | 分解一行数据
                contents[-1].append(escape(item)) # 把分解的数据放在列表的末尾
    return str(contents)
# 希望再 the_row_titles  变量中查找数据
<tr>
 {% for row_title in the_row_titles %}
        <th>{{ row_title }}</th>
 {{% endfor %}}   # 循环结尾
</tr>

使用HTML的表格标记<table><tr><th><td>,格式化输出日志数据,接着修改view_log函数,使得其向浏览器返回一个html而不是字符串

@app.route('/viewlog')
def view_log()->'html':
    contents = []
    with open('vsearch.log') as log:
        for line in log:
            contents.append([])
            for item in line.split('|'):
                contents[-1].append(escape(item))
    titles=('Form Data','Remote_addr','User_agent','Results')
    return render_template('viewlog.html',the_title='View Log',the_row_titles=titles,the_data=contents,)

修改后的view_loghtml代码:

{% extends 'base.html' %} {% block body %}

<h2>{{ the_title }}</h2>

<table>
    <tr>
        {% for row_title in the_row_titles %}
        <th>{{ row_title }}</th>
        {% endfor %}
    </tr>
    {% for log_row in the_data %}
    <tr>
        {% for item in log_row %}
        <td>{{item}}</td>
        {% endfor %}
    </tr>
    {% endfor %}
</table>

{% endblock %}

格式化输出效果:


格式化输出
上一篇下一篇

猜你喜欢

热点阅读