Тарифы Услуги Сим-карты

Комментарии в Python; Форматирование строк: Операторы форматирования и метод format()

Недавно узнал, что блог время от времени находят по запросу "что означает %s в python". Вспоминаю себя – когда я начинал изучать Python, мне хотелось быстрых и понятных ответов (мол, "не морочь голову, пальцем покажи"). Для таких нетерпеливых эта статья.

Оглавление

Для начала несколько примеров

Форматирование строк:
>>> name = "Vasya" >>> print "My name is %s" % (name) My name is Vasya С указанием размера полей (перед "Vasya" стоит пять пробелов, т.е. всего десять символов): >>> print "My name is %10s. That"s my name." % (name) My name is Vasya. That"s my name. То же самое, но выровненное по левому краю: >>> print "My name is %-10s. That"s my name." % (name) My name is Vasya . That"s my name. Когда это может быть полезно: >>> drinks = {"Long Island": 3, "Bloody Mary": 2, "Margarita":4} >>> print "%-15s%-5s" % ("Name", "Qty") Name Qty >>> for k,v in drinks.items(): ... print "%-15s%-3s" % (k, v) ... Bloody Mary 2 Long Island 3 Margarita 4 Если понадобится вывести целую часть числа:
>>> num = 12.34 >>> print "%d" % (num) 12 Вперемешку:
>>> age = 25 >>> print "My name is %s. I"m %d." % (name, age) My name is Vasya. I"m 25.

Теперь вкратце как работает оператор %

Выражение форматирования можно условно разделить на три части:

Определение_формата + % + объект(ы)

Обозначения %s, %d, %g и т. п. - это форматы типов данных. Если вы знакомы с языком Си, то это тот же синтаксис, что используется для вывода на печать printf() .

Спецификации различных типов данных Python приведены в следующей таблице:

Формат Значение
"d" Целое десятичное число.
"i" Целое десятичное число.
"o" Восьмеричное число.
"u" Устаревший тип – то же что "d" .
"x" Шестнадцатеричное число (нижний регистр).
"X" Шестнадцатеричное число (верхний регистр).
"e" Вещественное число в экспоненциальном виде (нижний регистр).
"E" Вещественное число в экспоненциальном виде (верхний регистр).
"f"
"F" Вещественное число в десятичном виде.
"g" Вещественное число. Использует формат "f" или "e" в нижнем регистре.
"G" Вещественное число. Использует формат "F" или "E" в верхнем регистре.
"c" Один символ (или цифра).
"r" repr() .
"s" Строка, в которую любой объект Python конвертируется с помощью str() .
"%" Аргумент не конвертируется, выводится просто символ "%" .

Встроенная функция format()

Работает так: str.format()

В строке "поля для замены" заключаются в фигурные скобки {} . Все, что не заключено в скобки, воспринимается как обычный текст, которые копируется в неизменном виде. Чтобы передать в тексте символы фигурных скобок, их дублируют: {{ и }} .
Поля для замены форматируются следующим образом:

Поле_для_замены::= "{" [имя_поля] ["!" конверсия] [":" спецификация] "}" имя_поля::= имя_аргумента ("." имя_атрибута | "[" номер_элемента "]")* имя_аргумента::= [идентификатор | integer] имя_атрибута::= идентификатор индекс_элемента::= integer | строковый индекс строковый_индекс::= <любой символ кроме "]"> + конверсия::= "r" | "s" # str или repr спецификация::= <описано ниже> где
спецификация::= [[заглушка]выравнивание][знак][#][ширина][,][.точность][тип] заглушка::= <любой символ> выравнивание::= "<" | ">" | "=" | "^" знак::= "+" | "-" | " " ширина::= integer # ширина поля точность::= integer # знаки после десятичной запятой тип::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" Записывается так: >>> print """\n{0} ... Сидел на стене... {0} ... Свалился во сне.""".format("Шалтай-Болтай") Шалтай-Болтай Сидел на стене Шалтай-Болтай Свалился во сне.

Как видите, этот способ гораздо гибче оператора "%", так как одни и те же значения мы можем использовать повторно и в любом порядке. Также можно передать именованные аргументы, и тогда обращаться к ним будем не по номерам, а по именам.

Еще пример форматирования:

>>> toc = (... ("Первая глава", "3"), ... ("Вторая глава", "150") ...) >>> for line in toc: ... print("{:.

Комментарии

На этой стадии, мы владеем уже достаточно обширным набором инструментария и можем писать достаточно "запутанный" код. После написания кода в несколько десятков строк, уже через несколько дней, его будет достаточно сложно прочесть. Другим же людям, будет его прочесть еще сложнее.
А если представить, что в крупных проектах мегабайты текстовых файлов с кодом, то они становятся еще более сложно читаемыми. Эту ситуацию спасают комментарии внутри кода. Эти комментарии, программисты оставляют для того, чтобы со временем, они могли прояснить тот или иной фрагмент кода и описать, какие-то действия, происходящие в определенных частях программного кода. Для ваших коллег и для вас же - это значительно облегчит читаемость кода.

В питоне различают два типа комментариев: Однострочный и многострочный. Однострочный комментарий начинается с символа "#", может быть как в отдельной строке, так и оканчивать строку с кодом, но обязательно должен быть однострочным, Т.Е. Не должен разбиваться на две строки. Он может оканчивать строку с кодом, но не может находиться в середине строки между двух частей кода. Кпримеру:

i = 0 # Счетчик для цикла

# Цикл будет выполняться исходя из условия выше

Многострочные комментарии заключаются в тройные кавычки""". Они могут разбиваться на несколько строк и быть достаточно длинными. По-факту, хоть сочинение пишите. Многострочный комментарий должен начинаться с новой строки и может продолжаться в других строках. Кпримеру:

"""Обходим список для нахождения необходимого элемента

После нахождения, обрываем цикл и сохраняем результат в переменную x

Если необходимый элемент найден небудет, сообщаем про это пользователю"""

Обратите внимание, однострочный комментарий, обязан начинаться с таким же отступом, как и код соответствующего блока, в противном случае будет трекбек. Также и многострочный комментарий, должен начинаться с соответствующим блоку кода отступом. Последующие строки комментария уже не требуют сохранять отступ, отступ должен быть только перед открывающими комментарий кавычками """.

Начинающие программисты, да и не только начинающие, часто пишут в комментариях очевидные вещи, что-то вроде "Я объявил тут переменную x". Пытайтесь избегать комментариев, которые дублируют произведенное действие человеческим языком. Перед написанием комментария, попробуйте задавать себе такие вопросы: "Для чего служит этот фрагмент?", "Какую цель я приследую этим фрагментом кода?", "Что я делаю при помощи этого фрагмента кода?", "Что в этом фрагменте неочевидно?"... Подобный ряд вопросов, поможет сконструировать правильный комментарий, который действительно поможет сопровождать код в будущем и сделает его более читаемым.

Операторы форматирования строки

Сейчас под выражением "форматирование строки", мы имеем ввиду разворачивание значений переменных в строке, Т.Е. КОгда есть необходимость в какой-тро строке, вставить значения каких-то переменных. Ранее мы делали это при помощи "+" - соединения строк и "," запись численных выражений после строк. Выглядело это, как минимум, некрасиво.

>>> a = "Hello"

>>> b = "dear"

>>> a + " " + b

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

Давайте рассмотрим следующий вариант:

>>> a = "Vasya"

>>> print "Привет %s" % a

Привет Vasya

Что происходит? Все достаточно просто. Оператор %s в нашей строке, заменяется на переменную, которая стоит справа от знака % после нашей строки.

Давайте рассмотрим еще один пример:

>>> name = "Vasya"

>>> lastname = "Pupkin"

>>> age = 25

>>> print "Имя %s, фамилия %s, возраст %d" % (name,lastname,age)

Имя Vasya, фамилия Pupkin, возраст 25

Во-первых обратите внимание, что если переменных более одной, мы передаем их в кортеже (). Также вы могли заметить, что строчные значения переменных, я передал при помощи оператора %s, а переменную ссылающуюся на число, при помощи оператора %d. Это работает только так. Каждый оператор может развернуть значение определенного типа: %s - строку, %d - число и Т.Д. Более подробный список операторов, будет приведен ниже.

Первый вопрос, который напрашивается сам собой: "Как нам вывести значение одной переменной несколько раз в одной строке?". Ответ очевиден, нам прийдется передать эту переменную в кортеже столько раз и в том порядке, в котором мы разворачиваем значения этих переменных в нашей строке. Это топорно и неудобно. Мы всегда должны записывать переменные в строгом порядке, который будет соответствовать разворачиванию их операторами в строке, да еще и повторять их при необходимости.

Список операторов форматирования:

"%d", "%i", "%u"

Десятичное число.

Число в восьмеричной системе счисления.

Число в шестнадцатеричной системе счисления (буквы в нижнем регистре).

Число в шестнадцатеричной системе счисления (буквы в верхнем регистре).

Число с плавающей точкой с экспонентой (экспонента в нижнем регистре).

Число с плавающей точкой с экспонентой (экспонента в верхнем регистре).

Число с плавающей точкой (обычный формат).

Число с плавающей точкой. с экспонентой (экспонента в нижнем регистре), если она меньше, чем -4 или точности, иначе обычный формат.

Число с плавающей точкой. с экспонентой (экспонента в верхнем регистре), если она меньше, чем -4 или точности, иначе обычный формат.

Символ (строка из одного символа или число - код символа).

Строка (литерал python).

Строка (как обычно воспринимается пользователем).

Операторы форматирования (дополнительно)

Тут я коротко продемонстрирую дополнительные возможности операторов форматирования.

Спецификаторы преобразования записываются в следующем порядке:

2. Ключ (опционально), определяет, какой аргумент из значения будет подставляться.

3. Флаги преобразования.

4. Минимальная ширина поля. Если *, значение берётся из кортежа.

5. Точность, начинается с ".", затем - желаемая точность.

6. Модификатор длины (опционально).

7. Тип (см. таблицу выше).

>>> print ("%(language)s has %(number)03d quote types." % {"language": "Python", "number": 2})

Python has 002 quote types.

Флаги преобразования:

Значение будет использовать альтернативную форму.

Свободное место будет заполнено нулями.

Свободное место будет заполнено пробелами справа.

Свободное место будет заполнено пробелами слева.

>>> "%.2s" % "Hello!"

>>> "%.*s" % (2, "Hello!")

>>> "%-10d" % 25

>>> "%+10f" % 25

>>> "%+10s" % "Hello"

Более подробно разбирать эти возможности не имеет смысла, ввиду их редкого использования.

Метод форматирования строк format()

На смену операторам форматирования, кнам пришел строчный метод format() . Этот метод куда более гибкий, удобный и многогранный в использовании. Давайте рассмотрим его применение для разворачивания значений переменных в строке.

>>> name = "Vasya"

>>> lastname = "Pupkin"

>>> age = 25

>>> print "{} {}, возраст {}".format(name,lastname,age)

Vasya Pupkin, возраст 25

Тут все достаточно очевидно. Фигурные скобочки {}, определяют места развертывания переменных в строке, а методу format(), мы передаем переменные, которые нужно разворачивать. На первый взгляд, ничего по сравнению с операторами форматирования не изменилось. Мы попрежнему неможем никак управлять нашим разворачиванием. Разница только в том, что нам уже ненужно запоминать кучку операторов, для разворачивания значений разных типов. Ничего, это только начало. Давайте наращивать функционал последовательно. Давайте рассмотрим следующий вариант:

>>> name = "Vasya"

>>> lastname = "Pupkin"

>>> age = 25

>>> print "{0} {1}, возраст {2}".format(name,lastname,age)

Vasya Pupkin, возраст 25

Ничего не изменилось, но в наших фигурных скобочках добавились какие-то циферки. Смотрим следующий пример:

>>> print "{1} {0}, возраст {2}".format(name,lastname,age)

Pupkin Vasya, возраст 25

Выводимая строка изменилась, Мы поменяли местами значения. Вы могли заметить, что на не пришлось менять местами переменные, которые мы передали в метод, мы просто поменяли цифры в фигурных скобочках {}. Эти цифры, являются своеобразными индексами тех переменных, которые мы хотим развернуть в нашей строке. В последнем примере, мы развернули переменную под индексом 1, потом 0 и 2, Т.Е. Вторую, первую и третью переданные в метод переменные. Это значит, что мы, указывая индексы переменных, которые были переданы в метод, можем разворачивать их в нужном нам порядке. Также, мы можем несколько раз вывести в строке значение одной переменной, несколько раз указав ее индекс в фигурных скобочках.

>>> print "{1} {1}, возраст {2}".format(name,lastname,age)

Pupkin Pupkin, возраст 25

Согласитесь, это уже куда более гибкий и удобный способ форматирования строки, в сравнении с операторами форматирования. Но и на этом гибкость этого метода для разворачивания значений переменных не заканчивается. Давайте рассмотрим вариант, именованных аргументов.

>>> a = "Vasya"

>>> b = "Pupkin"

>>> print "{name} {lastname}, возраст {age}".format(age=c,name=a,lastname=b)

Vasya Pupkin, возраст 25

Тут еще интереснее. Необходимые данные, находились под ничего не говорящими переменными a, b и c. При передаче этих переменных в наш метод, мы дали им осмысленные названия вида (название=переменная), после чего использовали эти названия в наших фигурных скобочках {}.

Методу format, мы можем передавать список значений и разворачивать их внутри нашей строки. Происходит это следующим образом:

>>> l = ["Vasya", "Pupkin", 25]

["Vasya", "Pupkin", 25]

>>> print "{0} {1}, возраст {2}".format(*l)

Vasya Pupkin, возраст 25

Тут все более чем очевидно. Мы передали список и обращались к его элементам по индексам, но при передаче списка, перед переменной, мы указали знак "*", что явно сообщило методу format() о том, что мы будем разворачивать элементы этого списка. Что произойдет, если мы опустим "*", перед указанием аргумента со списком?

>>> print "{0} {1}, возраст {2}".format(l)

Traceback (most recent call last):

File " ", line 1, in

IndexError: tuple index out of range

Метод не знал, что мы передали список и пытался искать в себе обычные аргументы под индексами 1 и 2, к которым мы обращались в строке.

Схожим образом, мы можем передать в метод format() и словарь.

>>> db = {"name":"Vasya", "lastname":"Pupkin", "age":25}

{"lastname": "Pupkin", "age": 25, "name": "Vasya"}

>>> print "{name} {lastname}, возраст {age}".format(**db)

Vasya Pupkin, возраст 25

Это очень похоже на передачу именованных аргументов с той только разницей, что мы передали в наш метод словарь. Если перед передачей списка мы указывали одну звездочку "*", то перед передачей словаря, мы ставим две звездочки "**" перед аргументом в методе format(), а в фигурных скобочках строки, мы обращаемся к ключам переданного словаря, для разворачивания их значений.

Мы рассмотрели все варианты разворачивания переменных в строке, при помощи метода format(). В дальнейшем, я крайне рекомендую использовать этот метод вместо операторов форматирования, Т.К. Этот способ является более новым, гибким и официальные источники, советуют нам придерживаться именно этого метода.

Метод format() (дополнительно)

Далее я приведу дополнительные возможности строчного метода format(). Более обширную информацию про данный метод, вы можете посмотреть в статье на хабре , или в официальной документации по Python.

Внимание! Дальнейшее является фрагментом статьи про метод format()

Снова начнем с простого: если нужно вывести строку заданной длины, то после имени переменной добавляем двоеточие (:) и затем количество символов. Так, чтобы вывести мое имя и дополнить его до десяти символов пробелами я должен делать так:

>>> "Your name is {name:10}".format(name="Reuven")

"Your name is Reuven "

(Обратите внимание что строка дополнена пробелами после имени.)

Если нужно задать выравнивание по правой стороне блока — используется знак > между: и числом:

>>> "Your name is {name:>10}".format(name="Reuven")

"Your name is Reuven"

И да, можно явно указать что я хочу выравнивания по левой стороне с помощью знака <

Если нужно вывести значение в центре блока, то вместо < и > используется символ ^:

>>> "Your name is {name:*^10}".format(name="Reuven")

"Your name is **Reuven**"

С текстом более менее понятно, но что насчет чисел? Лично мне было трудно предположить как это будет работать, но все оказалось достаточно прямолинейно. Для простого вывода чисел используем синтаксис похожий на строки:

>>> "The price is ${number}.".format(number=123)

Начиная с версии 3.6 в Python появился новый тип строк — f-строки , которые буквально означают «formatted string». Эти строки улучшают читаемость кода, а также работают быстрее чем другие способы форматирования. F-строки задаются с помощью литерала «f» перед кавычками.

>>> "обычная строка" >>> f"f-строка"

f-строки - это пятый способ (sic!) форматирования строк в Python, который очень похож на использование метода format().

Вспомним все 5 способов форматирования.

5 способов форматирования строк

1. Конкатенация. Грубый способ форматирования, в котором мы просто склеиваем несколько строк с помощью операции сложения:

>>> name = "Дмитрий" >>> age = 25 >>> print("Меня зовут " + name + ". Мне " + str(age) + " лет.") >>>

2. %-форматирование. Самый популярный способ, который перешел в Python из языка С. Передавать значения в строку можно через списки и кортежи, а также и с помощью словаря. Во втором случае значения помещаются не по позиции, а в соответствии с именами.

>>> name = "Дмитрий" >>> age = 25 >>> print("Меня зовут %s. Мне %d лет." % (name, age)) >>> Меня зовут Дмитрий. Мне 25 лет. >>> print("Меня зовут %(name)s. Мне %(age)d лет." % {"name": name, "age": age}) >>> Меня зовут Дмитрий. Мне 25 лет.

3. Template-строки. Этот способ появился в Python 2.4, как замена %-форматированию (PEP 292), но популярным так и не стал. Поддерживает передачу значений по имени и использует $-синтаксис как в PHP.

>>> from string import Template >>> name = "Дмитрий" >>> age = 25 >>> s = Template("Меня зовут $name. Мне $age лет.") >>> print(s.substitute(name=name, age=age)) >>> Меня зовут Дмитрий. Мне 25 лет.

4. Форматирование с помощью метода format(). Этот способ появился в Python 3 в качестве замены %-форматированию. Он также поддерживает передачу значений по позиции и по имени.

>>> name = "Дмитрий" >>> age = 25 >>> print("Меня зовут {}. Мне {} лет.".format(name, age) >>> Меня зовут Дмитрий. Мне 25 лет. >>> print("Меня зовут {name} Мне {age} лет.".format(age=age, name=name) >>> Меня зовут Дмитрий. Мне 25 лет.

5. f-строки. Форматирование, которое появилось в Python 3.6 (PEP 498). Этот способ похож на форматирование с помощью метода format(), но гибче, читабельней и быстрей.

>>> name = "Дмитрий" >>> age = 25 >>> print(f"Меня зовут {name} Мне {age} лет.") >>> Меня зовут Дмитрий. Мне 25 лет.

Погружене в f-строки

f-строки делают очень простую вещь — они берут значения переменных, которые есть в текущей области видимости, и подставляют их в строку. В самой строке вам лишь нужно указать имя этой переменной в фигурных скобках.

>>> name = "Дмитрий" >>> age = 25 >>> print(f"Меня зовут {name} Мне {age} лет.") >>> Меня зовут Дмитрий. Мне 25 лет.

f-строки также поддерживают расширенное форматирование чисел:

>>> from math import pi >>> print(f"Значение числа pi: {pi:.2f}") >>> Значение числа pi: 3.14

С помощью f-строк можно форматировать дату без вызова метода strftime():

>>> from datetime import datetime as dt >>> now = dt.now() >>> print(f"Текущее время {now:%d.%m.%Y %H:%M}") >>> Текущее время 24.02.2017 15:51

Они поддерживают базовые арифметические операции. Да, прямо в строках:

>>> x = 10 >>> y = 5 >>> print(f"{x} x {y} / 2 = {x * y / 2}") >>> 10 x 5 / 2 = 25.0

Позволяют обращаться к значениям списков по индексу:

>>> planets = ["Меркурий", "Венера", "Земля", "Марс"] >>> print(f"Мы живим не планете {planets}") >>> Мы живим не планете Земля

А также к элементам словаря по ключу:

>>> planet = {"name": "Земля", "radius": 6378000} >>> print(f"Планета {planet["name"]}. Радиус {planet["radius"]/1000} км.") >>> Планета Земля. Радиус 6378.0 км.

Причем вы можете использовать как строковые, так и числовые ключи. Точно также как в обычном Python коде:

>>> digits = {0: "ноль", "one": "один"} >>> print(f"0 - {digits}, 1 - {digits["one"]}") >>> 0 - ноль, 1 - один

Вы можете вызывать в f-строках методы объектов:

>>> name = "Дмитрий" >>> print(f"Имя: {name.upper()}") >>> Имя: ДМИТИРИЙ

А также вызывать функции:

>>> print(f"13 / 3 = {round(13/3)}") >>> 13 / 3 = 4

f-строки очень гибкий и мощный инструмент для создания самых разнообразных шаблонов.

Со всеми возможностя f-строк вы можете ознакомится в PEP498 .

Производительность

F-строки не только гибкие, но и быстрые. И для сравнения производительности разных подходов к форматированию я подготовил два шаблона:

  • простой , в который нужно вставить всего два значения: строку и число;
  • сложный , данные для которого собираются из разных переменных, а внутри происходит преобразование даты, вещественного числа, а также округление.

Финальная простая строка получается такой:

Привет, меня зовут Дмитрий. Мне 27 лет.

Сложная строка на выходе такая:

Сегодня 24.02.2017.
Мы живём на планете Земля. Её радиус 6378 км., а масса 5.973e+24
Период обращения планеты вокруг Солнца 365 дней.
  • Перевод

Предлагаю вниманию читателей хабры и поклонникам python перевод довольно объемной статьи о форматировании строк. Сказка будет правдивой и намек в ней будет на то, что консерваторам стоит иногда рассматривать что-то новое, даже если привычка упорно сопротивляется.

Предугадывая любознательность читателей, склонных задавать вопросы не по теме разговора, скажу, что картинка имеет опосредованное отношение к python, правда не самое приятное. Предлагаю найти почему в качестве домашнего задания.

Жду замечания по ошибкам в оформлении и опечаткам в личку - с меня традиционные хабраплюшки.

Я уже много лет пишу на python. Но в самом начале этого пути мне было интересно узнать как форматировать строки в стиле Perl. Напомню, что Perl (и многие интерпретаторы командной строки в Unix) поддерживают два типа строковых литералов - с одинарными кавычками (когда строка выводится как есть), и двойными где на место переменных подставляются их значения. В Perl, например, можно написать что то вроде:

$name = "Reuven"; print "Hello, $name\n";
И программа, соответственно, напишет «Hello, Reuven».

Строковые литералы в python не зависят от типа кавычек и переменные в них никогда не разворачиваются в свои значения. Чтобы этого добиться традиционно использовался оператор % для строк. В этом контексте оператор смотрит на строку слева от себя и подсчитывает сколько значений нужно заменить на значения соответствующих переменных справа от себя. Результатом операции является новая строка со вставленными на место плейсхолдеров значениями переменных. Например:

>>> name = "Reuven" >>> "Hello, %s" % name "Hello, Reuven"
Этот код на python вполне себе работает и выводит персонализированное приветствие. Так, несмотря на мою многолетнюю практику с python - я был вполне удовлетворен применением этого синтаксиса. Да, он не очень приятный и нет, я никогда не держал в памяти гору модификаторов printf, которые влияют на форматирование. В смысле я всегда использовал модификатор "s" (выводить как строку) и мне было достаточно того, что python неявно приводил аргументы к строке.

Но в данный момент факт, что синтаксис % подлежит списанию или, по крайней мере, объявлен устаревшим. В списке рассылки python-dev есть замечание, что в ветке 2.x он проживет минимум до 2022 года, но ничего не сказано про ветку 3.x, так что поддержка этого синтаксиса будет скоро удалена и применять его нежелательно. На смену ему пришел метод str.format.

В своих уроках по python я всегда упоминал о str.format, но в конкретных примерах чаще все полагался все-таки на %. Я даже рекомендовал студентам использовать % так как лично мне он казался намного проще.

Но стойкое ощущение того, что, я делаю что-то не так и, возможно, даже ввожу в заблуждение своих студентов подвигло меня поближе изучить str.format. В ходе исследования, я пришел к следующим выводам: 1) Он ничуть не сложнее % и даже проще в некоторых вариантах применения; 2) Я никогда не применял возможности str.format в полной мере, а они очень удобные, несмотря на некоторое время необходимое для их изучения.

Начнем с простейшего. Скажем кому-нибудь «Good morning», причем обратимся по имени и фамилии, предполагая что они сохранены в переменных «first» и «last». По-старому мы сделали бы так:

>>> first = "Reuven" >>> last = "Lerner" >>> "Good morning, %s %s" % (first, last) "Good morning, Reuven Lerner"
Даже в таком примере мы сталкиваемся с одной из проблем %-синтаксиса - у нас теперь две переменных, и чтобы использовать их обе нам нужно сделать из них кортеж. С точки зрения python это логично, но, уверяю вас, очень многих студентов это очень удивляет.

Как этот пример будет выглядеть в случае str.format? Довольно похоже:

>>> "Good morning, {} {}".format(first, last) "Good morning, Reuven Lerner"
Прошу обратить внимание, что мы немного поменяли принцип. Теперь это не бинарный оператор над строками, а метод объекта строка, принимающий ряд параметров. Это логично и более консистентно. Для тех же студентов оператор % в моих примерах выглядел как дополнение к print, а не операция над строками. Нотация с ".format" после строки делает более очевидным факт того, что это метод относящийся именно к этой строке.

Как вы уже наверняка знаете, вхождения “{} {}” в строке говорят что str.format должен принимать два параметра, значения которых будут вставлены в строку в том порядке, в котором они будут переданы в метод. Аргумента два, поэтому в строке должно быть два вхождения {}. Это немного сложнее понять, так как фигурные скобочки в Python намекают людям на словари и пустые скобочки выглядят не очень приятно. Но это ладно, я вполне могу с этим жить и принял это достаточно легко.

Момент, в котором str.format показывает первое преимущество над % - это при необходимости использования параметров в обратном порядке. На самом деле, с %s этого вообще никак не достичь. Невозможно также использовать значение одной переменной несколько раз. При использовании str.format мы вполне можем поменять последовательность подстановки:

>>> "Good morning, {1} {0}".format(first, last) "Good morning, Lerner Reuven"
Обратите внимание, что если бы я использовал пустые скобочки “{} {}”, то подстановка произошла бы в том же порядке, в каком передаются в метод параметры. Можно представить себе параметры как индексируемую с нуля последовательность и если я хочу поменять порядок следования, то просто проставляю в фигурных скобочках нужные индексы этой последовательности. Самый первый наш пример с str.format можно записать и так:

>>> "Good morning, {0} {1}".format(first, last) "Good morning, Reuven Lerner"
Заметим, что явно указав индексы, мы уже не можем положиться на автоматическую индексацию.

Разумеется, можно использовать последовательность и из списка, воспользовавшись оператором *:

>>> names = ("Reuven", "Lerner") >>> "Good morning, {} {}".format(*names) "Good morning, Reuven Lerner"
Можно использовать и именованные аргументы:

>>> "Good morning, {first} {last}".format(first="Reuven", last="Lerner") "Good morning, Reuven Lerner"
Этот вариант мне особенно нравится. Именованные параметры более явные (если у них хорошие имена), и применение {first} и {last} достаточно читабельно - особенно в сравнении с %(first)s, которое необходимо с оператором %

Именованные параметры можно, также, развернуть из словаря, используя оператор **:

>>> person = {"first":"Reuven", "last":"Lerner"} >>> "Good morning, {first} {last}".format(**person) "Good morning, Reuven Lerner"
Я описал все это своим студентам и был достаточно удивлен тем насколько комфортнее им живется с таким синтаксисом. Да и самому стало приятнее работать.

Нужно упомянуть, что именованные и позиционные аргументы технически можно использовать совместно. Но лучше этого не делать:

>>> person = {"first":"Reuven", "last":"Lerner"} >>> "Good {0}, {first} {last}".format("morning", **person) "Good morning, Reuven Lerner"

Я предупредил.

Чего может не хватать в str.format, так это… гм… форматирования. Плохая новость - в str.format совершенно другие правила определения того как форматировать вывод. Хорошая новость - эти правила достаточно несложно изучить и понять.

Снова начнем с простого: если нужно вывести строку заданной длины, то после имени переменной добавляем двоеточие (:) и затем количество символов. Так, чтобы вывести мое имя и дополнить его до десяти символов пробелами я должен делать так:

>>> "Your name is {name:10}".format(name="Reuven") "Your name is Reuven "
(Обратите внимание что строка дополнена пробелами после имени.)

Если нужно задать выравнивание по правой стороне блока - используется знак > между: и числом:

>>> "Your name is {name:>10}".format(name="Reuven") "Your name is Reuven"
И да, можно явно указать что я хочу выравнивания по левой стороне с помощью знака <
Если нужно вывести значение в центре блока, то вместо < и > используется символ ^:

>>> "Your name is {name:*^10}".format(name="Reuven") "Your name is **Reuven**"
С текстом более менее понятно, но что насчет чисел? Лично мне было трудно предположить как это будет работать, но все оказалось достаточно прямолинейно. Для простого вывода чисел используем синтаксис похожий на строки:

>>> "The price is ${number}.".format(number=123) "The price is $123."
Но для чисел применяется большее количество модификаторов, чем для строк. Например, чтобы вывести число в двоичном виде добавляем модификатор «b», если в шестнадцатеричном - модификатор «x»:

>>> "The price is ${number:b}.".format(number=5) "The price is $101." >>> "The price is ${number:x}.".format(number=123) "The price is $7b."
Разумеется, запись числа можно дополнить лидирующими нулями:

>>> "Your call is important to us. You are call #{number:05}.".format(number=123) "Your call is important to us. You are call #00123."
Заметим, что внутри {} нельзя использовать исполняемый python-код - вместо этого предлагается простенький микроязык отдельный и отличающийся от python в целом. Есть и небольшие исключения. Во-первых можно получить значения атрибутов/свойств через точку, во-вторых получить значение объекта по индексу, используя .

Например:

>>> class Foo(object): def __init__(self): self.x = 100 >>> f = Foo() >>> "Your number is {o.x}".format(o=f) "Your number is 100"n
Мы получили атрибут «х» объекта «f». Этот объект доступен по имени «o» внутри строки. Получить атрибут можно, а вот выполнить его - нет:

>>> "Your name is {name.upper()}".format(name="Reuven") AttributeError: "str" object has no attribute "upper()"
Я пытался выполнить “name.upper()”, предполагая, что будет вызван соответствующий метод, но python не разрешает выполнять код в этом месте и расценивает «upper()» как атрибут вместе со скобками. Без скобок вы получите просто строковое представление функции/метода:

>>> "Your name is {name.upper}".format(name="Reuven") "Your name is "
С помощью квадратных скобок можно взять элемент итерируемого объекта (списка, строки) по индексу. Но операции разрезания (slice) не поддерживаются:

>>> "Your favorite number is {n}.".format(n=numbers) "Your favorite number is 3."
Но:

>>> "Your favorite numbers are {n}.".format(n=numbers) ValueError: Missing "]" in format string
Можно использовать и для получения записей в словаре по имени, но имя вводится без кавычек:

>>> person = {"first":"Reuven", "last":"Lerner"} >>> "Your name is {p}.".format(p=person) "Your name is Reuven."
При попытке использовать кавычки получим исключение…

>>> "Your name is {p["first"]}.".format(p=person) KeyError: ""first""
Здесь приведены не все варианты использования str.format - на деле для каждого типа есть спецификация правил форматирования. Например, опция точности для чисел с плавающей запятой недоступна для строк.

Можно даже добавить собственные правила форматирования для объектов ваших классов так, что у них будет особый способ вывода и модификаторы для его настройки.

Если есть желание изучить эту тему подробнее - стоит начать с PEP 3101, где описан str.format. Могу, также, порекомендовать презентацию Эрика Смита с достаточно хорошим саммари по этой теме. Есть и хорошие примеры о том как перейти от использования % к str.format в документации python

Надеюсь, вам понравилось!

Текст программы говорит о том, как, а комментарии должны объяснять, почемуSwaroop Chitlur («A Byte of Python»)

Строки исходного текста

Физические строки

Физическая строка исходного файла - это строка заканчивающаяся символом признака конца строки (вводится нажатием на клавишу Enter). Этот признак - специальный символ, зависящий от платформы. В Unix, использует ASCII LF (перевод строки), в Windows - последовательность ASCII CR LF (возврат каретки с последующим переводом строки) и Macintosh - ASCII CR (возврат каретки). Все эти формы можно использовать в равной степени, независимо от платформы.

Логические строки

Программа Python разделена на несколько логических строк. Логическая строка содержит одну или более физических строк, соединяющихся правилами языка. (В интерактивном режиме продолжение логической строки на новой физической строке будет начинаться с символов...). Логическая строка - это законченное высказывание (инструкция ) языка.

Отступы в начале строки

Ведущие пробельные символы (пробелы и табуляции) в начале строки используются в Python для определения группы инструкций, как единого целого - составной инструкции или блока. Отступы в пределах блока должны быть равной символьной длины , иначе это приведет к ошибке. Для совместимости на разных платформах не следует применять смесь из пробелов и табуляций. Например:
Программа 2.1

From turtle import* begin_fill() for i in range(5): fd(150) for j in range(5): fd(50) left(144) left(144) end_fill() mainloop()

Примечание. В дальнейшем, программы будут нумероваться в формате: Программа x.y, где x - номер урока, y - номер программы в этом уроке.

Комментарии

Комментарии в Python начинаются с символа “#”. Комментарий заканчивается в конце физической строки и означают конец логической строки, если не используется неявное соединение строки (см. ниже). Комментарии предназначены для пояснений или заметок программиста. Комментарии помогают понять смысл исходного кода другим программистам (см. эпиграф). Комментарии полезны также при отладке программного кода и выявления ошибок. В пределах комментария можно использовать любые символы, в том числе служебные.

Объединение нескольких физических строк

Две (или более) физические строки могут быть объединены в одну логическую строку с использованием обратного слэша (бэк-слэш, “\”), а именно: когда физическая строка заканчивается символом “\” и он не является частью строки (т. е. не находится в пределах ” “) или комментария, он присоединяет следующую физическую строку, образуя одну логическую строку. После символа “\” должен следовать символ признака конца строки (т. е. физическая строка должна заканчиваться). Например:

If 1900 < year < 2100 and 1 <= month <= 12 \ and 1 <= day <= 31 and 0 <= hour < 24 \ and 0 <= minute < 60 and 0 <= second < 60: # Успешная проверка даты return 1

Примечание. Внутри строкового литерала экранирование бзк-слэша не имеет эффекта, но «\\» уменьшает количество выводимых символов "\" на 1:

Print("\ ") print("\\ ") print("\\\ ") print("\\\\") \ \ \\ \\

Неявное объединение физических строк

Выражения в скобках, в квадратных скобках, либо в фигурных скобках можно разделить на несколько физических строк без использования обратной косой черты. Например:
Программа 2.2

A = "Меня зовут - " b = input("Ваше имя: ") c = "\nМне - " d = input("Ваш возраст: ") e = "лет." print(a, # "Меня зовут - " b, # Имя, которое вы ввели c, # "Мне - " d, # Возраст, который вы ввели e # "лет")

Функция print()

В программа 2.2 для вывода данных на дисплей используется функция print() . Если не используется метод format() (см. ниже), то функция используется для вывода без форматов. Функция print имеет аргументы, которые могут придать выводимой информации читаемый вид. В общем виде функция имеет следующие аргументы:

Print(*objects, sep=" ", end="\n", file=sys.stdout, flush=False)

  • *objects - перечисленные через запятую объекты (переменные, строки, константы), значения которых нужно выводить
  • sep=" " - разделитель (по умолчанию - пробел)
  • end="\n" - завершающий символ (по умолчанию - символ конца строки)
  • file=sys.stdout - вывод в файл. Объект file должен быть объектом с методом write(str) . print() можно использовать только для текстовых файлов.
  • flush=False - принудительная очистка буфера вывода (по умолчанию - нет, поскольку обычно определяется файлом).

Например:
Программа 2.3 print("2", "+", "2", "= ") print("4") print("2", "+", "2", "= ", end="") print("4") print("2", "+", "2", "= ", sep="\n") print("4")

Вывод программы:

2 + 2 = 4 2 + 2 = 4 2 + 2 = 4

Метод format()

Функция print() имеет существенный недостаток - она не имеет аргументов, позволяющих производить форматированный вывод. Для осуществления вывода данных с определенным форматированием необходимо использовать метод format() .
Мини-руководство по этому методу на страницах документации
Примечание . В python отсутствует символьный тип данных, поэтому одиночный символ также рассматривается как строка.
Синтаксис метода format() :

"{:format_spec}".format()

где format_spec - спецификация формата:
[#][.precision]
Выглядит довольно пугающе, но не беспокойтесь! Обычно используется ограниченное количество форматирующих элементов, к тому же все они не являются обязательными!
Назначение форматирующих элементов:

  • fill - символ-заполнитель (любой символ)
  • align - выравнивание. Значения: "" | "=" | "^"
  • sign - вывод знака. Значения: "+" | "-" | " "
  • # - вывод префикса для двоичного, восьмеричного и шестнадцатеричного формата (т. е. 0x , 0o , или 0b)
  • 0 - заполнение лидирующими нулями для числовых типов, когда выравнивание не задано явно
  • width - ширина поля вывода (целое число)
  • grouping_option - разделитель разрядов «,» или «_» . Не используется для российской локали (для этих целей используется формат «n»)
  • .precision - количество дробных знаков (точка обязательна, затем следует целое число)
  • type - тип выводимого значения (см. таблицу ниже).
Обозначения типов
Символ Описание
b Бинарный формат. Выводит число в двоичной системе счисления
c Преобразует на выводе целое число в соответствующий символ юникода
d Десятичное целое число
e Число в экспоненциальном (научном) формате, e - строчная
E Число в экспоненциальном (с плавающей точкой, научном) формате, E - Прописная
f Число с фиксированной точкой
F Число с фиксированной точкой, NAN и INF (не число и бесконечность) выводить прописными
g Общий числовой формат. Для заданной точности p >= 1 это число округляется до p значащих цифр, а затем форматирует результат как в формате с фиксированной точкой или в научной нотации в зависимости от величины.
G То же самое, что и «g», но буквенные символы выводятся прописными
n То же самое, что и «d», за исключением того, что используется текущая настройка локали для вставки соответствующих символов разделителей.
o Число в восьмеричной системе счисления
s Строковый тип (по умолчанию)
x Шестнадцатеричное число
X То же самое, что и «x», только буквенные символы выводятся прописными
% Значение выводится в процентах (умножается на 100 и добавляется символ «%»)
None Аналогичен «g», за исключением того, что нотация с фиксированной точкой, используется, тогда, когда число имеет по крайней мере одну цифру после десятичной точки. Точность по умолчанию настолько высока, насколько это необходимо для представления конкретного значения.

Флаги используемые для выравнивания:

  • > - Выравнивание объекта по правому краю
  • ^ - Выравнивание по центру

Например:
Программа 2.4 print("{:<10}".format("Я")) print("{:^10}".format("Я")) print("{:>10}".format("Я"))

Вывод программы:

Я Я Я

Постановка задачи: С помощью символа "*" вывести следующий рисунок:

* *** ***** ******* ********* ***********

Решение: будем выводить символ "*" c выравниванием по центру:
Программа 2.5

Print("{:^11}".format("*")) print("{:^11}".format("***")) print("{:^11}".format("*****")) print("{:^11}".format("*******")) print("{:^11}".format("*********")) print("***********")

Можно использовать несколько спецификаций формата для одного и более выводимых значений различных объектов, перечисленных в методе format. Каждая спецификация должна заключаться в отдельные {} . Между спецификациями, заключенными в {} могут находиться произвольное количество различных символов-разделителей. Это позволяет выполнить сколь угодно сложное форматирование внятными и понятными инструментами. Например.
Постановка задачи: Вывести следующий рисунок:

********** ********** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ********** **********

Символы пробела и табуляции не использовать!
Решение:
Программа 2.6

Print("**********") print("**********") print("{:}{:>8}".format("**", "**")) print("{:}{:>8}".format("**", "**")) print("{:}{:>4}{:>4}".format("**", "**", "**")) print("{:}{:>4}{:>4}".format("**", "**", "**")) print("{:}{:>8}".format("**", "**")) print("{:}{:>8}".format("**", "**")) print("**********") print("**********")

Несложно заметить, что в этой программе выводится один и тот же объект несколько раз. Метод format() , позволяет рассматривать совокупность перчисляемых объектов как список и, соответственно, использовать индексацию для повторного вывода нужного объекта. Тогда этот код можно переписать следующим образом:

Print("**********") print("**********") print("{0:}{0:>8}".format("**")) print("{0:}{0:>8}".format("**")) print("{0:}{0:>4}{0:>4}".format("**")) print("{0:}{0:>4}{0:>4}".format("**")) print("{0:}{0:>8}".format("**")) print("{0:}{0:>8}".format("**")) print("**********") print("**********")

Примечание. Первый элемент списка имеет индекс 0. Когда для одного объекта используется несколько спецификаций формата, то для каждой из них первым символом в спецификации должен следовать символ-индекс выводимого объекта (в данном случае - он единственный, поэтому везде стоят нули).
Усложним задачу для закрепления основ работы с методом format() .
Постановка задачи: Вывести слово "МИР" с помощью символа "*". Символы пробела и табуляции не использовать.

* * * * ***** ** ** * ** * * * * * * * * ***** * * ** * * * * * * *

Решение:
Программа 2.7

Print("{0:1}{0:>6}{0:>2}{0:>6}{1:>6}".format("*","*****")) print("{0:1}{0:>5}{1:>2}{0:>6}{1:>2}{1:>5}".format("**","*")) print("{0:1}{0:>3}{0:>3}{0:>2}{0:>3}{0:>3}{1:>6}".format("*","*****")) print("{0:1}{0:>6}{1:>3}{0:>5}{0:>2}".format("*","**")) print("{0:1}{0:>6}{0:>2}{0:>6}{0:>2}".format("*"))

В этой программе для одного или двух выводимых объектов используются от 5 до 7 спецификаций формата. На рисунке ниже поясняется как используется индексация для каждой спецификации.

Домашнее задание

Выведите следующие рисунки с помощью метода format() и функции print() :

1. * ** *** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ************* ************** 2. ***** * ** *** **** ***** ****** ******* ******** ********* ********** *********** ********************* ******************* **************** 3. * *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** * 4. * * * * * * * * * * * * * * * * * * * * * * * ** * ** * * * * * * * * * * *** * *** ******* * * * ***