Nowe formatowanie stringów w Pythonie 3.6+, nie ogarniam.

Nowe formatowanie stringów w Pythonie 3.6+, nie ogarniam.
Ragnar Lothbrok
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 4 lata
  • Postów:35
0

Okej, to że mamy w F-Stringach wstawianie wartości w nawiasach klamrowych samo w sobie jest banalne, problem zaczyna się dalej bo im więcej czytam tym mniej rozumiem.
Np żeby dodać precyzje stosuje się zapis "jakaś_liczba:04", co wydaje mi się już od razu debilne bo słowniki też używają przecież dwukropka. Wszystko co próbuje napisać po przeczytaniu dokumentacji i poradników zwyczajnie nie działa, np :

Kopiuj
>>> f"{[x:04 for x in range(2)]}"
SyntaxError: invalid syntax
>>> f"{[x for x in range(2)]:04}"
Traceback (most recent call last):
  File "<pyshell#30>", line 1, in <module>
    f"{[x for x in range(2)]:04}"
TypeError: unsupported format string passed to list.__format__

Tracę po mału wiarę w sensowny rozwój pythona, co było nie tak z poprzednią interpolacją stringów? Jak mam wg nowych standardów napisać ekwiwalent np takiej linijki :

Kopiuj
    return("{nr:.{precision}f}".format(nr=dict_one.get('nr'),precision=dict_one.get('precision'))).center(dict_one.get('width'))
edytowany 2x, ostatnio: Ragnar Lothbrok
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:około godziny
  • Postów:4935
2

Generalnie, jeśli Chcesz wyświetlić listę z precyzją, to jest to nonsens, w pierwszej linijce interpreter mówi, również, o błędzie składniowym w list comprehension. A jeśli chodzi o precyzję i width, to w f stringach jakoś tak:

Kopiuj
>>> a = 10.12345
>>> f"{a:.{4}}"
'10.12'
>>> f"{a:.{5}}"
'10.123'
>>> width = 10
>>> f"{a:{width}.{5}}"
'    10.123'
>>> 


edytowany 1x, ostatnio: lion137
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Ja bym tylko radził uważać, bo te f-strings to RCE jak zrobicie coś głupiego. Tzn jak ktoś da podokleja tam input usera, bo można z tego stringa wykonywac dowolny kod.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
AN
W jaki to sposób? Pokaż przykład bo to raczej niemożliwe
  • Rejestracja:około 6 lat
  • Ostatnio:ponad rok
0

Jak mam wg nowych standardów napisać ekwiwalent np takiej linijki :

Kopiuj
    return("{nr:.{precision}f}".format(nr=dict_one.get('nr'),precision=dict_one.get('precision'))).center(dict_one.get('width'))
Kopiuj
>>> dict_one = {'nr': 42.3, 'precision': 2, 'width': 10}

>>> '{nr:^{width}.{precision}f}'.format_map(dict_one)
'  42.30   '

>>> '{nr:^{width}.{precision}f}'.format(**dict_one)
'  42.30   '

>>> 
edytowany 1x, ostatnio: Mózg
Ragnar Lothbrok
Bardzo eleganckie. I to mi się podoba i to rozumiem, ale format_map chyba nie jest kompatybilne z F'Stringami ?
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
3

W jaki to sposób? Pokaż przykład bo to raczej niemożliwe

@anonimowy hold my beer!
Załóżmy że robimy coś w stylu:

Kopiuj
equation = input("Podaj dzialanie: ")
print(eval('f"{%s}"' % equation))

(ofc to tylko przykład!)
Niby wszystko spoko, ale co jak ktoś poda ''.__reduce__(42)[0].__globals__['__builtins__']['__import__']('subprocess').check_output('cat /etc/passwd') ? (od razu mówie że takich gadget-chainów jest cała masa, sam mam pod ręką kilkanaście, więc nie ma sensu próbować ich blacklistować :P) :)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
YA
Można odrzucać te: ' | [ ( { . _ Chyba nikt nie będzie narzekał: "Nie mogę zapisać swojego imienia bez tych znaczków" ;-) Nie wiem czy to rozwiązuje problem, czy tylko komplikuje przekazywane wyrażenie/odracza w czasie wymyślenie jakiejś escape techniki. Albo po prostu sprawdzać to co się dostaje od usera ;-)
Shalom
. zastąpisz przez getattrjak trzeba, __ można przecież zaenkodować bo masz to jako stringi, [] ogarniasz jako getitem... i takie tam
AN
Podasz przykłady bez eval?
Shalom
Wszystko zależy od sytuacji i konkretnego zastosowania. Z takich ciekawych przykładów np. https://jbz.team/inshack2018/Config_Creator
AN
@Shalom ale znowu w kodzie źródłowym jest użyte eval i to na tym ostatecznie się wywala
AN
  • Rejestracja:prawie 11 lat
  • Ostatnio:7 dni
  • Postów:973
1

Ale przecież poprawnie by było print(eval('f"{equation}"')) i już nie zadziała takie kombinowanie. I jeszcze korzystanie z eval przy inpucie od usera :O Ciężko coś takiego zrobić celowo a co dopiero przypadkiem

Właściwie to f-string dodaje Ci dodatkową ochronę bo nawet eval nie zadziała w takim przypadku: eval('f"{equation}"'). A równie dobrze mógłbyś napisać eval(equation) tylko co to ma do f-stringów?


Zdalna praca dla Senior Python Developerów --> PW
edytowany 2x, ostatnio: anonimowy
IK
  • Rejestracja:ponad 7 lat
  • Ostatnio:prawie 2 lata
0
Shalom napisał(a):

W jaki to sposób? Pokaż przykład bo to raczej niemożliwe

@anonimowy hold my beer!
Załóżmy że robimy coś w stylu:

Kopiuj
equation = input("Podaj dzialanie: ")
print(eval('f"{%s}"' % equation))

(ofc to tylko przykład!)
Niby wszystko spoko, ale co jak ktoś poda ''.__reduce__(42)[0].__globals__['__builtins__']['__import__']('subprocess').check_output('cat /etc/passwd') ? (od razu mówie że takich gadget-chainów jest cała masa, sam mam pod ręką kilkanaście, więc nie ma sensu próbować ich blacklistować :P) :)

Chyba nie rozumiem. Jakim cudem to może zadziałać, skoro cały czas ''.__reduce__(42)[0].__globals__['__builtins__']['__import__']('subprocess').check_output('cat /etc/passwd') będzie traktowane jako string?

screenshot-20190925162124.png

Problemem tu jest użycie eval, a nie f-stringa.

edytowany 2x, ostatnio: iksde

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.