Баланс между креативностью и удобством


Одним из первых наших шагов в самом начале изучения любого языка программирования является вывод строки “Hello, World!”. Практически то же самое мы делаем и при знакомстве с Python. 

>>> # Самый первый вызов функции! >>> print("Hello, World!") Hello, World!

В вышеприведенном коде использована встроенная функция print(), которая получает строку и выводит ее на экран. Как мы видим, ничего сложного. 

А что если мы разнообразим строку и отформатируем ее? 

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

>>> # Более грамотный вызов функции >>> person = "Danny" >>> print("Hello, {}!".format(person)) Hello, Danny!

В данном примере кода мы определяем переменную person, которой хотим сказать Hello. С этой целью мы используем метод format() для замены поля, обозначенного фигурными скобками {}. Стоит отметить гибкость данного метода, что позволяет нам форматировать строки в среде выполнения, например переменная person может быть строкой ввода, заполняемой пользователем.

Однако, в отличие от перегруженного метода format(), в других языках программирования существуют более простые способы достичь тех же результатов. Например, в Swift можно повторить то же самое действие и без вызова функции форматирования. Как видно из нижеприведенного примера, всё необходимое форматирование осуществляется внутри строки, и такая техника известна как интерполяция строк. Что и говорить — очень удобно. 

let person = "Danny" print("Hello, \(person)!") // Hello, Danny!

Другие языки программирования развиваются, и Python — не исключение. В Python 3.6+ стал доступен новый синтаксис форматирования строк. Эта новая техника, общеизвестная как f-строки, носит официальное название — форматированные строковые литералы. Она предоставляет нам возможность значительно упростить интерполяцию строк. 

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

1. Интерполяция переменных/выражений 

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

>>> # Интерполяция строки >>> name = "Aaron" >>> f"Hello, {name}" 'Hello, Aaron' >>> >>> # Интерполяция целого числа >>> student_id = 160077 >>> F"My student ID # is {student_id}." 'My student ID # is 160077.' >>> >>> # Интерполяция списка >>> fruits = ["Apple", "Pear", "Banana"] >>> f"Fruits: {fruits}" "Fruits: ['Apple', 'Pear', 'Banana']" >>> >>> # Интерполяция кортежа >>> http_response = ('data', 200) >>> f"Http Response: {http_response}" "Http Response: ('data', 200)" >>> >>> # Интерполяция словаря >>> grades = {"John": 95, "Jennifer": 98} >>> f"Grades: {grades}" "Grades: {'John': 95, 'Jennifer': 98}"

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

С помощью этих переменных мы можем обратиться к их атрибутам или вычисленным значениям, вызывая определенные функции. В следующем коде приведено несколько примеров. Они должны быть довольно простыми. Как правило, выражения, возвращающие правильное значение, могут быть заключены в фигурные скобки. 

>>> # Обращение к элементу списка >>> pets = ["Dogs", "Cats", "Turtles"] >>> f"My pet: {pets[-1]}" 'My pet: Turtles' >>> >>> # С вызовом функции >>> name = "john" >>> f"Name: {name.title()}" 'Name: John' >>> >>> # Вычисление >>> number = 5 >>> f"Square: {number*number}" 'Square: 25'

2. Пользовательские объекты 

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

>>> # Определение пользовательского класса >>> class Student: ... def __init__(self, name, age): ... self.name = name ... self.age = age ... >>> # Создание экземпляра >>> student = Student('John Smith', 17) >>> >>> # Логирование экземпляра >>> print(f"Student: {student}") Student: <__main__.Student object at 0x102068e90>

Здесь мы создаем переменную student, которая является экземпляром пользовательского класса Student. При попытке осуществить логирование экземпляра мы получаем в качестве вывода основную информацию об объекте: модуль, класс и адрес памяти. Это, несомненно, полезная информация, но в ней отсутствуют подробные сведения о самом объекте student. Рассмотрим следующий код для улучшенной версии пользовательского класса. 

>>> # Определение пользовательского класса >>> class Student: ... def __init__(self, name, age): ... self.name = name ... self.age = age ... ... def __str__(self): ... print("__str__ is called") ... return f"Name: {self.name}; Age: {self.age}" ... >>> # Создание экземпляра >>> student = Student('John Smith', 17) >>> >>> # Логирование экземпляра >>> print(f"Student: {student}") __str__ is called Student: Name: John Smith; Age: 17

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

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

3. Конверсии 

Вместо вызова функции __str__() для интерполяции по умолчанию мы можем потребовать, чтобы f-строка использовала функцию __repr__(), т. е. прибегнуть к принципу конверсии. Функция __repr__ или repr() является встроенной функцией, которая возвращает строку, содержащую доступное для вывода представление объекта. Как правило, эта строка отображается для объекта в интерактивном интерпретаторе Python. Перед вами простейший пример:

>>> # Переменная >>> ages = {'John': 45, 'David': 38} >>> >>> # Отображение представления строки >>> ages {'John': 45, 'David': 38}

С помощью пользовательского класса Student мы можем переопределить функцию __repr__(), чтобы получить дополнительные возможности для интерполяции пользовательского экземпляра. Ниже представлена обновлённая версия пользовательского класса Student:

>>> # Обновление класса >>> class Student: ... # Остальные части остаются прежними ... def __repr__(self): ... print("__repr__ is called") ... return f"Student name is {self.name}, whose age is {self.age}." ... >>> # Создание экземпляра >>> student = Student('John Smith', 17) >>> >>> # Логирование экземпляра >>> print(f"Student str: {student!s} Student repr: {student!r}") __str__ is called __repr__ is called Student str: Name: John Smith; Age: 17 Student repr: Student name is John Smith, whose age is 17.

В данном коде мы обновляем класс путем реализации функции __repr__(), которая возвращает нам кое-что более интересное. Чтобы получить доступ к интерполированному значению с помощью функции repr(), необходимо использовать !r после переменной student. Применяя синтаксис !r, мы добиваемся использования интерполяцией строки, возвращаемой функцией repr(). Схожим образом можно использовать !s, чтобы при конверсии происходил вызов функции str(), что также является опцией интерполяции по умолчанию. 

4. Многострочные строки 

Вывод многострочной строки — еще один распространенный случай использования. И с f-строкой это также становится возможным. С этой целью воспользуемся предоставляемой Python опцией — тройными кавычками, позволяющими создавать многострочные строки. Предлагаю вашему вниманию упрощенный пример: 

>>> name = 'Danny Richardson' >>> >>> # Использование символа перевода строки /n >>> print(f'********************\n{name}\n********************') ******************** Danny Richardson ******************** >>> >>> # Использование тройных кавычек >>> print(f'''******************** ... {name} ... ********************''') ******************** Danny Richardson ********************

Как видим, вместо одинарных или двойных кавычек были использованы тройные для охвата многострочной строки. В то же время мы еще можем использовать символ перевода строки (\n) в f-строке, чтобы сообщить о добавлении новой строки. 

5. Форматирование числовых значений и строк 

В этом разделе кратко представлены несколько распространенных и востребованных случаев форматирования. Сначала рассмотрим форматирование с числовыми значениями на основе простых примеров в следующем фрагменте кода. 

>>> # Разделитель больших чисел >>> big_number = 98765432123456789 >>> f"{big_number:_d}" '98_765_432_123_456_789' >>> >>> # Форматирование десятичных дробей >>> more_digits = 2.345678 >>> f"2 digits: {more_digits:.2f}; 4 digits: {more_digits:.4f}" '2 digits: 2.35; 4 digits: 2.3457' >>> >>> # Экспоненциальная запись >>> sci_number = 0.0000043203 >>> f"number: {sci_number:e}" 'number: 4.320300e-06'

Мы можем также предоставить форматирование относительно выравнивания строк по краю или по формату, например по левому краю или по центру. Более того, предусмотрена возможность использования необходимых символов заполнения. Для выравнивания по левому и правому краям, а также центру существуют, соответственно, <, > и ^. Обратимся к нижеприведенным примерам.

>>> s0, s1 = 'a', 'bb' >>> >>> # Выравнивание по левому краю с символом заполнения * >>> print(f'{s0:*<7}\n{s1:*<7}') a****** bb***** >>> >>> # Выравнивание по правому краю с символом заполнения % >>> print(f'{s0:%>8}\n{s1:%>8}') %%%%%%%a %%%%%%bb >>> >>> # Выравнивание по центру >>> print(f'{s0:@^9}\n{s1:@^9}') @@@@[email protected]@@@ @@@[email protected]@@@

6. Ограничения в использовании 

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

  • Выражения, заключенные в фигурные скобки, не могут быть пустыми. 
  • 2. Выражения не могут использовать обратные слеши. 

    >>> print(f'Hello, {}!') File "<stdin>", line 1 SyntaxError: f-string: empty expression not allowed >>> >>> print(f'{"Hello"\n"World"}') File "<stdin>", line 1 SyntaxError: f-string expression part cannot include a backslash

    Заключение 

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


    Перевод статьи


    Поделиться статьей:


    Вернуться к статьям

    Комментарии

      Ничего не найдено.