Разработка расширений на 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
Организация файлов на компьютере может быть утомительной задачей, особенно когда это делается вручную. Некоторые папки (например, папка «Загрузки») на компьютере часто забиты так, что мы не всегда можем найти то что нам нужно. В данной статье Вы узнаете как с помощью языка Python и его встроенных средств организовать размещение файлов по папкам в соответствии с их расширениями.
И так, давайте начнем. Как мы уже сказали выше, нам не понадобится для установки ничего, кроме стандартной библиотеки Python 3. Импортируем модули:
import os
import glob
import shutil
Мы будем использовать функцию shutil.move() из модуля shutil для перемещения файлов, и нам также понадобится модуль globe, чтобы получить список совпадающих файлов с помощью регулярного выражения. Мы также используем модуль os для обработки имен файлов.
Поскольку мы собираемся упорядочивать файлы по расширению, имеет смысл размещать файлы одного типа (например, mp3, wav) в одной папке (например, «аудио»). Ниже словарь Python сопоставляет каждое расширение с типом.:
extensions = «jpg»: «изображения»,
«png»: «изображения»,
«ico»: «изображения»,
«gif»: «изображения»,
«svg»: «изображения»,
«sql»: «SQL_»,
«exe»: «Программы»,
«msi»: «Программы»,
«pdf»: «pdf»,
«xlsx»: «Эксель»,
«csv»: «Эксель»,
«rar»: «Архивы»,
«zip»: «Архивы»,
«gz»: «Архивы»,
«tar»: «Архивы»,
«docx»: «ВОРД»,
«txt»: «Текст»,
«py»: «python»,
«pptx»: «powerpoint»,
«ppt»: «powerpoint»,
«mp3»: «аудио»,
«wav»: «аудио»,
«mp4»: «видео»,
«m3u8»: «видео»,
«webm»: «видео»,
«ts»: «видео»,
«json»: «json»,
«css»: «web»,
«js»: «web»,
«html»: «web»,
«apk»: «apk»,
«sqlite3»: «sqlite3»,
>
Так, файлы mp4 и m3u8 будут помещены в папку видео и так далее. Данный список не окончателен и может быть расширен.
Перейдем к следующему фрагменту кода.
# путь к целевой папке
path = r»С:\Downloads»
verbose = 1
for extension, folder_name in extensions.items():
# найдем все файлы подходящие по расширению
files = glob.glob(os.path.join(path, f»*.»))
print(f»[*] Найдено файлов с расширением»)
if not os.path.isdir(os.path.join(path, folder_name)) and files:
# создание новой директории
print(f»[+] Создание папки «)
os.mkdir(os.path.join(path, folder_name))
for file in files:
# Для каждого файла с соответствующим расширением помещаем его в нужную папку
basename = os.path.basename(file)
dst = os.path.join(path, folder_name, basename)
if verbose:
print(f»[*] перемещение в «)
shutil.move(file, dst)
Мы перебираем наш словарь, который сопоставляет каждое расширение с типом файла, получаем список файлов каждого расширения и перемещаем их в соответствующую папку. Мы также создаем папку с помощью функции os.mkdir(), если она ранее не существовала.
Переменная path — это путь к папке, которую вы хотите упорядочить, вы можете использовать модули sys или argparse для передачи пути к папке через cmd.
»’
вывод:
[+] Найдено 0 файлов с расширением .jpg
[+] Найдено 2 файлов с расширением .png
[+] Создаем папки изображения
[+] Найдено 0 файлов с расширением .ico
[+] Найдено 0 файлов с расширением .gif
»’

Если теперь понадобится найти или удалить нужный файл в какой либо папке, то Python3 и его стандартная библиотека существенно упростят нашу задачу.

![]()
Создано 14.12.2021 08:47:08
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
- Кнопка:
Она выглядит вот так: - Текстовая ссылка:
Она выглядит вот так: Как создать свой сайт - BB-код ссылки для форумов (например, можете поставить её в подписи):
Комментарии ( 0 ):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2023 Русаков Михаил Юрьевич. Все права защищены.
Шпаргалка по форматам файлов с данными в python
Python понимает все популярные форматы файлов. Кроме того, у каждой библиотеки есть свой, «теплый ламповый», формат. Синтаксис, разумеется, у каждого формата сугубо индивидуален. Я собрал все функции для работы с файлами разных форматов на один лист A4, с приложением в виде примера использования в jupyter notebook.

Я условно разделил форматы на три блока по способу использования. Как известно, файлы нужны для обмена информацией: между людьми, между программами (первый блок), между компьютером и сетью (второй) и «save game» – между одной и той же программой в разные моменты времени (третий блок).
Вкратце о каждом блоке:
1) Универсальные форматы:
- .csv – текстовый, значения, разделённые по идее запятыми (comma separated), но например, русский эксель предпочитает разделять точками с запятыми, поскольку в русской локали запятая уже используется – в качестве десятичного разделителя;
- .raw – бинарный формат для тех, кто не любит форматы файлов. Тип данных и, если данные многомерные, соответствующие размеры должны передаваться отдельно, в файле только сами данные;
- .xls/.xlsx – старый бинарный (ограничение в 65k строк) и новый xml’ный форматы экселя;
- .mat – это на самом деле тоже два формата (оба бинарные): старый проприетарный и новый на основе hdf5. Питон умеет работать с обоими (через библиотеки).
- .json – текстовый, выглядит как словарь в питоне, но кавычки можно использовать только двойные;
- .xml – текстовый, похож на html.
- .pkl – бинарный формат, в него умеют сохраняться все встроенные питоновские объекты. Пользовательские классы тоже умеют, а если питон сохраняет как-то не так, можно ему помочь через магические методы. Поддерживает дописывание в конец существующего файла (appending).
- .npy и .npz – в numpy аж целых два своих формата (оба бинарные). Появились как реакция на потерю обратной совместимости у pkl в момент перехода python v2->v3. Накладные расходы минимальные (~ на 100 байт больше, чем соответствующий raw; pkl, впрочем, немногим больше: на ~150 байт больше raw). В .npy можно сохранить только один массив, а в npz – сразу несколько, причём достать их оттуда впоследствии можно по имени.
- .h5 – бинарный формат hdf5. Примечателен тем, что в нем можно хранить целую иерархическую структуру данных, это практически файловая система в одном файле. Кроме того, его можно открыть в matlab без конвертации. Минусы:
a) небольшие файлы занимают неоправданно много места (например, 300 байт pkl vs 3.1 Мb у h5),
b) много багов,
c) есть дописывание в существующий файл, но если при этом случится ошибка (а так бывает), данные из него достать будет проблематично.

– в формате pdf
– в формате png:
Пример использования всех функций с диаграммы: html с оглавлением и ipynb-исходником
Работа с файлами в Python
Многим из нас знакома ситуация, когда компьютер оказывался завален тоннами беспорядочных файлов. Только что вы открывали большой zip-архив, спустя мгновение – файлы повсюду в этой директории, вперемешку с важными документами. Наверняка приходилось мучительно скучно сортировать эту свалку вручную? Чтобы облегчить подобные задачи, мы сейчас погрузимся в «умную» работу с файлами при помощи Python.
Итак, приступим, вооружившись Python версии 3.4 или выше. Сначала пройдемся по модулю OS, а по ходу дела познакомимся еще с несколькими. Всё, что мы будем использовать, доступно в Python «с коробки», так что ничего дополнительно устанавливать не потребуется.
Генератор случайных файлов
Создадим папку ManageFiles , а внутри нее еще одну — RandomFiles . Дерево каталогов теперь должно выглядеть вот так:
ManageFiles/ | |_RandomFiles/
Чтобы поиграться с файлами, мы сгенерируем их случайным образом в директории RandomFiles . Создайте файл create_random_files.py в папке ManageFiles . Вот что должно получиться:
ManageFiles/ | |_ create_random_files.py |_RandomFiles/
Готово? Теперь поместите в файл следующий код, и перейдем к его рассмотрению:
import os from pathlib import Path import random list_of_extensions = ['.rst', '.txt', '.md', '.docx', '.odt', '.html', '.ppt', '.doc'] # перейти в папку RandomFiles os.chdir('./RandomFiles') for item in list_of_extensions: # создать 20 случайных файлов для каждого расширения имени for num in range(20): # пусть имя файла начинается со случайного числа от 1 до 50 file_name = random.randint(1, 50) file_to_create = str(file_name) + item Path(file_to_create).touch()
Начиная с Python 3.4 мы получили pathlib, нашу маленькую волшебную палочку. Также мы импортируем функцию random для генерации случайных чисел, но ее мы посмотрим в действии чуть ниже.
Сперва создадим список файловых расширений для формирования названий файлов. Не стесняйтесь добавить туда свои варианты.
Далее мы переходим в папку RandomFiles и запускаем цикл. В нем мы просто говорим: возьми каждый элемент list_of_extensions и сделай с ним кое-что во внутреннем цикле 20 раз.
Теперь пришло время для импортированной функции random . Используем ее для производства случайных чисел от 1 до 50. Это просто не очень творческий способ побыстрее дать названия нашим тестовым файлам: к сгенерированному числу добавим расширение файла и получим что-то вроде 23.txt или 14.txt . И так 20 раз для каждого расширения. В итоге образуется беспорядок, достаточный для того, чтобы его было лень сортировать вручную.
Итак, запустим наш генератор хаоса через терминал.
python create_random_files.py
Поздравляю, теперь у нас полная папка неразберихи. Будем распутывать.
В той же директории, где create_random_files.py , создадим файл clean_up.py и поместим туда следующий код.
Способ 1
import os import shutil import glob # перейти в папку RandomFiles os.chdir('./RandomFiles') # получить список файлов в папке RandomFiles files_to_group = [] for random_file in os.listdir('.'): files_to_group.append(random_file) # получить все расширения имен всех файлов file_extensions = [] for our_file in files_to_group: file_extensions.append(os.path.splitext(our_file)[1]) print(set(file_extensions)) file_types = set(file_extensions) for type in file_types: new_directory = type.replace(".", " ") os.mkdir(new_directory) # создать папку с именем данного расширения for fname in glob.glob(f'*.'): shutil.move(fname, new_directory)
Для этого импортируем еще две библиотеки: shutil и glob. Первая поможет перемещать файлы, а вторая – находить и систематизировать. Но обо всем по порядку.
Для начала получим список всех файлов в директории.
Здесь мы предполагаем, что у нас нет ни малейшего понятия о том, какие именно файлы лежат в этой папке. Вместо того, чтобы вписывать все расширения вручную и использовать лестницу инструкций if или switch, мы желаем, чтобы программа сама просмотрела каталог и определила, на какие типы можно разделить его содержание. Что, если бы там были файлы с десятками расширений или логи? Вы бы стали описывать их вручную?
Получив список всех файлов, мы заходим в еще один цикл, чтобы извлечь расширения названий.
os.path.splitext(our_file)[1]
Сейчас наша переменная our_file выглядит как-нибудь так: 5.docx . Когда разделим ее, получим следующее:
`('5', '.docx')`
Мы возьмем отсюда второй элемент по индексу [1], то есть .docx . Ведь по индексу [0] у нас располагается 5 .
Таким образом, у нас имеется список всех файловых расширений в папке, в том числе повторяющихся. Чтобы оставить только уникальные элементы, преобразуем его во множество. К примеру, если бы этот список состоял исключительно из .docx , повторяющегося снова и снова, то в set остался бы всего один элемент.
# создать множество и присвоить его переменной file_types = set(file_extensions)
Заметим, что в списке типов файлов каждое расширение содержит . в начале. Если мы назовем так папки на UNIX-системе, то они будут скрытыми, что не входит в наши намерения.
Поэтому, итерируя по нашему множеству, мы заменяем точку на пустую строку. И создаем папку с полученным названием.
new_directory = type.replace(".", " ") # наша директория теперь будет называться "docx"
Но чтобы переместить файлы, нам все еще нужно расширение .docx .
for fname in glob.glob(f'*.')
Этим попросту отбираем все файлы, оканчивающиеся расширением .docx . Заметьте, что в f’*.’) нет пробелов.
Символ подстановки * обозначает, что подходит любое имя, если оно заканчивается на .docx . Поскольку мы уже включили точку в поиск, мы используем [1:], что значит «все после первого символа». В нашем примере это docx .
Что дальше? Перемещаем любые файлы с данным расширением в директорию с тем же названием.
shutil.move(fname, new_directory)
Таким образом, как только в цикле создана папка для первого попавшегося файла с данным расширением, все последующие файлы будут отправлены в нее же. Все будет сгруппировано без повторения каталогов.
Способ 2
В качестве хитрого способа создать список в одну строку можно использовать генераторы.
import os import shutil import glob # перейти в папаку RandomFiles os.chdir('./RandomFiles') # добавить все файлы в данной папке в список all_files = [x for x in os.listdir('.')] # создать множество расширений имен файлов в этой папке file_types = set((os.path.splitext(f)[1] for f in all_files)) for ftype in file_types: new_directory = ftype.replace(".", '') os.mkdir(new_directory) for fname in glob.glob(f'*.'): shutil.move(fname, new_directory)
Оба варианта сработают, и все ваши файлы будут отсортированы по расширению.
ManageFiles/ | |_create_random_files.py |_RandomFiles/ |_doc |_docx |_html |_md |_odt |_ppt
Вот и все. Если вам когда-либо понадобится отсортировать файлы таким образом, вы сэкономите немало времени ?. Код упражнения доступен здесь.
