Логические выражения. Главные форматы файлов.
Содержание
-
Логические выражения. Главные форматы файлов.
-
Разбор задач
- 1. Являются ли питонские программы текстовыми файлами? (Ответ: да/нет + доказательство).
- 2. Напишите программу, которая читает содержимое файла "in.txt" и без изменений пишет его в файл "out.txt"
- 3. Напишите программу, которая пишет в файл "words.txt" текст песенки про 99 бутылок
- 4. Напишите программу, которая считает число строк, букв и слов в файле "words.txt", и пишет его на экран
- Логические выражения или как питон отличает истину от лжи
- Два слова про переносы строк
- Какие бывают текстовые форматы файлов
- TXT
- CSV
- XML
- Литература
-
Разбор задач
Напоминание
Для понимания материала ОБЯЗАТЕЛЬНО каждый пример пытаться исполнить, понять, почему он работает или не работает, и попробовать в нём что-то поменять, и посмотреть, что получится.
Программирование – это практическая дисциплина, и без успешных попыток что-то сделать руками понимания теории не появляется.
Одним из важнейших умений является и умение состыковать несколько кусочков программы, которое требует только практики, но не теории. Зачастую достаточно просто того, чтобы составить кусочки программы вместе, но иногда приходится ещё и подумать, что при этом происходит с переменными.
Разбор задач
1. Являются ли питонские программы текстовыми файлами? (Ответ: да/нет + доказательство).
Ответ: являются.
Например, мы можем открыть блокнот, написать в нём текст программы, сохранить в файл, и этот файл без изменений запустить питоном.
Или так:
После того, как мы запустим эту программу, у нас возникнет файл example.py, который мы, в свою очередь, снова можем запустить питоном.
2. Напишите программу, которая читает содержимое файла "in.txt" и без изменений пишет его в файл "out.txt"
Наиболее прямолинейное решение (которое работает для только небольших файлов – не больше нескольких гигабайт) состоит из двух частей:
- сначала нужно прочитать файл и положить его текст в переменную
- затем нужно открыть выходной файл за запись, и положить текст из переменной в него
1 import codecs
2 infile = codecs.open("in.txt")
3 text = infile.read() # получили в переменной text содержимое файла in.txt
4 outfile = codecs.open("out.txt", "w")
5 outfile.write(text) # записали содержимое переменной text в файл out.txt
6 outfile.close() # нужно обязательно не забыть закрыть за собой файл, иначе есть шансы, что он так и останется пустым
3. Напишите программу, которая пишет в файл "words.txt" текст песенки про 99 бутылок
Нам нужно взять решение нашей задачи про 99 бутылок из позапрошлого раза и модифицировать его так, чтобы вместо print у нас везде была запись в файл.
Вроде просто, но вылезает много мелких различий:
- нужно не забыть открыть файл в начале и закрыть файл в конце
- write не добавляет переносы строк самостоятельно
- print умеет выводить числа, write требует обязательно вручную привести данные к строкам
print разрешает перечислить несколько аргументов через запятую и втыкает между ними пробел, а write принимает один аргумент: приходится склеивать из кусочков строк вручную с помощью + (операции конкатенации), а конкатенация не вставляет пробелов – о них тоже нужно не забыть.
Для простоты я пишу программу про сильно урезанную версию стишка:
4. Напишите программу, которая считает число строк, букв и слов в файле "words.txt", и пишет его на экран
Это задание ничем не отличается от прошлого раза, кроме того, что текст, в котором нужно посчитать число строк, букв и слов, получается из файла.
Если в прошлый раз было:
то в этот раз вместо первой строки у нас получается:
Логические выражения или как питон отличает истину от лжи
Я рассчитываю здесь на поддержку со стороны ваших математиков в том, чтобы они потренировали вас переводить выражения с человеческого языка на язык алгебры логики и обратно. Пожалуйста, потрясите их на эту тему слегка.
Если у нас есть два числа в питоне, мы можем их сравнить:
Переводится на русский этот странный кусок кода так: положить в переменную answer ответ на вопрос "правда ли, что 1 больше 2"? Мы-то знаем ответ на этот вопрос. Поэтому нас не удивит, что питон ответит: False (то есть неправда)1. Ответов на операцию сравнения в питоне может быть только два: True или False.
С числами всё просто: можно спрашивать, правда ли, что данное число больше (>), меньше (<), больше или равно (>=), меньше или равно (<=), равно (==) или отличается (!=)2
Приятная новость (неожиданная для тех, кто умел программировать до этого) состоит в том, что мы можем писать цепочки сравниений так же, как мы делали это на математике:
Ещё одна приятная новость состоит в том, что так же можно сравнивать и строки:
А можете ли вы угадать ответ тут:
Питон сравнивает строки в лексикографическом порядке. Лексикографический – это тот порядок, в котором слова расположены в словаре. Если у нас есть два слова x и y, то для того, чтобы решить, кто из них в словаре идёт раньше, мы смотрим на первую букву каждого слова: если она различается, то раньше идёт то слово, у которого первая буква раньше в алфавите. Если совпадает (а в словаре это направо и налево случается), то мы смотрим на вторую букву в каждом слове. И так далее. (А если мы дошли до конца строки, а буквы все совпали, то x и y – это одно и то же слово!)
Например: что идёт в словаре раньше – ананас или антилопа? По первой букве оба слова идут в главу "А". По второй совпадают: "н". А по третьей букву у нас "а" и "т" – значит ананас раньше.
По этому принципу питон сравнивает между собой строки.
По такому же принципу питон сравнивает между собой и два списка.
Для строк в питоне есть множество полезных методов, проверяющих обладает ли строка некими свойствами:
s.isupper(), s.islower(), s.istitle() – все буквы в верхнем/нижнем регистре / в верхнем только первая буква
s.isdigit(), s.isalpha(), s.isalnum(), s.isspace() – все символы в строке являются: цифрами / буквами / буквами или цифрами / примерно пробелами (пробелами, табуляциями, переносами строк – и ещё есть с десяток символов, которые выполняют роль пробелов)
Примеры:
Попробуйте дописать этот фрагмент кода используя все известные вам проверки на разные типы символов, и посмотреть, как он реагирует на разные строки.
Для списков и строк есть ещё одна полезная операция сравнения: in проверяет наличие элемента в списке или наличие подстроки в строке, not in – отстутствие:
Теперь мы можем четвёртую домашнюю задачу выполнить с точностью да занудства и посчитать именно число букв в тексте:
Есть ещё одна операция сравнения, с которой вы встретитесь в разных фрагментах кода в сети, которую я на ближайший год советую вам просто не использовать никогда: is и is not. Это НЕ сравнение на равенство. Это проверка на то, что слева и справа стоит один и тот же объект. И беда в том, что 1 is 1 имеет право быть верным не всегда – а это значит, что оно будет верно пока вы пишете и отлаживаете программу, но как только вы её захотите показать большому начальнику чтобы похвастаться, окажется, что оно не работает! Так что простое правило: в питоне есть сравнение is, мы его не используем. Даже не привожу примеров, чтобы у вас не было примеров плохого.
Кроме того, получившиеся логические ответы в питоне можно комбинировать:
Логическая операция and (И) проверяет, являются ли выполненными оба условия одновременно, or – хотя бы одно, not – что условие не выполнено.
Experts only
Кроме перечисленного, питон может воспринимать почти любой объект как логическое значение:
- 0 как False, все остальные числа как True
- [] как False, все остальные списки как True
''как False, все остальные строки как True
и т.п. для остальных типов данных.
Это позволяет в некоторых случаях писать гораздо более понятную и надёжную проверку на пустоту.
Если вы считаете, что этот блок текста относится к вам, я предлагаю задуматься, в каких случаях вам будет полезна проверка is.
Два слова про переносы строк
Печальная новость: исторически сложилось, что перенос строки в текстовых файлах может обозначаться двумя разными способами:
- "\r\n", он же CR-LF, он же windows line feed. В них перенос строки обозначается двумя символами: carrige return и line feed. (Происходит это обозначение от механических печатных машинок, там было два действия: перетянуть каретку в начало строки и провернуть барабан на следующую строку). В питоне эти два символа обозначаются
"\n", он же LF, он же unix line feed. Здесь перенос строки обозначается одним символом – потому, что так проще.
Ещё одна печальная новость состоит в том, что python, по идее, должен бы сам их различать и оставлять те, которые нужно, но почему-то в некоторых случаях он этого не делает.
Это очень неудобно, но есть и хорошие новости:
мне известна только одна – самая бесполезная – программа, которая не умеет сама их различать, и признаёт только windows line feed – это блокнот
- если мы читаем файл, считая, что в нём строки разделены только "\n", то в обоих случаях мы получим правильное разбиение на строки
Отсюда мы можем выработать такую стратегию поведения:
мы всегда в программе обозначаем перенос строки символом "\n" – и когда пишем файл, и когда читаем файл
при чтении строки из файла нужно учитывать, что в ней в конце могут оказаться лишние невидимые символы, поэтому всегда стоит пользоваться str.strip()
- мы никогда не пользуемся блокнотом
count
У строк и у списков есть метод count:
У строк метод count считает количество раз, которое подстрока встретилась в строке.
У списков метод count считает количество раз, которое данный элемент встретился в списке.
Это не очень полезные методы, так как обычно для статистики требуется считать несколько более сложные вещи, и есть более удачные способы это делать. Мы дойдём до этих способов несколько позже, а пока что поупражняемся с более простыми решениями.
Какие бывают текстовые форматы файлов
Обычно форматы файлов называют так же, как и соответствующее расширение файла. (Расширение файла – часть имени, идущая после точки). Важно понимать, что формат файла – это то, как устроены внутренности, а расширение файла – это просто имя файла3. "Если на клетке с тигром написано баран – не верь глазам своим!"
TXT
Наверное, самый полезный для нас формат – TXT.
Это очень сложный формат файлов, но мы его уже знаем: это текстовый файл, в котором хранится только читаемый и понятный человеку текст.
Полезно знать, что этот же формат называется "plain text", или "обычный текст", и многие программы, работающие с размеченным текстом, например, Word, умеют сохранять текст в TXT.
CSV
Второй из самых полезных для нас форматов – CSV. Он предназначен для хранения табличных данных. Название расшифровывается "comman separated values", то есть "значения, разделённые запятой".
Формат устроен так: каждая строка таблицы отображается как строка текстового файла. Строка делится на ячейки по разделителям – типично, запятым. Например:
Name,age Johnson,42 Иванов,33
Обозначает таблицу:
Формально название формата требует, чтобы в качестве разделителя в нём использовались запятые, но на практике чаще всего используют запятые, точки с запятой или табуляции (символ табуляции в питонских строках обозначается "\t"). Пожалуй, что табуляции используются даже чаще остальных, в честь чего для них иногда используют название TSV – tab-separated values.
Формат CSV прекрасем тем, что все программы для работы с таблицами (включая MS Excel, Google Spreadsheets и Libreoffice) умеют сохранять таблицы в этом формате. Очевидно, в этом формате невозможно сохранить всяческие навороты вроде объединения строк или столбцов, раскраски, шрифтов и пр, поэтому если такие явления в вашей таблице встречаются, то вам либо сообщат об опасности сохранения в этом формате, либо (встречается реже, но больше удивляет) вам могут не предложить CSV в качестве возможных форматов для сохранения.
Оперируя лишь теми знаниями про питон, которые у нас были, мы уже можем прочитать csv-файл и узнать, что лежит в какой ячейке таблицы. Проще всего нам таблицу в питоне представить как список строк, где каждая строка представлена как список ячеекв в ней:
1 import codecs
2 separator = "," # а если в файле другой разделитель, можем поменять
3 file = codecs.open("example.csv") # предполагаем, что codecs.open правильно угадает кодировку, если нет -- пропишем
4
5 rows = []
6 for line in file:
7 line_cleared = line.rstrip() # убираем лишние \r\n
8 cells = line_cleared.split(separator)
9 rows.append(cells) # добавляем список ячеек данной строки в качестве одного элемента в список строк
10
11 print rows
Одно маленькое замечание, которое изредка может стоить вам большого количества нервов: когда мы идём по строкам файла циклом for, то в переменную line на каждой итерации попадает вся строка целиком включая символы переноса строки. Поэтому я рекомендую взять себе в бездумную привычку первым делом при таком работе вызывать rstrip(), чтобы их отрезать – что и показано в примере.
Теперь мы можем, например, получить содержимое 3-й ячейки второй строки:
Мы можем делать с таблицами, прочитанными таким образом всё, что мы умели делать со списками: считать длину, искать, есть ли в них интересующие нас данные, ходить по ним циклом, редактировать... Например:
XML
Последний из самых важных для вас форматов файлов называется XML.
Работать с ним с помощью питона мы научимся нескоро – где-то в середине второго модуля – но иметь о нём представление нам необходимо для того, чтобы смотреть на него глазами и уметь из него находить нужные нам вещи.
Язык XML используется по существу для двух вещей:
- хранения сложных структур
- разметки частей текста, не нарушая саму структуру текста
Пример сложной структуры – это, например, НКРЯ:
Корпус – это метаданные + тексты. Каждый текст – это метаданные + предложения. Предложение состоит из слов, про каждое из которых указан морфологический разбор.
То есть основное отношение, которое описывается в формате XML: общее состоит из таких-то частей. Это отношение записывается в xml так:
Разметка <whole> и </whole> называется открывающий тэг и закрывающий тэг соответственно. Слово, описывающее тэг, обычно имеет какую-то смысловую нагрузку.
У тэгов могут дополнительно указываться атрибуты в виде пар ключ="значение" внутри открывающего тэга:
Соответствено, чтобы получить эффект "корпус состоит из текстов, текст состоит из предложений", пары тэгов можно друг в друга вкладывать.
Пример из syntagrus:
1 <?xml version="1.0" encoding="utf-8" standalone="no"?>
2 <text DB_PATH="Y:\\Corpus\\Ready_Corpus\\2011\\Alpinizm.tgt" PARAMS="ETAPOPTION=RE; DOMAINS=COMMON-DOMAIN; LEVEL=$TRUE; WEAKPRED=$FALSE; PARAFR=$FALSE; STAT=N; SENTFEATS=STDSENT; SYNTMODE=STDSYNT; ALTTR=$TRUE; MWORDFORM=$FALSE; CORDESCRMODE=CORDESCROLDMODE; SYNTAXONLY=$FALSE; SOFTSENTBR=$FALSE; SOFTGEOMFILTR=$TRUE; EXPERMODE=EXPER_OFF; DISAMBMODE=DISAMB_OFF; MAXALTNUM=NORMALNUM; USECORPLF=$FALSE; SPEECHMODE=SPEECHMODENO; " ver="1.1">
3 <inf>
4 <annot>ЛМ</annot>
5 <editor>TF</editor>
6 <source>Википедия, 22 мая 2011</source>
7 <title>Альпинизм</title>
8 </inf>
9 <body>
10 <S ID="1">
11 <W DOM="2" FEAT="S ЕД МУЖ ИМ НЕОД" ID="1" LEMMA="АЛЬПИНИЗМ" LINK="предик">Альпинизм</W> -
12 <W DOM="_root" FEAT="S ЕД МУЖ ИМ НЕОД" ID="2" LEMMA="ВИД">вид</W>
13 <W DOM="2" FEAT="S ЕД МУЖ РОД НЕОД" ID="3" LEMMA="СПОРТ" LINK="квазиагент">спорта</W>
14 <W DOM="3" FEAT="CONJ" ID="4" LEMMA="И" LINK="сочин">и</W>
15 <W DOM="6" FEAT="A ЕД МУЖ РОД" ID="5" LEMMA="АКТИВНЫЙ" LINK="опред">активного</W>
16 <W DOM="4" FEAT="S ЕД МУЖ РОД НЕОД" ID="6" LEMMA="ОТДЫХ" LINK="соч-союзн">отдыха</W>,
17 <W DOM="9" FEAT="S ЕД ЖЕН ТВОР НЕОД" ID="7" LEMMA="ЦЕЛЬ" LINK="1-компл">целью</W>
18 <W DOM="7" FEAT="S ЕД МУЖ РОД" ID="8" LEMMA="КОТОРЫЙ" LINK="квазиагент">которого</W>
19 <W DOM="2" FEAT="V НЕСОВ ИЗЪЯВ НЕПРОШ ЕД 3-Л" ID="9" LEMMA="ЯВЛЯТЬСЯ" LINK="релят">является</W>
20 <W DOM="9" FEAT="S ЕД СРЕД ИМ НЕОД" ID="10" LEMMA="ВОСХОЖДЕНИЕ" LINK="предик">восхождение</W>
21 <W DOM="10" FEAT="PR" ID="11" LEMMA="НА" LINK="2-компл">на</W>
22 <W DOM="11" FEAT="S МН ЖЕН ВИН НЕОД" ID="12" LEMMA="ВЕРШИНА" LINK="предл">вершины</W>
23 <W DOM="12" FEAT="S МН ЖЕН РОД НЕОД" ID="13" LEMMA="ГОРА" LINK="квазиагент">гор</W>.
24 </S>
25 <S ID="2">
26 <W DOM="2" FEAT="A ЕД ЖЕН ИМ" ID="1" LEMMA="СПОРТИВНЫЙ" LINK="опред">Спортивная</W>
27 <W DOM="4" FEAT="S ЕД ЖЕН ИМ НЕОД" ID="2" LEMMA="СУЩНОСТЬ" LINK="предик">сущность</W>
28 <W DOM="2" FEAT="S ЕД МУЖ РОД НЕОД" ID="3" LEMMA="АЛЬПИНИЗМ" LINK="квазиагент">альпинизма</W>
29 <W DOM="_root" FEAT="V НЕСОВ ИЗЪЯВ НЕПРОШ ЕД 3-Л" ID="4" LEMMA="СОСТОЯТЬ">состоит</W>
30 <W DOM="4" FEAT="PR" ID="5" LEMMA="В" LINK="1-компл">в</W>
31 <W DOM="5" FEAT="S ЕД СРЕД ПР НЕОД" ID="6" LEMMA="ПРЕОДОЛЕНИЕ" LINK="предл">преодолении</W>
32 <W DOM="6" FEAT="S МН СРЕД РОД НЕОД" ID="7" LEMMA="ПРЕПЯТСТВИЕ" LINK="1-компл">препятствий</W>,
33 <W DOM="7" FEAT="V НЕСОВ СТРАД ПРИЧ НЕПРОШ МН РОД" ID="8" LEMMA="СОЗДАВАТЬ" LINK="опред">создаваемых</W>
34 <W DOM="8" FEAT="S ЕД ЖЕН ТВОР НЕОД" ID="9" LEMMA="ПРИРОДА" LINK="агент">природой</W>
35 (<W DOM="7" FEAT="S ЕД ЖЕН ИМ НЕОД" ID="10" LEMMA="ВЫСОТА" LINK="примыкат">высота</W>,
36 <W DOM="10" FEAT="S ЕД МУЖ ИМ НЕОД" ID="11" LEMMA="РЕЛЬЕФ" LINK="сочин">рельеф</W>,
37 <W DOM="11" FEAT="S ЕД ЖЕН ИМ НЕОД" ID="12" LEMMA="ПОГОДА" LINK="сочин">погода</W>),
38 <W DOM="7" FEAT="PR" ID="13" LEMMA="НА" LINK="атриб">на</W>
39 <W DOM="13" FEAT="S ЕД МУЖ ПР НЕОД" ID="14" LEMMA="ПУТЬ" LINK="предл">пути</W>
40 <W DOM="14" FEAT="PR" ID="15" LEMMA="К" LINK="3-компл">к</W>
41 <W DOM="15" FEAT="S ЕД ЖЕН ДАТ НЕОД" ID="16" LEMMA="ВЕРШИНА" LINK="предл">вершине</W>.
42 </S>
43 ...
44 </body>
45 </text>
Здесь мы видим ещё один тип тэгов: тэги <?...?> отвечают за настройку того, как интерпретировать этот документ, и нужны только компьютеру. Мы их смело можем не читать.
Стандарт XML не говорит нам трактовку конкретных тэгов, об этом нужно договариваться с авторами документа. (Впрочем, стандарт XML предполагает некоторые способы формализовать эту договорённость).
В нашем примере:
1 <W DOM="4" FEAT="S ЕД МУЖ РОД НЕОД" ID="6" LEMMA="ОТДЫХ" LINK="соч-союзн">отдыха</W>,
Тэг <w> обозначает разобранный токен. Про него в качестве атрибутов указывается:
морфологический анализ в атрибуте FEAT
лемма (LEMMA)
- отношения между словами в предложениями:
на каждом слове есть атрибут ID, который указывает его номер
на подчинённом слове есть атрибут DOM, который указывает определяемое слово
атрибут LINK указыает тип связи
Литература
http://docs.python.org/2.7/tutorial/datastructures.html#more-on-conditions
http://docs.python.org/2.7/library/stdtypes.html#string-methods
Собственно, алгебра логики -- это область математики, которая занимается выражениями, в которых участвуют значения "истина" и "ложь". И это большая область математики с кучей интересных выводов и полезных применений: начиная от ловли политиков на вранье и заканчивая расположением элементов на микросхеме. (1)
Для проверки на неравенство есть синтаксис <>, которые те из вас, кто привык к паскалю, с удовольствием бы стали использовать. Но я это очень не рекоммендую делать, так как в третьем питоне такое сравнение уже не работает. (2)
Увы, Windows этого не понимает, и принимает решение о том, как файл открывать исходя из того, как файл назван (3)