LINUX.ORG.RU

f-строки или str.format - может ли одно полностью заменить другое, поделитесь опытом?

 ,


0

2

Сабж. Я много лет эти фичи игнорировал и вообще не любил третий питон - оператора % из py2 мне хватало. Но тут занялся одной штукой для преобразования аргументов командной строки, и понял что вещи в общем годные, правда опыта с ними у меня маловато.

В связи с этим нубвопрос - можно ли считать, что f-строки полностью заменяют str.format? Или это все таки разное, и str.format предпочтительнее и предсказуемее (требует меньше букв) в каких то случаях?

Речь о паттернах само собой (строке что форматируется), а не о способах вызова.

★★★★★
Ответ на: комментарий от AntonI

Оффтоп, не спалось =)

local cmd = { };
local ids =  1 ;
local cur = { };

for id,val in ipairs({...}) do
    -----------------------
    if val:find('@') then
       cmd[#cmd+1] =
       {
         iter  = {},
         body  = { text = '' },
         label = val:gsub('@','')
       };
       cur = cmd[#cmd].iter;
       ids = #cmd;
       goto step; end
    -------------------------------------------
    if cur == cmd[ids].iter and val ~= '{'then
       cur[#cur+1] = val;
       goto step; end
    -------------------------------------------
    if cur == cmd[ids].iter and val == '{'then
       cur =  cmd[ids].body;
       goto step; end
    -------------------------------------------
    if cur == cmd[ids].body and val ~= '}' then
       cur.text = cur.text ..' '..val;
       goto step; end
    --------
    ::step::
    --------
end

local result = '';

for _,val in pairs(cmd) do
    if val['iter'] then
       for _,litera in pairs(val.iter) do
           result =  result .. val.body.text:gsub('{'..val.label..'}',litera);
       end
    end
end

print(result)
dron@gnu:~$ lua fstrlol.lua i@ 1 2 3 { asd  qwe{i}rty  } x@ A B LALALA { lala baba{x}bab {x}_{x}  }
 asd qwe1rty asd qwe2rty asd qwe3rty lala babaAbab A_A lala babaBbab B_B lala babaLALALAbab LALALA_LALALA
dron@gnu:~$ 
LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

У меня там еще макросы вида name{ body … } подстановка как name# и переменные можно явно задавать как name#=value

Фсе;-)

Понятно что все это можно вкладывать друг в друга и перемешивать.

На питоне 74 строки с подробным хелпом.

Луа к сожалению не знаю, но выглядит симпатично.

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI
from https://www.linux.org.ru/forum/development/17406531?cid=17407019 import MyScope

print((f:='Да: %(f)s')%MyScope())
print(*(f'но {print=} не в Муscope:'.partition('=')),sep='\nолоМуscope')
#print('нет: %(print)s'%MyScope()) # ибо globals не универсум хнык хнык  #закоментить _thisline_ для продолжения банкета
print('Итого:')
from itertools import takewhile as tw
(f:=lambda нет:print(''.join(tw(lambda _:_!='=',f'сломалось как нижележащее?:{нет=}'))))(bin)
(f:=lambda нет:print('вы как всегда правы: (%(нет)s)'%MyScope()))(bin)
qulinxao3 ★★
()
Ответ на: комментарий от qulinxao3

Да, globals не универсальный, это просто пример. Ничего не мешает читать контекст сверху по стеку как ic или использовать ещё какие то варианты, вплоть до нечеткого ввода, анализа исходников из предыдущих версий гита, обращения на удаленные хосты и т.д - то, чего f-строки и близко не умеют.

Ключевым здесь является то, что % позволяет вводить имя переменной в строке ЕДИНОЖДЫ. А ещё можно ввести чего нить вроде a*= и напечатать значения всех переменных отвечающих шаблону a* - опять таки, f-строки этого не могут. И ещё 100500 вариантов.

Вы вторую страницу не можете понять такой тривиальной вещи… в % словарь указывается явно и может быть легко заменён на что угодно, в т.ч. на пользовательский эмулятор словаря. В str.format словарь указывается явно, но это может быть ТОЛЬКО словарь, что сильно ограничивает возможности. В f-строках контекст уже указан неявно, и что бы его сменить приходится плясать с eval - это напрочь убивает всю изящность f-строк.

ЗЫ str.format тоже позволяет вводить имя переменной единожды и изгалятся над контекстом - но для этого надо писать свою обертку над формат-ом которая будет ловить KeyError. А в % это все из коробки.

AntonI ★★★★★
() автор топика
Последнее исправление: AntonI (всего исправлений: 4)
Ответ на: комментарий от AntonI

Отладка начинается с того мы ищем ошибку в СВОЕЙ программе, в СВОЁМ коде.

начинать с того что программа правильная - а среда нет - тоже рабочая эвристика

завидую вам.

qulinxao3 ★★
()
Ответ на: комментарий от AntonI

постановка :

(Q:)есть f’{z=}’ возвращающее литерал f’z={z}’ для любого имени z

(ЛЮБОГО) как реализовать используя %,str.format:

(A:)Да, globals не универсальный, это просто пример.. Ничего не мешает читать контекст сверху по стеку как ic или использовать ещё какие то варианты, вплоть до нечеткого ввода, анализа исходников из предыдущих версий гита, обращения на удаленные хосты и т.д - то, чего f-строки и близко не умеют.

f’{ic(валидноевыражение)}’ не может а % ходить в гит может ок

(A:)ДА! И если у нас это есть, то нам уже пофик что юзать. А если этого нет, то нам НИЧЕГО не поможет.

(A:)Я привел пример как, посмотрите внимательно..

(A:)Блин, у Вас совсем с воображением туго что ли?! Ок, еще раз:

(A:)Я такой код с % уже два раза привел. Третий раз приводить не буду, сорри.

ок. кто ж считать то умеет .

(A:)print(‘Today: %(fact)s It is real, sorry…:-(’%MyScope())

информативно сообщили окружающим о уровне своего интеллекта

(A:)Не вангуйте о других и не будете выглядеть идиотом…

(A:)Вот сфига ли ли Вы с двух раз не смогли вкурить про возможности %MyScope() мне непонятно… ;-

уникальная снежинка устанавливает правила не уникальным

ps:

(Q:)ваш же ручной закат солнце в ручную - солнце очевидно закатывает - от того ваши руки так мозолисты

qulinxao3 ★★
()
Последнее исправление: qulinxao3 (всего исправлений: 1)
Ответ на: комментарий от AntonI

и раскручиваю евалом

Вы с qulinxao чтоль соревнуетесь?

В любом случае если вам темплейт строки отдельно не нужен в сохранённом виде (ну, в базе например) - проще f-string

upcFrost ★★★★★
()
Ответ на: комментарий от upcFrost

А как еще? Если шаблон строки приходит из переменной? Он не то что такой нужен, он такой есть в данном случае;-)

Я наверное определился, как то так будет

el = ... # обрабатываемый элемент входной последовательности
tmp_scope = dict(scope)
while 1:  
    try: dst_seq.append(el.format(**tmp_scope)); break
    except KeyError as ex:
        key = ex.args[0]
        try: tmp_scope[key] = eval(key, _math_dict, scope)  
        except: tmp_scope[key] = '{%s}'%key

На f-строках такое выглядит значительно кривее…

AntonI ★★★★★
() автор топика
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от qulinxao3

вывести имя переменной в лог

Это, сука, гениально, это шедевр мысли!

(full:=f'{var=}')[:full.index('=')]

для того, чтобы нам получить стоку «var» мы берем и… создаем переменную, в котору помещаем форматированную строку, в которую передаем переменную var, полученную после подстановки строку парсим и извлекаем оттуда var. Это шутка года такая??? Можно узнать, это в какой компании трудятся столь продвинутые разработчики?

FishHook
()
Ответ на: комментарий от FishHook

@qulinxao3 пытается сказать, что у него есть некая вундервафля (приблуда к IDE), которая при замене имени переменной var на foo поменяет f"var=" на f"foo=" автоматически. А просто «var» на «foo» не поменяет.

Я его так понял в итоге.

AntonI ★★★★★
() автор топика

Сабж. Я много лет эти фичи игнорировал и вообще не любил третий питон - оператора % из py2 мне хватало.

В связи с этим нубвопрос - можно ли считать, что f-строки полностью заменяют str.format? Или это все таки разное, и str.format предпочтительнее и предсказуемее (требует меньше букв) в каких то случаях?

Я немного запутался в вопросе. Мы говорим о «{0}».format(a) vs f"{a}" или мы говорим о «%s» % a vs f"{a}"?

FishHook
()
Ответ на: комментарий от FishHook

Мы говорим о «{a}».format(a=1) vs eval(‘f"{a}"’, {‘a’:1})

Я в итоге остановился на str.format, он как то попредсказуемее.

f-строки или str.format - может ли одно полностью заменить другое, поделитесь опытом? (комментарий)

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

В 3.12 наконец убрали историю с кавычками и теперь стало совсем хорошо. Плюс там есть достаточно много плюшек типа форматирования дат. Но есть и ограничения.

https://realpython.com/python312-f-strings

stave ★★★★★
()
Ответ на: комментарий от upcFrost

Ну он делает ровно то что должен;-)

  1. пытается отформатировать строку el по словарю tmp_scope и добавить результат в выходную последовательность.

  2. если вылетел KeyError - пытается вычислить ключ (то что было в паттерне между { }) и добавить соответствующую запись в tmp_scope, что бы в следующий заход там не падало а запись встала на место

  3. если eval упал, пишет в tmp_scope запись дублирующую ключ, что бы паттерн после подстановки не поменялся

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

PS цикл нужен что бы все ключи разрешить, то есть он долбится в str.format пока в tmp_scope не будет все что нужно для успешного форматирования. В % это решалось сразу, ну что делать…

Вообще eval в try заворачивать это хорошая практика, если хочется хоть как то контролировать ситуацию.

AntonI ★★★★★
() автор топика
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от upcFrost

А какой смысл вообще дергать eval для статической (явно вбитой в код?) строки???

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

У нас скажем бьют по рукам за геттеры/сеттеры (за редкими исключениями).

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

есть некая вундервафля (приблуда к IDE)

Вундервафля, позволяющая переименовать переменную в файле/всём проекте – вполне обычная фукнция любого продвинутого редактора кода, не то, что IDE.

Вы последние три десятилетия код сугубо в notepad.exe набирали что-ли?

apt_install_lrzsz ★★★
()
Ответ на: комментарий от apt_install_lrzsz

А почему Вы мне такие вопросы задаете?! Спрашивайте у @qulinxao3, это у него «var=» в «foo=» переименовывается автоматом, а «var» в «foo» нет. Я ХЗ в чем он работает.

Я в имаксе кодю, и у меня не возникает необходимости в автоматическом переименовании переменных. Чур меня.

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

Каждый аргумент форматируется по некоторому словарю. Вот дальше вопрос, то ли его форматировать через str.format, то ли eval-ом как f-строку. Важно что подстановка выполняется один и только один раз.

Что-то я для таки такие вещи делал через jinja2 когда их много.

thunar ★★★★★
()
Ответ на: комментарий от AntonI

Мы говорим о «{a}».format(a=1) vs eval(‘f"{a}"’, {‘a’:1})

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

он как то попредсказуемее.

я не понял, что вы понимаете под предсказуемостью

def calculate(a: int, b: int) -> int:
    c = a + b
    d = a**2 + b**2
    e = a**2 - b**2
    log.info(f"Calculating formula: {a} + {b} + {c} + {d} + {e}")
    return a + b + c + d + e

почему это хуже чем

def calculate(a: int, b: int) -> int:
    c = a + b
    d = a**2 + b**2
    e = a**2 - b**2
    log.info("Calculating formula: {} + {} + {} + {} + {}".formant(a, b, c, d, e))
    return a + b + c + d + e

??

FishHook
()
Ответ на: комментарий от AntonI

Да что имел в виду qulinxao3 понятно. ИДЕ умеет различать переменные и строки. Когда вы с помощью тулзы рефакторите код и переименовываете переменную, тулза переименует именно переменную, а если где-то в строковых литералах есть подстрока с именем переменной то тулза её не изменит, и поэтому в логах, например останется что-то вроде «Variable foo is 44», хотя в коде уже давно не foo, а bar. Хотя это тоже не всегда так, Идея, например, предложит исправления в строках тоже. Другое дело, что замусоривать код подобными хреновинами, придет в голову только юноше-максималисту, который как это свойственно малолетним **** все возводит в абсолют. Здесь возведена в абсолют идея, что любая сущность должна быть определена единожды, а любое изменение должно быть точечным. Вот таким бредовым способом qulinxao3 решает теоретическую возможность забыть изменить строку лога, что вероятно, в горячем мозгу рисует картины локального апокалипсиса. Лучше же засрать код шизофренией, чем раз в десять лет увидеть в логах foo там где должен быть bar. При чем совершенно непонятно, почему изкоробочное f"{foo=}" не подходит.

FishHook
()
Ответ на: комментарий от FishHook

Причем, я должен сделать зачемание, что на самом деле @qulinxao3 не последователен, потому что… давайте посмотрим, как это должно работать

var = "I am a string"
# let's save var value in the log
var_name = (full:=f'{var=}')[:full.index('=')]
log.info(f"{var_name} is {var}")

И теперь мы применяем, как он выражатся «рефактор» и изменяем var на item. И??? у нас по прежнему остается некий var_name и комментарий содержащие смысловую ссылку на несуществующую переменную. Как-то мы будем решать эту проблему? @qulinxao3

FishHook
()
Ответ на: комментарий от FishHook

Пока все идёт нормально они одинаковы. Проблемы начинаются когда что то идёт не так - str.format может выкинуть KeyError или ValueError, f-строка может выкинуть почти что угодно.

f-строка не существует в памяти в том виде в котором вы её видите в коде

Именно это намекает - не надо их использовать для случаев когда паттерны генерятся динамически. Хотя питон такое и позволяет через eval, но все же ф-строки для другого.

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

Именно это намекает - не надо их использовать для случаев когда паттерны генерятся динамически.

а кто-то призывает к обратному? Я вам выше уже намекал, что это разные сущности. Ваше стремление оставить в живых только один способ создания строки некое недоумение вызывает.

может выкинуть KeyError или ValueError

Да ладно!

class Foo:

    def __format__(self, __format_spec: str) -> str:
        raise NotImplemented("ha-ha!")

print("{}".format(Foo()))


Traceback (most recent call last):
  File "../misc/test3.py", line 6, in <module>
    print("{}".format(Foo()))
  File "../misc/test3.py", line 4, in __format__
    raise NotImplemented("ha-ha!")
FishHook
()
Ответ на: комментарий от FishHook

Ваше стремление оставить в живых только один способ создания строки некое недоумение вызывает.

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

Да ладно!

В контексте решения той задачи такие варианты исключены.

Но за спецметод формат спасибо, зря я бочку на str.format за негибкость катил:-)

AntonI ★★★★★
() автор топика
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от AntonI

Но за спецметод формат спасибо, зря я бочку на str.format за негибкость катил:-)

Ага! То есть учебник вы не читали, сразу на форум. Хорошо, но давайте всё-таки разберемся с тезисом " str.format может выкинуть KeyError или ValueError, f-строка может выкинуть почти что угодно."

Мы уже поняли, что str.format не избавляет нас от необходимости ловить эксепшены и вот это

log.info(f"{a/b}")

при b = 0 упадет так же громко как вот это

log.info("{}".format(a/b))

правильно же?

О каких KeyError или ValueError тогда речь? А вот о каких

log.info("{1}".format(a)) # there must be {0}

Но дорогой друг, ведь с f-строками вы вообще лишены возможности изобразить нечто подобное, верно? Ну там же не нужен индекс. Поэтому они безопаснее по вашей логике

FishHook
()
Последнее исправление: FishHook (всего исправлений: 1)
Ответ на: комментарий от AntonI

Вот так вы задали вопрос

Сабж. Я много лет эти фичи игнорировал и вообще не любил третий питон - оператора % из py2 мне хватало. Но тут занялся одной штукой для преобразования аргументов командной строки, и понял что вещи в общем годные, правда опыта с ними у меня маловато. В связи с этим нубвопрос - можно ли считать, что f-строки полностью заменяют str.format? Или это все таки разное, и str.format предпочтительнее и предсказуемее (требует меньше букв) в каких то случаях? Речь о паттернах само собой (строке что форматируется), а не о способах вызова.

FishHook
()
Ответ на: комментарий от FishHook

То есть учебник вы не читали, сразу на форум.

Когда я учебник читал, этого всего в питоне не было, и питона 3 тоже не было. А с тех пор я учебники как то больше пишу, но по другим вещам:-)

Насчёт остального - Вы не поняли что именно мне в данном случае требуется. Но объяснять мне лень, на этом я заканчиваю - все что я хотел услышать я услышал.

Спасибо.

AntonI ★★★★★
() автор топика
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от wandrien

Поясните свои слова каким-нибудь примером, пожалуйста. Я не понимаю, почему я не могу передать строку полученную с помощью f-синтаксиса в геттекст, как любую другую строку

FishHook
()
Ответ на: комментарий от AntonI

Насчёт остального - Вы не поняли что именно мне в данном случае требуется.

Бред понять нельзя, это его имманентное свойство - быть лишенным всякого смысла

Когда я учебник читал, этого всего в питоне не было, и питона 3 тоже не было.

Это извиняет невежество?

FishHook
()