Bagaimana cara memformat string menggunakan kamus di python-3.x?


215

Saya penggemar berat menggunakan kamus untuk memformat string. Ini membantu saya membaca format string yang saya gunakan serta membiarkan saya memanfaatkan kamus yang ada. Sebagai contoh:

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()

Namun saya tidak dapat mengetahui sintaks python 3.x untuk melakukan hal yang sama (atau jika itu bahkan mungkin). Saya ingin melakukan hal berikut

# 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)

Jawaban:


15

Karena pertanyaan khusus untuk Python 3, inilah yang digunakan sintaks f-string baru , tersedia sejak Python 3.6:

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

Perhatikan kutipan tunggal luar dan kutipan ganda dalam (Anda juga bisa melakukannya sebaliknya).


Saya akan mengatakan bahwa penggunaan f-string lebih selaras dengan pendekatan python3.
Jonatas CD

2
Perlu diingat bahwa f-string adalah baru untuk Python 3.6, dan bukan dalam 3.5.
Hugo

410

Apakah ini baik untukmu?

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

2
Mencoba ini dan berhasil. Tapi saya tidak mengerti penggunaan notasi pointer. Saya tahu Python tidak menggunakan pointer, apakah ini contoh kwarg?
Homunculus Reticulli

2
@HomunculusReticulli Itu adalah parameter format (Lebar bidang minimum), bukan penunjuk ke gaya penunjuk C ++. docs.python.org/release/2.4.4/lib/typesseq-strings.html
D.Rosado

29
Python 3.2 diperkenalkan format_map. Mirip dengan str.format(**mapping), kecuali yang mappingdigunakan secara langsung dan tidak disalin ke dict. Ini berguna jika misalnya mappingadalah subclass dict
diapir

1
@ Eugene Apa yang ** lakukan untuk kamus python? Saya tidak berpikir bahwa itu menciptakan objek karena print (** geopoint) gagal memberikan kesalahan sintaksis
Nityesh Agarwal

4
@NityeshAgarwal menyebar kamus dengan nama = pasangan nilai sebagai argumen individu yaitu print(**geopoint)sama dengan print(longitude=71.091, latitude=41.123). Dalam banyak bahasa, ini dikenal sebagai operator percikan . Dalam JavaScript, itu disebut operator spread . Dalam python, tidak ada nama khusus yang diberikan kepada operator ini.
abhisekp

79

Untuk membongkar kamus ke argumen kata kunci, gunakan **. Juga ,, dukungan pemformatan gaya baru yang mengacu pada atribut objek dan item pemetaan:

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

2
Saya menemukan jawaban ini lebih baik, karena menambahkan indeks posisi untuk placeholder membuat kode lebih eksplisit, dan lebih mudah digunakan. Terutama jika seseorang memiliki sesuatu seperti ini:'{0[latitude]} {1[latitude]} {0[longitude]} {1[longitude]}'.format(geopoint0, geopoint1)
Løiten

1
Ini berguna jika Anda menggunakan a defaultdictdan tidak memiliki semua kunci
Whymarrh

65

Karena Python 3.0 dan 3.1 EOL'ed dan tidak ada yang menggunakannya, Anda dapat dan harus menggunakan str.format_map(mapping)(Python 3.2+):

Mirip dengan str.format(**mapping), kecuali bahwa pemetaan digunakan secara langsung dan tidak disalin kedict . Ini berguna jika misalnya pemetaan adalah dictsubkelas.

Apa artinya ini adalah bahwa Anda dapat menggunakan misalnya a defaultdictyang akan menetapkan (dan mengembalikan) nilai default untuk kunci yang hilang:

>>> 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'

Bahkan jika pemetaan yang disediakan adalah a dict , bukan subclass, ini mungkin masih akan sedikit lebih cepat.

Perbedaannya tidak besar, mengingat

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

kemudian

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

sekitar 10 ns (2%) lebih cepat dari

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

pada Python 3.4.3 saya. Perbedaannya mungkin akan lebih besar karena lebih banyak kunci dalam kamus, dan


Perhatikan bahwa bahasa format jauh lebih fleksibel daripada itu; mereka dapat berisi ekspresi yang diindeks, akses atribut dan sebagainya, sehingga Anda dapat memformat seluruh objek, atau 2 di antaranya:

>>> 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'

Mulai dari 3,6 Anda dapat menggunakan string interpolasi juga:

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

Anda hanya perlu ingat untuk menggunakan karakter kutipan lain dalam tanda kutip bersarang. Kelebihan lain dari pendekatan ini adalah bahwa itu jauh lebih cepat daripada memanggil metode pemformatan.


Bagus, Apakah ada peningkatan kinerja format? (Mengingat bahwa itu tidak disalin ke dikt)
Bhargav Rao

2
@BhargavRao tidak banyak, 2%: D
Antti Haapala

@BhargavRao jika Anda mencari kinerja, gunakan ini '%(latitude)s %(longitude)s'%geopoint;)
Tcll

20
print("{latitude} {longitude}".format(**geopoint))

6

Sintaks Python 2 juga berfungsi di 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 itu juga jauh lebih banyak performan daripada f""atau "".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
Anda melewatkan satu;) print('%(latitude)s %(longitude)s'%geopoint)ini juga secara signifikan lebih cepat daripada yang lain 2
Tcll

@tcll Sebenarnya saya ingin contoh, di mana saya dapat menggunakan nama kamus di dalam string. Sesuatu seperti ini'%(geopoint["latitude"])s %(geopoint["longitude"])s'%{"geopoint":geopoint}
Sheikh Abdul Wahid

1

Sebagian besar jawaban hanya memformat nilai-nilai dikt.

Jika Anda ingin juga memformat kunci menjadi string, Anda dapat menggunakan dict.items () :

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

Keluaran:

('lintang', 41.123) ('bujur', 71.091)

Jika Anda ingin memformat dengan cara arbitrer, artinya, tidak menampilkan nilai kunci seperti tupel:

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

Keluaran:

lintang adalah 41.123 dan bujur adalah 71.091


perhatikan ada kemungkinan 'bujur' bisa datang sebelum 'lintang' dari geopoint.items();)
Tcll
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.