Простой способ создать файл в python
Умение создавать файлы в Python открывает массу новых возможностей — например, позволяет хранить данные, сохраняя их согласованность для разных пользователей. Вместе с тем упрощает процесс управления данными, скрапинга контента и многое другое.
Важно и то, что в Python этот процесс очень простой.
Как создать файл в Python в три строки
С помощью следующего кода можно создать файл с названием BabyFile.txt и записать в него текст «Привет, файл!»:
my_file = open("BabyFile.txt", "w+")
my_file.write("Привет, файл!")
my_file.close()В начале объявляется переменная my_file . После этого используются встроенные функции open и write для открытия и записи в файл. "w+" сообщает, что запись будет осуществляться в новый файл. Если он существует, то новое содержимое нужно записать поверх уже существующего. Если же вместо этого использовать параметр "w" , тогда файл будет создан только в том случае, если он не существовал до этого.
Важно заметить, что в конце файл всегда нужно закрывать, чтобы изменения сохранились.
Как записывать, добавляя новое содержимое
С созданием файла разобрались. Теперь можно узнать, как редактировать, удалять и даже копировать файлы.
Если нужно добавить новые данные в файл, тогда вместо "w+" нужно просто использовать параметр "a+" .
Разработка расширений на Python¶
Для разработки расширений можно использовать язык программирования Python. По сравнению с классическими расширениями, написанными на C++, их легче разрабатывать, понимать, поддерживать и распространять в силу динамической природы самого Python.
Расширения на Python перечисляются в Менеджере модулей QGIS наравне с расширениями на C++. Поиск расширений выполняется в следующих каталогах:
- UNIX/Mac: ~/.qgis/python/plugins и (qgis_prefix)/share/qgis/python/plugins
- Windows: ~/.qgis/python/plugins и (qgis_prefix)/python/plugins
В Windows домашний каталог (обозначенный выше как ~ ) обычно выглядит как C:\Documents and Settings\(user) . Вложенные каталоги в этих папках рассматриваются как пакеты Python, которые можно загружать в QGIS как расширения.
- Идея: Прежде всего нужна идея для нового расширения QGIS. Зачем это нужно? Какую задачу необходимо решить? Может, есть готовое расширения для решения этой задачи?
- Создание файлов: Подробнее этот шаг описан ниже. Точка входа ( __init.py__ ). Тело расширения ( plugin.py ). Форма QT-Designer ( form.ui ), со своим resources.qrc .
- Реализация: Пишем код в plugin.py
- Тестирование: Закройте и снова откройте QGIS, загрузите своё расширение. Проверьте, что всё работает как надо.
- Публикация: опубликуйте своё расширение в репозитории QGIS или настройте свой собственный репозиторий в качестве “арсенала” личного “ГИС вооружения”
Разработка расширения¶
С момента введения поддержки Python в QGIS появилось множество расширений — на странице Plugin Repositories можно найти некоторые из них. Исходный код этих расширений можно использовать, чтобы узнать больше о программировании с PyQGIS, а также для того, чтобы удостовериться, что разработка не дублируется. Готовы к созданию расширения, но отсутствует идея? На странице Python Plugin Ideas собрано много идей и пожеланий!
Создание необходимых файлов¶
Ниже показано содержимое каталога нашего демонстрационного расширения:
PYTHON_PLUGINS_PATH/ testplug/ __init__.py plugin.py metadata.txt resources.qrc resources.py form.ui form.py
Для чего используются файлы:
- __init__.py = Точка входа расширения. Содержит общую информацию, версию расширения, его название и основной класс.
- plugin.py = Основной код расширения. Содержит информацию обо всех действиях, доступных в расширении, а также основной код.
- resources.qrc = XML-документ, созданный QT-Designer. Здесь хранятся относительные пути к ресурсам форм.
- resources.py = Понятная Python версия вышеописанного файла.
- form.ui = Интерфейс пользователя (GUI), созданный в QT-Designer.
- form.py = Конвертированная в код Python версия вышеописанного файла.
- metadata.txt = требуется в QGIS >= 1.8.0. Содержит общую информацию, версию расширения, его название и другие метаданые, используемые новым репозиторием расширений. Метаданным в metadata.txt отдается предпочтение перед методами из файла __init__.py . Если текстовый файл присутствует, именно он будет использоваться для получения этой информации. Начиная с QGIS 2.0 метаданные из __init__.py больше не будут использоваться и файл metadata.txt станет обязательным.
Здесь и вот здесь можно найти два способа автоматической генерации базовых файлов (скелета) типового Python расширения для QGIS. Кроме того, существует модуль Plugin Builder , который создает шаблон модуля прямо из QGIS и не требует соединения с Интернет. Это упростит работу и поможет быстрее начать разработку типового расширения.
Написание кода¶
__init__.py¶
Прежде всего, Менеджер модулей должен получить основные сведения о расширении, такие как его название, описание и т.д. Файл __init__.py именно то место, где должна быть эта информация:
def name(): return "My testing plugin" def description(): return "This plugin has no real use." def version(): return "Version 0.1" def qgisMinimumVersion(): return "1.0" def authorName(): return "Developer" def classFactory(iface): # загружаем класс TestPlugin из файла testplugin.py from testplugin import TestPlugin return TestPlugin(iface)
В QGIS 1.9.90 модули могут быть помещены не только в меню Модули , но и в меню Растр , Вектор , База данных и Web . Поэтому было введено новое поле метаданных “category”. Это поле используется в качестве подсказки для пользователей и сообщает где (в каком меню) искать модуль. Допустимыми значениями для параметра “category” являются Vector, Raster, Database, Web и Layers. Например, если модуль должен быть доступен из меню Растр , добавьте в __init__.py следующие строки:
def category(): return "Raster"
metadata.txt¶
Для QGIS >= 1.8 необходимо создать файл metadata.txt (см. также) Пример :file: ` metadata.txt’:
; the next section is mandatory [general] name=HelloWorld qgisMinimumVersion=1.8 description=This is a plugin for greeting the (going multiline) world category=Raster version=version 1.2 ; end of mandatory metadata ; start of optional metadata changelog=this is a very very very very very very long multiline changelog ; tags are in comma separated value format, spaces are allowed tags=wkt,raster,hello world ; these metadata can be empty ; in a future version of the web application it will ; be probably possible to create a project on redmine ; if they are not filled homepage=http://www.itopen.it tracker=http://bugs.itopen.it repository=http://www.itopen.it/repo icon=icon.png ; experimental flag experimental=True ; deprecated flag (applies to the whole plugin and not only to the uploaded version) deprecated=False
plugin.py¶
Стоит сказать несколько слов о функции classFactory() , которая вызывается когда расширение загружается в QGIS. Она получает ссылку на экземпляр класса QgisInterface и должна вернуть экземпляр класса вашего расширения — в нашем случае этот класс называется``TestPlugin``. Ниже показано он должен выглядеть (например, testplugin.py ):
from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * # загружаем ресурсы Qt из файла resouces.py import resources class TestPlugin: def __init__(self, iface): # сохраняем ссылку на интерфейс QGIS self.iface = iface def initGui(self): # создаем действия для запуска расширения или его настройки self.action = QAction(QIcon(":/plugins/testplug/icon.png"), "Test plugin", self.iface.mainWindow()) self.action.setWhatsThis("Configuration for test plugin") self.action.setStatusTip("This is status tip") QObject.connect(self.action, SIGNAL("triggered()"), self.run) # добавляем кнопку на панель и пункт в меню self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Test plugins", self.action) # подключаемся к сигналу renderComplete, который посылается по завершению отрисовки карты QObject.connect(self.iface.mapCanvas(), SIGNAL("renderComplete(QPainter *)"), self.renderTest) def unload(self): # удаляем пункт меню и кнопку на панели self.iface.removePluginMenu("&Test plugins",self.action) self.iface.removeToolBarIcon(self.action) # отключаемся от сигнала карты QObject.disconnect(self.iface.MapCanvas(), SIGNAL("renderComplete(QPainter *)"), self.renderTest) def run(self): # создаем и показываем диалог настройки или выполняем что-то еще print "TestPlugin: run called!" def renderTest(self, painter): # рисуем на карте, используя painter print "TestPlugin: renderTest called!"
Если используется QGIS 1.9.90 или старше и необходимо разместить модуль в одном из новых меню ( Растр , Вектор , База данных или Web ), нужно модифицировать код функций initGui() и unload() . Так как эти новые пункты меню доступны только в QGIS 1.9.90, прежде всего необходимо проверить, что используемая версия QGIS имеет все необходимые функции. Если новые пункты меню доступны, мы можем разместить модуль в нужном месте, в противном случае будем использовать меню Модули как и раньше. Вот пример для меню Растр :
def initGui(self): # создаем действия для запуска расширения или его настройки self.action = QAction(QIcon(":/plugins/testplug/icon.png"), "Test plugin", self.iface.mainWindow()) self.action.setWhatsThis("Configuration for test plugin") self.action.setStatusTip("This is status tip") QObject.connect(self.action, SIGNAL("triggered()"), self.run) # проверяем, доступно ли меню Растр if hasattr(self.iface, "addPluginToRasterMenu"): # меню Растр и одноименная панель доступны self.iface.addRasterToolBarIcon(self.action) self.iface.addPluginToRasterMenu("&Test plugins", self.action) else: # меню Растр отсутствует, размещаем модуль в меню Модули, как и раньше self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Test plugins", self.action) # одключаемся к сигналу renderComplete, который посылается по завершению отрисовки карты QObject.connect(self.iface.mapCanvas(), SIGNAL("renderComplete(QPainter *)"), self.renderTest) def unload(self): # проверям доступно ли меню Растр и удаляем наши кнопки из соответствующего # меню и панели if hasattr(self.iface, "addPluginToRasterMenu"): self.iface.removePluginRasterMenu("&Test plugins",self.action) self.iface.removeRasterToolBarIcon(self.action) else: self.iface.removePluginMenu("&Test plugins",self.action) self.iface.removeToolBarIcon(self.action) # отключаемся от сигнала карты QObject.disconnect(self.iface.MapCanvas(), SIGNAL("renderComplete(QPainter *)"), self.renderTest)
Полный список методов, которые можно использовать для размещения модуля в новых меню и на новых панелях инструментов доступен в описании API.
В расширении обязательно должны присутствовать функции initGui() и unload() . Эти функции вызываются когда расширение загружается и выгружается.
Файл ресурсов¶
Как видно в примере выше, в initGui() мы использовали иконку из файла ресурсов (в нашем случае он называется resources.qrc ):
icon.png
Хорошим тоном считается использование префикса, это позволит избежать конфликтов с другими расширениями или с частями QGIS. Если префикс не задан, можно получить не те ресурсы, которые нужны. Теперь сгенерируем файл ресурсов на Python. Это делается командой pyrcc4:
pyrcc4 -o resources.py resources.qrc
Вот и все. ничего сложного 🙂 Если всё сделано правильно, то расширение должно отобразиться в Менеджере модулей и загружаться в QGIS без ошибок. После его загрузки на панели появится кнопка, а в меню — новый пункт, нажатие на которые приведет к выводу сообщения на терминал.
При работе над реальным расширением удобно вести разработку в другом (рабочем) каталоге и создать makefile, который будет генерировать файлы интерфейса и ресурсов, а также выполнять копирование расширения в каталог QGIS.
Документация¶
Этот способ создания документации требует наличия Qgis версии 1.5.
Документацию к расширению можно готовить в виде файлов HTML. Модуль qgis.utils предоставляет функцию showPluginHelp() , которая откроет файл справки в браузере, точно так же как другие файлы справки QGIS.
Функция showPluginHelp`() ищет файлы справки в том же каталоге, где находится вызвавший её модуль. Она по очереди будет искать файлы index-ll_cc.html , index-ll.html , index-en.html , index-en_us.html и index.html , и отобразит первый найденный. Здесь ll_cc — язык интерфейса QGIS. Это позволяет включать в состав расширения документацию на разных языках.
Кроме того, функция showPluginHelp() может принимать параметр packageName, идентифицирующий расширение, справку которого нужно отобразить; filename, который используется для переопределения имени файла с документацией; и section, для передачи имени якоря (закладки) в документе, на который браузер должен перейти.
Фрагменты кода¶
Здесь собраны фрагменты кода, полезные при разработке расширений.
Как вызвать метод по нажатию комбинации клавиш¶
Добавьте в initGui() :
self.keyAction = QAction("Test Plugin", self.iface.mainWindow()) self.iface.registerMainWindowAction(self.keyAction, "F7") # action1 is triggered by the F7 key self.iface.addPluginToMenu("&Test plugins", self.keyAction) QObject.connect(self.keyAction, SIGNAL("triggered()"),self.keyActionF7)
self.iface.unregisterMainWindowAction(self.keyAction)
Метод, вызываемый по нажатию F7:
def keyActionF7(self): QMessageBox.information(self.iface.mainWindow(),"Ok", "You pressed F7")
Как управлять видимостью слоя (временное решение)¶
Примечание: в QGIS 1.5 появился класс QgsLegendInterface , позволяющий управлять списком слоёв легенды.
Так как в настоящее время методы прямого доступа к слоям легенды отсутствуют, в качестве временно решения для управления видимостью слоёв можно использовать решение на основе изменения прозрачности слоя:
def toggleLayer(self, lyrNr): lyr = self.iface.mapCanvas().layer(lyrNr) if lyr: cTran = lyr.getTransparency() lyr.setTransparency(0 if cTran > 100 else 255) self.iface.mapCanvas().refresh()
Метод принимает номер слоя в качестве параметры (0 соответствует самому верхнему) и вызывается так:
self.toggleLayer(3)
Как получить доступ к таблице атрибутов выделенных объектов¶
def changeValue(self, value): layer = self.iface.activeLayer() if(layer): nF = layer.selectedFeatureCount() if (nF > 0): layer.startEditing() ob = layer.selectedFeaturesIds() b = QVariant(value) if (nF > 1): for i in ob: layer.changeAttributeValue(int(i),1,b) # 1 соответствует второй колонке else: layer.changeAttributeValue(int(ob[0]),1,b) # 1 соответствует второй колонке layer.commitChanges() else: QMessageBox.critical(self.iface.mainWindow(),"Error", "Please select at least one feature from current layer") else: QMessageBox.critical(self.iface.mainWindow(),"Error","Please select a layer")
Метод принимает один параметр (новое значения атрибута выделенного объекта(ов)) и вызывается как:
self.changeValue(50)
Как выполнять отладку при помощи PDB¶
Сначала добавьте следующий код в место, которое будет отлаживаться:
# для отладки используем pdb import pdb # устанавливаем точку останова pyqtRemoveInputHook() pdb.set_trace()
Затем запускаем QGIS из командной строки.
$ ./Qgis
$ /Applications/Qgis.app/Contents/MacOS/Qgis
Когда приложение достигнет точки останова, консоль станет доступной и можно будет вводить команды!
Тестирование¶
Публикация расширения¶
Если после создания расширения вы решите, что оно может быть полезно и другим пользователям — не бойтесь загрузить его в репозиторий QGIS plugin repository. На этой же странице можно найти инструкции по подготовке пакета, следование которым избавит от проблем с установкой расширения через Установщик модулей. В случае, когда нужно настроить собственный репозиторий, создайте простой XML документ, описывающий все расширения и их метаданные. Пример файла можно найти на странице Python plugin repositories.
Примечание: настройка IDE в Windows¶
При использовании Linux разработка расширений не требует дополнительных настроек. Но в при использовании Windows необходимо убедиться, что и QGIS, и интерпретатор используют одни и те же переменные окружения и библиотеки. Наиболее простой и быстрый способ сделать это — модифицировать командный файл для запуска QGIS.
Если используется установщик OSGeo4W, командный файл можно найти в каталоге bin папки, куда выполнена установка OSGeo4W. Ищите что-то похожее на C:\OSGeo4W\bin\qgis-unstable.bat .
Далее будет описана настройка Pyscripter IDE. Настройка других сред разработки может несколько отличаться:
- Сделайте копию qgis-unstable.bat и переименуйте её в pyscripter.bat.
- Откройте это файл в редакторе. Удалите последнюю строку, которая отвечает за запуск QGIS.
- Добавьте строку для запуска pyscripter с параметром, указывающим на используемую версию Python. QGIS 1.5 использует Python 2.5.
- Добавьте еще один аргумент, указывающий на каталог, где pyscripter должен искать библиотеки Python, используемые qgis. Обычно это каталог bin папки, куда установлен OSGeo4W:
@echo off SET OSGEO4W_ROOT=C:\OSGeo4W call "%OSGEO4W_ROOT%"\bin\o4w_env.bat call "%OSGEO4W_ROOT%"\bin\gdal16.bat @echo off path %PATH%;%GISBASE%\bin start C:\pyscripter\pyscripter.exe --python25 --pythondllpath=C:\OSGeo4W\bin
Теперь при запуске этого командного файла установятся необходимые переменные окружения и будет запущен pyscripter.
Как создать исполняемые файлы для Python (от .PY до .EXE)
Сегодня мы увидим, как создавать исполняемые файлы, начиная с наших скриптов Python, чтобы мы могли легко запускать и делиться нашими программами, так как после того, как мы создадим эти приложения, которые мы создадим из наших файлов, будет достаточно щелкнуть по ним, чтобы запустить их, без необходимости установки в системе интерпретатора Python или другие зависимости!
Например, если у вас есть друзья или коллеги, с которыми вы хотите поделиться своей программой, или если вы хотите создать исполняемый файл, чтобы брать его с собой, не беспокоясь о настройке системы каждый раз, когда вам придется ее использовать, эта статья — то, чего вы ждали!
Для этого мы будем использовать инструмент под названием pyinstaller.
Pyinstaller отлично работает как в Windows, так и в Linux и Mac OS, и поэтому все команды, которые мы покажем вам в этой статье, будут такими же, что и вам, независимо от того, в какой операционной системе вы находитесь.
Также очень важно помнить, что pyinstaller не является кросс-компилятором, или, как многие из вас уже предполагали, вы можете создавать исполняемые файлы только для используемой вами операционной системы.
Если вы хотите создать файл .exe, например, а затем исполняемый файл для Windows, вы можете сделать это только из Windows. То же самое относится к файлам .app, которые можно использовать в Mac OS, и для исполняемых файлов Linux.
Процедура создания наших приложений действительно очень и очень проста: внутри виртуальной среды, которую мы используем с нашим скриптом Python, мы даем команду:
pip install pyinstaller
После того, как это будет сделано, мы можем использовать его как любое программное обеспечение в командной строки, точно так же, как мы устанавливаем модули через pip:
pyinstaller script_name.py --onefile
Читать Как использовать классы данных в Python
Давайте посмотрим на вывод в папке, над которой мы работаем, и увидим, что были созданы некоторые новые файлы и папки.
Единственный файл, который нам понадобится, файл, который нас интересует и который мы затем можем передать, будет находиться в папке dist.
Как видите, все работает отлично, и мы можем использовать программу без необходимости знать, как использовать Python, как его настроить, как создать виртуальную среду, установить необходимые зависимости и так далее!
Внутри этого исполняемого файла есть все, что необходимо для правильной работы нашей программы.
Если вы работаете в Windows и генерируете исполняемый файл для программы с графическим интерфейсом, как в этом случае, я предлагаю вам добавить еще один вариант:
pyinstaller script_name.py --noconsole --onefile
Опция —noconsole гарантирует, что единственным окном, отображаемым в этих случаях, является графический интерфейс вашей программы, поскольку по умолчанию Windows также открывает системный терминал, который останется активным во время работы программы, что может вызвать путаницу, особенно для менее опытных пользователей.
Мы советуем вам делать тесты и экспериментировать самостоятельно, чтобы полностью понять, что мы имеем в виду.
Эта опция вам не понадобится, если вы обнаружите, что создаете исполняемые файлы для простых сценариев, которые можно использовать из терминала по понятным причинам.
Удачного кодирования! : D
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Работа с файлами
Для открытия файлов в python используется функция open :
file = open("/path/for/your/file.txt", "r")
Она возвращает поток - интерфейс взаимодействия с содержимым файла.
Функция open принимает первым аргументом полное имя файла (с путём, абсолютным или относительным), вторым - режим, в котором мы откроем файл
Режим | Обозначение |
---|---|
'r' | открытие на чтение (является значением по умолчанию). |
'w' | открытие на запись, содержимое файла удаляется, если файла не существует, создается новый. |
'x' | открытие на запись, если файла не существует, иначе исключение. |
'a' | открытие на дозапись, информация добавляется в конец файла. |
'b' | открытие в двоичном режиме. |
't' | открытие в текстовом режиме (является значением по умолчанию). |
'+' | открытие на чтение и запись |
По умолчанию файл открывается в режиме rt - для чтения в текстовом формате.
Стоит заметить, что файл можно открыть в двух разных форматах: текстовом и бинарном (двоичном). Файлы, открытые в текстовом формате (по умолчанию, или явно добавляя “t” к аргументу режима), обрабатываются Python-ом и возвращаются как строки. При открытии файла в бинарном формате никакой обработки содержимого не производится, содержимое возвращается побайтово.
Таким образом, если мы хотим открыть файл в двоичном формате для записи, надо использовать режим “wb”, если мы хотим дописать содержимое в конец файла в текстовом формате, то - “a” или “at”, “r+b” - открыть двоичный файл на чтение и запись.
Обычно, файлы, в которых содержится текст, например, файлы txt , код вашей программы, файлы формата csv , открываются в текстовом формате, а файлы, которые нельзя проинтерпретировать как текст - в бинарном (например, картинки, музыку). Иногда файлы с текстом открывают в бинарном режиме, для более явного управления всеми спецсимволами (например табуляция ↹).
При открытии файла в текстовом режиме, также можно указать подходящую кодировку. Например, если в вашем файле содержится текст на русском в utf8, откройте его в этой кодировке:
russian_file = open("russian.txt", "r", encoding="utf8")
Как только файл был открыт и у вас появился файловый объект, вы можете получить следующую информацию о нем:
Атрибут | Значение |
---|---|
file.closed | Возвращает True если файл был закрыт. |
file.mode | Возвращает режим доступа, с которым был открыт файл. |
file.name | Возвращает имя файла. |
У получаемого объекта есть несколько полезных методов, рассмотрим их.
- метод read ( n ) позволяет прочитать следующие n символов файла. Замечу, что можно представить, что в нашем объекте файла есть указатель на текущую читаемую позицию. При открытии файла, она ставится в самое начало. По мере чтения, этот указатель сдвигается. Таким образом, если выполнять read ( n ) несколько раз подряд, мы будем получать не первые n символов, а каждый раз новые, n символов.
Если n явно не указать, то считается весь файл целиком (указатель окажется в самом конце файла). Для использования метода read, файл должен быть открыт в режиме для чтения Примечание: чтобы узнать текущее положение указателя внутри файла, можно воспользоваться методом tell () , а чтобы установить указатель в нужное положение pos , используется метод seek ( pos )
file = open("russian.txt", "r", encoding="utf8") #открыли файл, file.tell() == 0, #т.е указатель стоит в самом начале text = file.read() #считали весь файл
Следует сказать, что открытый в любом режиме файл после его использования нужно обязательно закрывать. Делается это методом close(). Посе его выполнения работа с файлом будет корректно завершена, но с нашим объектом файла работать уже тоже будет нельзя - при необходимости повторной работы с файлом нужно снова его открывать при помощи open.
file = open("some_data.txt") text = file.read() file.close() #дальше работаем с text, если надо
Но вдруг в процессе выполнения нашей программы произройдет критическая ошибка и программа завершит свое выполнение, а мы, например, записывали в файл какую-то информацию? Верно, вполне возможно, что последняя добавленная информация в файл так и не запишется. Чтобы избежать такой ситуации, ну и чтобы просто не забывать вовремя вызывать close() используется конструкция with:
with open("text.txt", "w") as out: #в out теперь находится ссылка на наш объект файла, как если #бы было просто out = open("text.txt", "w") for i in range(100): out.write("А я запишу все эти строки в влюбом случае\n") #записываем 100 одинаковых строчек raise Exception #принудительно "вызываем" ошибку. #Об Exceptionах будет дальше в следующих семинарах #в файле все равно будут все 100 нужные строки
Конструкция with используется для того, чтобы гаранировать, что критические действия будут выполнены в любом случае, ее можно использовать и в некоторых других случаях, но в контексте открытия файлов она используется чаще всего.
Я рекомендую по возможности всегда открывать файлы, не зависимо от режима, с конструкцией with!
Через конструкцию with можно открывать сразу несколько файлов:
with open("input.txt", "r") as input, open("output.txt", "w") as output: output.write(input.read()) #скопировали содержимое input в output
- Чтобы считать из файла целую строку, используется метод readline(max_len). Если указать параметр max_len, то будут считаны максимум max_len символов
with open("text.txt", "r") as file: print(file.readline()) #считали и вывели первую строку файла
На самом деле у нашего объекта файла есть итератор, поэтому перебирать строки внутри файла можно с его помощью:
with open("text.txt", "r") as file: for line in file: print(line)
Такой способ чтения наиболее удобен для построчного чтения
Упражнение 1: создайте произвольный текстовый файл с несколькими строками произвольного текста. Выведите в консоль строки файла, удалив лишние пробелы в начале и конце строк, если они есть
Упражнение 2: запишите в новый файл содержимое списка строк (каждую строку с новой строки) без использования цикла
def write_array(array, file_name): """записывает строки из array в файл file_name""" #ваш код здесь pass
Работа с файловой системой
Взаимодействие с файлами не ограничивается только самими файлами, нам часто приходится работать и с папками. Главными героями этого раздела будут библиотеки os и os.path. Они связаны с операционной системой компьютера и позволяют взаимодейстовать с файловой системой.
Все папки директории
os.listdir(dir) перечисялет файлы и папки в указанной директории dir. Если вызвать эту функцию без аргументов, она вернет файлы и папки текущей рабочей директории.
Текущая папка
Относительные пути строятся относительно текущей папки. Чтобы получить абсолютный путь файла из относительного, используется функция os.path.abspath(file_path). Чтобы узнать, какая папка является текущей, можно вызвать функцию os.getcwd(). Для смены текущей папки используется os.chdir(new_dir).
Проверка существования файла или папки и определение, является ли имя файлом или папкой
os.path.exists(file_name) проверяет, существует ли указанный файл (или директория) file_name.
Чтобы проверить, является ли данное имя name файлом или папкой, можно воспользоваться функциями os.isdir(name) или os.isfile(name), которые возвращают True или False.
Рекурсивный обход папок
Одной из самых интересных и мощных функций является функция os.walk(dir) - она позволяет рекурсивно пройтись по всем папкам, подпапкам, их подпапкам и так далее. На самом деле она возвращает генератор (последовательность элементов). Каждый элемент представляеьт собой кортеж из 3х элементов. Первый элемнт - строковое представление директории текущей директории, которую просматривает функция. Вторым элементом - список всех подпапок данной директории, а третьим - список всех файлов этой директории.
for current_dir, dirs, files in os.walk("."): #передаем в качестве аргумента текущую директорию #("." - означает именно ее) print(current_dir, dirs, files) #выведем, что получается
Копирование файлов
Копировать файлы можно при помощи функции copy из модуля shutil
shutil.copy("input.txt", "output.txt")
Копировать папки можно с помощью copytree из того же модуля:
shutil.copytree("test", "test/test2") #Скопирует папку test внутрь неё самой же в подпапку test2
Многие другие функции для работы с файлами и папками вы сможете найти в модулях os и shutil. Теперь вы знаете, где искать нужный функционал 😉
Упражнение 3: Вам дана в архиве файловая структура, состоящая из директорий и файлов.
Вам необходимо распаковать этот архив (средствами языка python), и затем найти в данной в файловой структуре все директории, в которых есть хотя бы один файл с расширением “.py”.
Ответом на данную задачу будет являться файл со списком таких директорий, отсортированных в лексикографическом порядке.
Распространенные форматы текстовых данных
csv
csv является табличным форматом. В нем содержатся значения разделенные запятой (Comma-Separated Values). Например,
first name,last name,module1,module2,module3 Nikolay,Neznaev,0,20,10 Stepan,Sharyashiy,100,99.5,100
Для работы с csv файлами можно воспользоваться библиотекой csv:
import csv with open("example.csv", "r") as file: reader = csv.reader(file) #На основе открытого файла получаем объект из библиотеки csv for row in reader: print(row) #Каждая строка - список значений
В csv.reader параметром delimeter можно передать разделитель значений, таким образом разделяющим символом в файле csv может быть не только запятая.
Для изолирования некоторых значений можно пользоваться двойными кавычками. Библиотека csv учитывает различные мелочи, такие как строки с содержащимися в ней запятыми и переносами строки, различные разделители, поэтому ее использование целесообразнее splitа по разделителю.
Для записи значений в csv формате используется csv.writer:
import csv students = [ ["Greg", "Lebovskiy", 70, 80, 90, "Good job, Greg!"], ["Nick", "Shalopaev", 10, 50, 45, "Shalopaev, you should study better!"] ] with open("example.csv", "a") as file: writer = csv.writer(file) #На основе открытого файла получаем объект из библиотеки csv for student in students: writer.writerow(student) #Записываем строку #Вместо цикла выше мы могли сразу записать все через writer.writerows(students)
JSON
JSON (JavaScript Object Notation) - простой формат обмена данными, удобный для чтения и написания как человеком, так и компьютером. Впервые он был придуман и использован в JavaScript для хранения структур и классов, но быстро обео свою популярность и вышел за пределы своего родителя.
JSON основан на двух структурах данных: * Коллекция пар ключ/значение. В разных языках, эта концепция реализована как объект, запись, структура, словарь, хэш, именованный список или ассоциативный массив. * Упорядоченный список значений. В большинстве языков это реализовано как массив, вектор, список или последовательность.
Это универсальные структуры данных. Почти все современные языки программирования поддерживают их в какой-либо форме. Логично предположить, что формат данных, независимый от языка программирования, должен быть основан на этих структурах.
Объекты в формате SJON хранятся как словари в Python, но с некоторыми деталями: во первых, ключом в json-объекте может быть только строка, значения True и False пишутся с маленькой буквы, значению None соответствует значение null, строки хранятся только внутри двойных кавычек.
Для удобной работы с json файлами в языке python можно использовать библиотеку json
import json student1 = "full_name" : "Greg Martin", "scores" : [100, 85, 94], "certificate" : True, "comment": "Great job, Greg!" > student2 = "full_name" : "John Price", "scores" : [0, 10, 0], "certificate" : False, "comment": "Guns aren't gonna help you here, captain!" > data = [student1, student2] print(json.dumps(data, indent=4, sort_keys=True)) #Делаем отступы в 4 пробела, сортируем ключи в алфавитном порядке
Для получения строкового представления объекта в формате json можно использовать json.dumps(data, **parrams) с различными вспомогательными настройками (пробелы, сортировка и др.)
Для записи в файл можно воспользоваться json.dump(data, file_obj, **params):
with open("output.json", "w") as out: json.dump(data, out, indent=4, sort_keys=True)
Для получения объекта python на основе его срокового представления можно воспользоваться функцией json.loads или json.load для считывания из файла:
json_str = json.dumps(data, indent=4, sort_keys=True) #получение строкового представления json data_again = json.loads(json_str) #получаем объект python print(sum(data_again[0]["scores"])) #убедимся в кореектном считывании: #посчитаем сумму баллов у первого студента with open("output.json") as file: data_from_file = json.load(file) #считаем объект из файла print(sum(data_from_file[0]["scores"])) #аналогично посчитаем сумму баллов
При записи-считывнии объектов из формата json кортежи превращаются в списки # Исключения (материал ниже взят с сайта https://pythonworld.ru/tipy-dannyx-v-python/isklyucheniya-v-python-konstrukciya-try-except-dlya-obrabotki-isklyuchenij.html )
Исключения (exceptions) - ещё один тип данных в python. Исключения необходимы для того, чтобы сообщать программисту об ошибках.
Самый простейший пример исключения - деление на ноль:
100 / 0 Traceback (most recent call last): File "", line 1, in 100 / 0 ZeroDivisionError: division by zero
Разберём это сообщение подробнее: интерпретатор нам сообщает о том, что он поймал исключение и напечатал информацию (Traceback (most recent call last)).
Далее имя файла (File ""). Имя пустое, потому что мы находимся в интерактивном режиме, строка в файле (line 1);
Выражение, в котором произошла ошибка (100 / 0).
Название исключения (ZeroDivisionError) и краткое описание исключения (division by zero).
Разумеется, возможны и другие исключения:
2 + '1' Traceback (most recent call last): File "", line 1, in 2 + '1' TypeError: unsupported operand type(s) for +: 'int' and 'str' int('qwerty') Traceback (most recent call last): File "", line 1, in int('qwerty') ValueError: invalid literal for int() with base 10: 'qwerty'
В этих двух примерах генерируются исключения TypeError и ValueError соответственно. Подсказки дают нам полную информацию о том, где порождено исключение, и с чем оно связано.
Рассмотрим иерархию встроенных в python исключений, хотя иногда вам могут встретиться и другие, так как программисты могут создавать собственные исключения. Данный список актуален для python 3.3, в более ранних версиях есть незначительные изменения.
- BaseException - базовое исключение, от которого берут начало все остальные.
- SystemExit - исключение, порождаемое функцией sys.exit при выходе из программы.
- KeyboardInterrupt - порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
- GeneratorExit - порождается при вызове метода close объекта generator.
- Exception - а вот тут уже заканчиваются полностью системные исключения (которые лучше не трогать) и начинаются обыкновенные, с которыми можно работать.
- StopIteration - порождается встроенной функцией next, если в итераторе больше нет элементов.
- ArithmeticError - арифметическая ошибка.
- FloatingPointError - порождается при неудачном выполнении операции с плавающей запятой. На практике встречается нечасто.
- OverflowError - возникает, когда результат арифметической операции слишком велик для представления. Не появляется при обычной работе с целыми числами (так как python поддерживает длинные числа), но может возникать в некоторых других случаях.
- ZeroDivisionError - деление на ноль.
- IndexError - индекс не входит в диапазон элементов.
- KeyError - несуществующий ключ (в словаре, множестве или другом объекте).
- UnboundLocalError - сделана ссылка на локальную переменную в функции, но переменная не определена ранее.
- BlockingIOError
- ChildProcessError - неудача при операции с дочерним процессом.
- ConnectionError - базовый класс для исключений, связанных с подключениями.
- BrokenPipeError
- ConnectionAbortedError
- ConnectionRefusedError
- ConnectionResetError
- IndentationError - неправильные отступы.
- TabError - смешивание в отступах табуляции и пробелов.
- UnicodeEncodeError - исключение, связанное с кодированием unicode.
- UnicodeDecodeError - исключение, связанное с декодированием unicode.
- UnicodeTranslateError - исключение, связанное с переводом unicode.
Теперь, зная, когда и при каких обстоятельствах могут возникнуть исключения, мы можем их обрабатывать. Для обработки исключений используется конструкция try - except.
Первый пример применения этой конструкции:
try: k = 1 / 0 except ZeroDivisionError: k = 0 print(k)
В блоке try мы выполняем инструкцию, которая может породить исключение, а в блоке except мы перехватываем их. При этом перехватываются как само исключение, так и его потомки. Например, перехватывая ArithmeticError, мы также перехватываем FloatingPointError, OverflowError и ZeroDivisionError.
try: k = 1 / 0 except ArithmeticError: k = 0 print(k)
Также возможна инструкция except без аргументов, которая перехватывает вообще всё (и прерывание с клавиатуры, и системный выход и т. д.). Поэтому в такой форме инструкция except практически не используется, а используется except Exception. Однако чаще всего перехватывают исключения по одному, для упрощения отладки (вдруг вы ещё другую ошибку сделаете, а except её перехватит).
Ещё две инструкции, относящиеся к нашей проблеме, это finally и else. Finally выполняет блок инструкций в любом случае, было ли исключение, или нет (применима, когда нужно непременно что-то сделать, к примеру, закрыть файл). Инструкция else выполняется в том случае, если исключения не было.
f = open('1.txt') ints = [] try: for line in f: ints.append(int(line)) except ValueError: print('Это не число. Выходим.') except Exception: print('Это что ещё такое?') else: print('Всё хорошо.') finally: f.close() print('Я закрыл файл.') # Именно в таком порядке: try, группа except, затем else, и только потом finally.
Чтобы в своей программе вызвать исключение надо воспользоваться командой raise.
Чтобы создать свое собственное исключение, надо унаследоваться от одного из уже существующих классов исключения:
class MyException(Exception): #создали свой класс. Ничего переопределять не обязательно pass raise MyException("My hovercraft is full of eels") #поднятие исключения
Сайт построен с использованием Pelican. За основу оформления взята тема от Smashing Magazine. Исходные тексты программ, приведённые на этом сайте, распространяются под лицензией GPLv3, все остальные материалы сайта распространяются под лицензией CC-BY.