F-strings to intuicyjny i prosty sposób na formatowanie łańcuchów znaków w Pythonie. Ucząc się programowania przez ostatnie kilka lat bez trudu mogłem zauważyć tendencję do odchodzenia od dawniejszych metod formatowania łańcuchów znaków właśnie na rzecz f-strings. Nie twierdzę, że pozostałe metody czyli formatowanie łańcuchów znaków przy pomocy operatora „%” oraz str.format() stały się nieistotne – wręcz przeciwnie, przy ich użyciu napisano wiele gigabajtów dokumentacji i ich znajomość jest niezbędna, jednak w praktyce te wcześniej stosowane sposoby formatowania wydają się wychodzić z użycia. Temat ten zaciekawił mnie na tyle, że postanowiłem przeszukać Internet, by dowiedzieć się, czy mimo wszystko wciąż występują sytuacje, w których f-strings powinniśmy unikać.

Zacznę od podstaw – załóżmy, że chcemy wyświetlić komunikat, w którym będą zawierały się jakieś zmienne z uprzednio przypisanymi wartościami i chcemy do tego celu wykorzystać f-strings:

from datetime import date
def count_age(birthday):
	today = date.today()
	age = today.year - birthday.year - ((today.month, today.day) < 	(birthday.month, birthday.day))
	return age

person = "Andrzej"
birthday = date(1980, 5, 20)

print(f"{person} urodził/a się {birthday.day}.{birthday.month}.{birthday.year} r., a zatem ma {count_age(birthday)} lat/a.")

A teraz spójrzmy jak wyglądałoby to przy użyciu poprzednich metod:

print("%s urodził/a się %d.%d.%d r., a zatem ma %d lat/a." % (person, birthday.day, birthday.month, birthday.year, count_age(birthday)))

print("{} urodził/a się {}.{}.{} r., a zatem ma {} lat/a.".format(person, birthday.day, birthday.month, birthday.year, count_age(birthday)))

Co może zwrócić naszą uwagę? Przede wszystkim czytelność i brak powtórzeń przy f-strings. Kod z f-strings już teraz jest krótszy – różnica może zwiększać się lub zmniejszać w zależności od ilości zmiennych, z których będziemy korzystać.

Jak wynika z powyższego przykładu przy pomocy f-strings można nie tylko wyświetlać proste zmienne, ale również wywoływać funkcje. Zresztą możliwości jest więcej – np. obliczanie wyrażeń matematycznych.

Przejdę teraz do wyjątków.

1.

Co do zasady powinniśmy unikać jakiegokolwiek formatowania łańcuchów znaków używając SQL z Pythonem, aby uniknąć ryzyka SQL-injection.

Za przykład niech posłuży PostgreSQL. Sposób działania mamy opisany w dokumentacji biblioteki psycopg2, która stanowi ponoć najbardziej popularny adapter dla tej bazy danych.

https://www.psycopg.org/docs/usage.html#query-parameters

from psycopg2 import sql

cur.execute(
    sql.SQL("insert into {} values (%s, %s)")
        .format(sql.Identifier('my_table')),
    [10, 20])

Sam kod zadziałałby również z f-strings i jeżeli jesteśmy na 100% pewni, że ze względu na ograniczony sposób jego wykorzystania nie powinien być narażony na żaden atak możemy zdecydować się na użycie formatowania łańcuchów znaków. Zasadniczo jednak, jeżeli osoby tworzące dokumentację zalecają używać narzędzi w określony sposób, to robią tak z jakiegoś istotnego powodu i lepiej ich posłuchać.

2.

https://stackoverflow.com/questions/44780357/how-to-use-newline-n-in-f-string-to-format-output-in-python-3-6

Teraz dwa linki ze stackoverflow. Autor pierwszej odpowiedzi (Dimitris Fasarakis Hilliard) zauwazył, że zgodnie z dokumentacją f-strings, wewnątrz nawiasów klamrowych nie można używać ukośników wstecznych („\”). W sytuacji gdy są one dla nas konieczne, wygodniejsze może być użycie str.format() albo próba „obejścia systemu” poprzez przypisanie wyrażenia z ukośnikiem wstecznym do zmiennej i wprowadzenie dopiero tej zmiennej do nawiasu klamrowego. W odpowiedziach na wyżej zalinkowane pytanie znajdują się jeszcze inne możliwe rozwiązania, warto się zapoznać.

Przy okazji mogę dodać, że zgodnie z dokumentacją, w nawiasach klamrowych f-strings nie można również używać znaku „#”.

3.A.

https://stackoverflow.com/questions/69855146/are-there-cases-when-the-f-string-is-not-better-than-older-string-formatting-met

Tworzenie logów. Nie mam doświadczenia w tej materii, przytoczę zatem tylko, odpowiedź jednego z autorów (luk2302), który twierdzi, że jeżeli rejestrator nie jest skonfigurowany do tworzenia logów INFO, używanie f-strings będzie skutkowało potencjalnie kosztowną interpolacją argumentów na łańcuchy znaków.

3.B.

Pod powyższym linkiem znajduje się więcej odpowiedzi, autor drugiej (Pedro Maia) przytomnie twierdzi, że w sytuacji gdy mamy jakiś szablon złożony z łańcuchów znaków i chcemy wykorzystywać go na wiele różnych sposobów lepiej będzie zastosować formatowanie za pomocą operatora %.

3.C.

Autor(ka?) trzeciej odpowiedzi („user2357112 supports Monica”) napisał(a?) z kolei,że f-strings nie są dobrym pomysłem w sytuacji gdy dane oprogramowanie ma mieć więcej wersji językowych. Łańcuch znaków f-strings jest zakodowany w kodzie źródłowym programu i nie ma możliwości, aby dokonać jego dynamicznej zamiany na przetłumaczony szablon na podstawie ustawień językowych użytkownika.

 

Jeżeli znane są komuś jakieś inne wyjątki to bardzo proszę o komentarz.

Z powyższego wynika, że odstępstwa lub problemy z f-strings mogą dotyczyć zarówno kwestii drobnych jak i całkiem poważnych. Wiele zależy od tego jakie funkcje ma spełniać nasz kod. Warto pamiętać o dawnych metodach formatowania znaków, ale o ile nie spotykamy się, z którymś z opisanych wyżej zagadnień najłatwiej będzie jednak używać f-strings.

PEP 498 czyli propozycja ulepszenia Pythona nr 498 znajduje się pod poniższym linkiem:

https://peps.python.org/pep-0498/

Polecam przynajmniej przejrzenie tej dokumentacji, bo doskonale pokazuje sposób myślenia jaki towarzyszy zmianom dokonywanym w tym języku programowania, przykład f-strings jest o tyle symptomatyczny, że używając Pythona z formatowaniem łańcuchów znaków spotykamy się bardzo często.

Dla mnie osobiście budująca i motywująca jest idea ulepszeń, która wynika z autentycznej potrzeby lub dążenia, by ułatwić innym korzystanie z danego narzędzia, a nie czyjegoś „widzi mi się” – zmiana dla zmiany. W przyszłości napiszę o tym szerzej.

Co ciekawe obecnym, a zarazem pierwszym deweloperem-rezydentem Fundacji Pythona, który czuwa nad tymi sprawami jest Polak – Łukasz Langa. W zeszłym roku był gościem podcastu Python Talk To Me, gdzie udzielił interesującego wywiadu.

https://talkpython.fm/episodes/show/331/meet-the-python-developer-in-residence-lukasz-langa