Академический Документы
Профессиональный Документы
Культура Документы
-
$
!($((+!
!+
!+
1
+
!*
("
%
)
*3
3
%
! 2
*
!%&
0
0
"'
)
5
*
%)!
%
0
"
98!
:+
5
$0
.
%&,
*
5
(%!"
N( $ 279
1 #
«ȋȄȖȉȐȐȟ
ȆȟȋȟȆȄȉȐ©VHDUFKOHWWHUVª
ȌȓȉȔȉȈȄȉȐȓȒȏȗțȉȑȑȟȉ «ȌȓȒȕȏȉȡȖȒȇȒȐȟ
ȔȉȋȗȏȠȖȄȖȟȒȅȔȄȖȑȒ« ȓȔȒȕȖȒȆȟȅȔȄȕȟȆȄȉȐȆȕȉ
ȈȄȑȑȟȉ""ǰȟȈȒȏȊȑȟ
ǬȖȄȎ«ȏȢȅȒȍȆȉȅ șȒȖȣȅȟȆȉȕȖȌȊȗȔȑȄȏ
ȋȄȓȔȒȕȆȟȓȒȏȑȣȉȖȕȣ ȋȄȓȔȒȕȒȆȔȄȋȆȉȑȉȖ"
ȕȒȕȆȒȌȐȌȋȑȄțȉȑȌȣȐȌ
ȆȓȄȔȄȐȉȖȔȄș©SKUDVHª
Ȍ©OHWWHUVª«
280 z
0
{ ,
(
s$$$
! `o[
*
q
«open»
(
$
$s$
Теперь используем tasks в цикле for, чтобы прочитать каждую строку из файла
и присвоить ее переменной цикла (chore). В каждой итерации переменной
chore будет присваиваться очередная строка из файла. Когда файловый
поток используется с циклом for, интерпретатор Python берет на себя чтение
очередной строки из файла в каждой итерации. Кроме того, он самостоятельно
завершит цикл, достигнув конца файла.
282 z
0
{ ,
;
?
=>7
!,
#"#*+!"),+!",
!""+
a ,6 '#
#*
",
" %"#for
+#2,*4(
+2#
#
"
Первый аргумент функции open — имя файла для обработки. А второй аргумент можно опустить. В нем
можно передавать разные значения, определяющие режим открытия файла. В число режимов входят:
«чтение», «запись» и «добавление в конец». Вот наиболее часто встречающиеся значения режимов, каждое
из которых (кроме r) создает пустой файл, если файл с таким именем отсутствует:
‘r’ открыть файл для чтения. Это режим по умолчанию, поэтому аргумент с данным значением можно
опустить. Если в вызове функции open второй аргумент отсутствует, то подразумевается ‘r’. Также
подразумевается, что файл для чтения уже существует.
‘w’ открыть файл для записи. Если в файле уже есть данные, они удаляются.
‘a’ открыть файл для добавления в конец. Сохраняет содержимое файла, добавляя данные в конец файла
(сравните это поведение с режимом ‘w’).
‘x’ открыть новый файл для записи. Вызов завершается неудачей, если файл уже существует (сравните с ‘w’ и ‘a’).
По умолчанию файл открывается в текстовом режиме, когда подразумевается, что файл содержит строки
с текстовыми данными (например, ASCII или UTF-8). Если вы работаете с нетекстовыми данными (например,
с изображением или аудиофайлом MP3), нужно указать, что файл должен открываться в двоичном режиме,
добавив символ ‘b’ к любому из режимов, перечисленных выше (например, ‘wb’ означает «режим запи-
си двоичных данных»). Если вы добавите символ ‘+’ во второй аргумент, файл будет открыт в режиме для
чтения и записи (например, ‘x+b’ означает «читать и записывать в новый двоичный файл»). Чтобы узнать
больше о работе open (и других опциональных аргументах), обращайтесь к документации по Python.
ȃȓȒȕȐȒȖȔȉȏȓȔȒȉȎȖȟ
ȆȔȉȓȒȋȌȖȒȔȌȌ*LW+XEǦȅȒȏȠȜȌȑȕȖȆȉ
ȌȋȑȌșȓȔȌȒȖȎȔȟȖȌȌȘȄȍȏȒȆȌȕȓȒȏȠȋȗȉȖȕȣ
ȆȟȔȄȊȉȑȌȉ©ZLWKªǻȖȒȡȖȒȋȑȄțȌȖ"
! `oh
=88B|ST
tasks = open('todos.txt')
(
for chore in tasks: q
print(chore, end='')
(
tasks.close()
$
w(
$
with open('todos.txt') as tasks:
(
for chore in tasks: q
print(chore, end='') (s
)
284 z
0
{ ,
3*1
I
8
9. 9 .'%#
>
$8D
Упражнение
>$ F
I $F.
>>
> 9@
from flask import Flask, render_template, request
from vsearch import search4letters
@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
if __name__ == '__main__':
app.run(debug=True)
! `oZ
#
.:FLN(:=µ:=<jFG=¬GC)
#
«
FN/»
«¥<=;:K/
log»$ q w«CL=»
$%
( «print» (
s$ ( $
«:=µ»
v$
«res»(
$«log»
286 z
0
{ ,
Краткий обзор
Прежде чем продолжить работу с последней версией vsearch4web.
py, приведите свой код в точное соответствие с нашим. Ниже показано
содержимое файла, в котором выделены последние изменения.
app = Flask(__name__)
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
$
phrase = request.form['phrase']
v
letters = request.form['letters']
title = 'Here are your results:'
*
results = str(search4letters(phrase, letters))
(
log_request(request, results) «¥<=;:K/GC»
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
if __name__ == '__main__':
app.run(debug=True)
q$$
Запуск веб-приложения (
*
Запустим эту версию веб-приложения (если необходимо) в командной $$
строке. В Windows выполните эту команду:
v
$
(
C:\webapps> py -3 vsearch4web.py $ $
В Linux или Mac OS X выполните эту команду: s
)
$ python3 vsearch4web.py $%
*
После запуска приложения попробуем сохранить в журнал данные $$
из HTML-формы.
! `oa
,
¢ÃÁ´À³ÒÂÁ¸º·½³
9.8D8..
9 jp-<D'
>
Q#
9
.
>
9.6F#.%phraseletters@
hitch-hikergM aeiou
galaxygM xyz
q
288 z
0
{ ,
x
(
)
!
(
v
$
y(
«
=X;..» «¥<=;:K/GC»
Заманчиво воспользоваться
спользоваться текстовым редактором, чтобы заглянуть
в файл vsearch.log. Но что здесь интересного? Мы пишем веб-
приложение, поэтому давайте организуем доступ к данным в журнале
через само приложение. Тогда нам не придется покидать веб-браузер,
чтобы посмотреть данные приложения. Итак, создадим новый URL /
viewlog, отображающий содержимое журнала.
! `oV
:;
URL
файла используем инструкцию with.
with open('vsearch.log') as log:
@app.route('/viewlog')
q def view_the_log() -> str:
$
with open('vsearch.log') as log:
^«H contents = log.read()
¥F=
GC» return contents
290 z
0
{ ,
¢ÃÁ´À³ÒÂÁ¸º·½³
I8$#8D
>>
.
9
> 99.
# >>
# '2.
# 9 2.
.
8 82'%
9.hi</viewlog 8
9
#9
8 % 8.http://127.0.0.1:5000/viewlog.
?@A B3 >
9.FirefoxChrome
4
%>.9 4
*$
$ $
(
~~
~
! `V[
L
,
Чтобы понять, почему данные о запросе не выводятся на экран, нужно знать, как
браузеры интерпретируют разметку HTML, и тот факт, что Firefox выделил данные
запроса красным, помогает понять произошедшее. Оказывается, с данными ничего
не произошло. Но угловые скобки (< и >) вводят браузер в заблуждение. Когда
встречается открывающая угловая скобка, браузер считает, что все содержимое
между нею и соответствующей закрывающей угловой скобкой является HTML-
тегом. Поскольку <Request> не является допустимым HTML-тегом, современные
браузеры игнорируют его и не выводят текст между угловыми скобками на экран,
что, собственно, и произошло. Загадка исчезновения данных запроса решена.
Но мы же должны показать их на странице с URL /viewlog.
Для этого нужно сообщить браузеру, что он не должен воспринимать угловые
скобки, окружающие объект запроса, как HTML-тег, а обрабатывать их как
обычный текст. Нам повезло, потому что в фреймворке Flask есть функция,
которая нам поможет.
292 z
0
{ ,
@app.route('/viewlog')
def view_the_log() -> str:
$(
)
( with open('vsearch.log') as log:
contents = log.read()
return contents
Чтобы решить проблему, мы должны вызвать escape с аргументом contents.
! `Vh
!
,
¢ÃÁ´À³ÒÂÁ¸º·½³
.
$8
.escape
.#
3 8
.
98D
>4
U
.$. hi</viewlog8.
G
9
> 8> 9.>
U$ #% 2
88 9 % 9
8D
> Chrome
8D >Chrome
x
(
s
º
$
($
294 z
0
{ ,
q*
<Request 'http://localhost:5000/search4' [POST]> {'i', 'e'}
<Request 'http://localhost:5000/search4' [POST]> {'i', 'e', 'u', 'a'}
<Request 'http://localhost:5000/search4' [POST]> {'a'}
q«dir» $$«:
=µ»
$v$
( «str»
$
(
$
$
«res»
Упражнение ]
. 6'26log_request 8
%'2
_
Y# vsearch4log.py 88D
>
.
9
w
% '%vsearch.log.
x
Y
F968.
9.
C
I %'%>
F96hi<=7;:94>
! `VZ
ES\Y|\req
¢ÃÁ´À³ÒÂÁ¸º·½³
F% 2
?
9.
8. ?3# >
> 68%$%8.4
$
$
$
$
296 z
0
{ ,
Код работает, но есть проблема. Каждый вызов print по умолчанию !
добавляет символ переноса строки, то есть для каждого запроса \]B^*($
в файл журнала записываются четыре отдельные строки. Вот как
выглядят данные, записанные этим кодом. z
«ImmutableMultiDict»
s
($G;<_
Q|* (
)
! `Va
1
#
q
x
*
s$ (
s
$
$
298 z
0
{ ,
ǤȆ3(3țȖȒȖȒ
ȕȎȄȋȄȑȒȓȒȓȒȆȒȈȗ
ȖȄȎȌșȈȏȌȑȑȟșȕȖȔȒȎ
ȎȒȈȄ"
! `VV
K(
]
Y# vsearch4log.py3 8
.
98D
>4
_
% F66'%vsearch.log
w
9
8.
x
U
%'%>8 9
hi<=7;:94>
¢ÃÁ´À³ÒÂÁ¸º·½³
$
>Chrome@
s
$
$
($
)
300 z
0
{ ,
s
)
($
~
! h\[
!
8
dzȒȓȔȄȆȠȖȉȐȉȑȣȉȕȏȌ
ȣȒȜȌȅȄȢȕȠȑȒȔȄȋȆȉȡȖȒ
ȑȉȖȄȊȉȕȖȔȗȎȖȗȔȄȈȄȑȑȟș
ȎȒȖȒȔȗȢȐȟȆȌȈȉȏȌȆȎȒȑȚȉ
ȇȏȄȆȟ"
302 z
0
{ ,
people['Ford']['Home Planet']
$
$&
$«\Cf=
Когда нужен произвольный доступ к структуре данных, нет ничего |G;L=N»
лучше, чем словарь словарей. Но подходит ли он для представления
данных из журнала?
Давайте подумаем, что у нас есть.
! h\h
14
304 z
0
{ ,
DZȗȊȑȟȉȈȄȑȑȟȉȗȊȉ
ȑȄșȒȈȣȖȕȣȆ©FRQWHQWVª
ǨȄȆȄȍȖȉȓȔȉȒȅȔȄȋȗȉȐ
ȉȇȒȆȕȓȌȕȒȎȕȓȌȕȎȒȆ
DZȉȗȆȉȔȉȑțȖȒȈȄȑȑȟȉ
ȑȗȊȑȒȒȅȔȄȅȄȖȟȆȄȖȠ
ȈȆȄȊȈȟȒȈȌȑȔȄȋȓȔȌ
țȖȉȑȌȌȄȋȄȖȉȐȓȔȌ
ȓȔȉȒȅȔȄȋȒȆȄȑȌȌ
! h\Z
-" " "
306 z
0
{ ,
Заточите карандаш
W Вот как выглядит функция view_the_log сейчас.
@app.route('/viewlog')
def view_the_log() -> str:
with open('vsearch.log') as log:
contents = log.readlines()
return escape(''.join(contents))
!
&
v return str(contents)
! h\a
Заточите карандаш
Решение Вот как выглядит функция view_the_log сейчас.
@app.route('/viewlog')
def view_the_log() -> str:
with open('vsearch.log') as log:
contents = log.readlines()
return escape(''.join(contents))
@app.route('/viewlog')
def view_the_log() -> 'str': (
«contents» $(
KCLN=LN<¬[]
«log».
FN/C.=L(,¥<=;:K/GC>);<GC%
!
$ jC:GFL=FLGC%
(
$ KCLN=LN<;..=L([]) «contents»
«log»
jC:FN=fFLGFL=<.GFN(‘|’)% q
(
KCLN=LN<[-1];..=L(escape(item))
) «e scape»~
$ w
return str(contents)
s
$ s
$
v
«contents»
308 z
0
{ ,
¢ÃÁ´À³ÒÂÁ¸º·½³
. '26view_the_log8 8$ @
@app.route('/viewlog')
def view_the_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)
Y# 3
.
8D
>4.
.$. hi</
viewlog8.
($
~
! h\V
SXDC|UX5
#
z
<th>
zs
$ z
<td> <tr>
Всякий раз, когда возникает необходимость сгенерировать разметку HTML (особенно <table>),
вспоминайте о Jinjia2. Механизм шаблонов Jinjia2 разработан специально для создания HTML,
и в нем есть несколько простых программных конструкций (основанных на синтаксисе Python),
с помощью которых можно автоматизировать любую необходимую логику.
В последней главе вы увидите, как теги {{и}}, а также {% block%} в Jinjia2 позволяют
использовать переменные и блоки HTML в виде аргументов шаблонов. Оказывается, теги {%
и %} более универсальные и могут содержать любые инструкции Jinjia2, к которым относится
и цикл for. На следующей странице вы увидите шаблон, использующий цикл for для
преобразования списка списков, содержащегося в contents, в читаемый формат.
310 z
0
{ ,
{% extends 'base.html' %}
s
{% block body %}
<h2>{{ the_title }}</h2>
w
(
<table>
<th>)
<tr>
$
{% for row_title in the_row_titles %}
<th>{{row_title}}</th>
{% endfor %} (
</tr> <tr>)
{% for log_row in the_data %}
q
<tr>
$v {% for item in log_row %} z
<td>{{item}}</td> s
$
<table>. {% endfor %}
</tr> <td>
{% endfor %}
</table> (
$
{% endblock %} <tr>
! h[[
1(#
312 z
0
{ ,
¢ÃÁ´À³ÒÂÁ¸º·½³
.
8$
>
Y 2$ >
9 2
>
9.
9%
8
q
v
$
Если заглянуть в исходный код этой страницы (щелкнув правой §
кнопкой мыши и выбрав соответствующий пункт в контекстном
меню), то можно увидеть, что каждый элемент данных из журнала
находится внутри своего тега <td>, каждая строка данных — в своем
теге <tr>, а таблица целиком заключена в тег <table>.
! h[h
#
314
z
z
z
0
{ ,
ǬțȖȒȅȟ
ȆȟȓȒȏȑȌȖȠȡȖȌȔȄȕțȉȖȟ
ȓȔȌȈȉȖȕȣȑȄȓȌȕȄȖȠȚȉȏȗȢ
ȎȗțȗȎȒȈȄǷȇȄȈȄȏ"
! h[Z
Код из главы 6
($
w$% with open('todos.txt') as tasks:
for chore in tasks:
$ $ |}N/CL
print(chore, end='')
s
«
FN/»)s$
(
tasks = open('todos.txt')
for chore in tasks:
print(chore, end='')
tasks.close()
z$
*
*
$(
...
...
@app.route('/viewlog')
def view_the_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,)
...
«¥<=;:K/g
=X.}»
$$
($(
$
$)
$
316 z