Jak sformatować ciąg przy użyciu słownika w python-3.x?


215

Jestem wielkim fanem używania słowników do formatowania ciągów. Pomaga mi odczytać używany format ciągów, a także pozwala mi korzystać z istniejących słowników. Na przykład:

class MyClass:
    def __init__(self):
        self.title = 'Title'

a = MyClass()
print 'The title is %(title)s' % a.__dict__

path = '/path/to/a/file'
print 'You put your file here: %(path)s' % locals()

Nie mogę jednak rozgryźć składni Pythona 3.x, aby zrobić to samo (a jeśli to w ogóle możliwe). Chciałbym wykonać następujące czynności

# Fails, KeyError 'latitude'
geopoint = {'latitude':41.123,'longitude':71.091}
print '{latitude} {longitude}'.format(geopoint)

# Succeeds
print '{latitude} {longitude}'.format(latitude=41.123,longitude=71.091)

Odpowiedzi:


15

Ponieważ pytanie jest specyficzne dla Pythona 3, oto nowa składnia f-string , dostępna od Pythona 3.6:

>>> geopoint = {'latitude':41.123,'longitude':71.091}
>>> print(f'{geopoint["latitude"]} {geopoint["longitude"]}')
41.123 71.091

Zwróć uwagę na pojedyncze pojedyncze cudzysłowy i wewnętrzne podwójne cudzysłowy (możesz to również zrobić na odwrót).


Powiedziałbym, że użycie ciągu f jest bardziej dostosowane do podejścia python3.
Jonatas CD,

2
Należy pamiętać, że ciągi f są nowością w Pythonie 3.6, a nie w wersji 3.5.
Hugo,

409

Czy to dla ciebie dobre?

geopoint = {'latitude':41.123,'longitude':71.091}
print('{latitude} {longitude}'.format(**geopoint))

2
Próbowałem tego i zadziałało. Ale nie rozumiem użycia „notacji wskaźnikowej”. Wiem, że Python nie używa wskaźników, czy to przykład kwargs?
Homunculus Reticulli

2
@HomunculusReticulli Jest to parametr formatu (minimalna szerokość pola), a nie wskaźnik do stylu C ++ wskaźnika. docs.python.org/release/2.4.4/lib/typesseq-strings.html
D.Rosado

29
Wprowadzono Python 3.2 format_map. Podobny str.format(**mapping), z wyjątkiem tego, że mappingjest używany bezpośrednio i nie jest kopiowany do pliku dict. Jest to przydatne, jeśli na przykład mappingjest podklasa dict
diapir

1
@eugene Co ** robi słownika python? Nie sądzę, że tworzy obiekt, ponieważ print (** geopoint) nie daje błędu składniowego
Nityesh Agarwal

4
@NityeshAgarwal rozkłada słownik z parami nazwa = wartość jako pojedyncze argumenty, tzn. print(**geopoint)Jest taki sam jak print(longitude=71.091, latitude=41.123). W wielu językach jest znany jako operator ikony . W JavaScript nazywa się to operatorem rozprzestrzeniania . W Pythonie nie ma konkretnej nazwy dla tego operatora.
abhisekp

79

Aby rozpakować słownik na argumenty słów kluczowych, użyj **. Również formatowanie w nowym stylu obsługuje odwoływanie się do atrybutów obiektów i elementów odwzorowań:

'{0[latitude]} {0[longitude]}'.format(geopoint)
'The title is {0.title}s'.format(a) # the a from your first example

2
Znajduję tę odpowiedź lepiej, ponieważ dodanie indeksu pozycyjnego dla symbolu zastępczego czyni kod bardziej wyraźnym i łatwiejszym w użyciu. Zwłaszcza jeśli ktoś ma coś takiego:'{0[latitude]} {1[latitude]} {0[longitude]} {1[longitude]}'.format(geopoint0, geopoint1)
Løiten

1
Jest to przydatne, jeśli używasz a defaultdicti nie masz wszystkich kluczy
Whymarrh

65

Ponieważ Python 3.0 i 3.1 są EOL'ed i nikt ich nie używa, możesz i powinieneś używać str.format_map(mapping)(Python 3.2+):

Podobne do str.format(**mapping), z tym wyjątkiem, że mapowanie jest używane bezpośrednio i nie jest kopiowane do plikudict . Jest to przydatne, jeśli na przykład mapowanie jest dictpodklasą.

Oznacza to, że możesz użyć na przykład a defaultdict, który ustawi (i zwróci) domyślną wartość dla brakujących kluczy:

>>> from collections import defaultdict
>>> vals = defaultdict(lambda: '<unset>', {'bar': 'baz'})
>>> 'foo is {foo} and bar is {bar}'.format_map(vals)
'foo is <unset> and bar is baz'

Nawet jeśli dostarczone mapowanie to dict podklasą, a nie podklasą, prawdopodobnie nadal byłoby to nieco szybsze.

Biorąc pod uwagę, różnica nie jest duża

>>> d = dict(foo='x', bar='y', baz='z')

następnie

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format_map(d)

jest około 10 ns (2%) szybszy niż

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format(**d)

w moim Pythonie 3.4.3. Różnica byłaby prawdopodobnie większa, ponieważ więcej kluczy znajduje się w słowniku i


Pamiętaj jednak, że język formatu jest znacznie bardziej elastyczny; mogą zawierać wyrażeń indeksowane dostępy atrybutów i tak dalej, więc można sformatować cały obiekt lub 2 z nich:

>>> p1 = {'latitude':41.123,'longitude':71.091}
>>> p2 = {'latitude':56.456,'longitude':23.456}
>>> '{0[latitude]} {0[longitude]} - {1[latitude]} {1[longitude]}'.format(p1, p2)
'41.123 71.091 - 56.456 23.456'

Począwszy od wersji 3.6, można również używać interpolowanych ciągów:

>>> f'lat:{p1["latitude"]} lng:{p1["longitude"]}'
'lat:41.123 lng:71.091'

Trzeba tylko pamiętać, aby użyć innych znaków cudzysłowu w zagnieżdżonych cudzysłowach. Inną zaletą tego podejścia jest to, że jest znacznie szybsze niż wywoływanie metody formatowania.


Fajnie, czy jest jakaś poprawa wydajności format? (Biorąc pod uwagę, że nie jest on kopiowany do
nagrania

2
@BhargavRao niewiele, 2%: D
Antti Haapala

@BhargavRao, jeśli szukasz wydajności, użyj tego '%(latitude)s %(longitude)s'%geopoint;)
Tcll


6

Składnia Python 2 działa również w Python 3:

>>> class MyClass:
...     def __init__(self):
...         self.title = 'Title'
... 
>>> a = MyClass()
>>> print('The title is %(title)s' % a.__dict__)
The title is Title
>>> 
>>> path = '/path/to/a/file'
>>> print('You put your file here: %(path)s' % locals())
You put your file here: /path/to/a/file

plus jest również zauważalnie bardziej wydajny niż f""lub "".format();)
Tcll

2
geopoint = {'latitude':41.123,'longitude':71.091}

# working examples.
print(f'{geopoint["latitude"]} {geopoint["longitude"]}') # from above answer
print('{geopoint[latitude]} {geopoint[longitude]}'.format(geopoint=geopoint)) # alternate for format method  (including dict name in string).
print('%(latitude)s %(longitude)s'%geopoint) # thanks @tcll

1
przegapiłeś jeden;) print('%(latitude)s %(longitude)s'%geopoint)jest to również znacznie szybsze niż inne 2
Tcll

@ tcll Właściwie chciałem przykładów, w których mogę użyć nazwy słownika wewnątrz ciągu. Coś w tym stylu'%(geopoint["latitude"])s %(geopoint["longitude"])s'%{"geopoint":geopoint}
szejk Abdul Wahid

1

Większość odpowiedzi sformatowała tylko wartości nagrania.

Jeśli chcesz również sformatować klucz w ciągu, możesz użyć dict.items () :

geopoint = {'latitude':41.123,'longitude':71.091}
print("{} {}".format(*geopoint.items()))

Wynik:

(„szerokość geograficzna”, 41.123) („długość geograficzna”, 71.091)

Jeśli chcesz sformatować w sposób arbitralny, to znaczy, nie pokazując kluczowych wartości, takich jak krotki:

from functools import reduce
print("{} is {} and {} is {}".format(*reduce((lambda x, y: x + y), [list(item) for item in geopoint.items()])))

Wynik:

szerokość geograficzna wynosi 41.123, a długość geograficzna wynosi 71.091


zauważ, że istnieje szansa, że ​​„długość geograficzna” może wystąpić przed „szerokością geograficzną” od geopoint.items();)
Tcll
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.