ฉันจะจัดรูปแบบสตริงโดยใช้พจนานุกรมใน python-3.x ได้อย่างไร


215

ฉันเป็นแฟนตัวยงของการใช้พจนานุกรมเพื่อจัดรูปแบบสตริง มันช่วยให้ฉันอ่านรูปแบบสตริงที่ฉันใช้รวมถึงให้ฉันได้ประโยชน์จากพจนานุกรมที่มีอยู่ ตัวอย่างเช่น:

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

อย่างไรก็ตามฉันไม่สามารถเข้าใจไวยากรณ์ของ python 3.x สำหรับการทำสิ่งเดียวกัน (หรือถ้าเป็นไปได้) ฉันต้องการทำดังต่อไปนี้

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

คำตอบ:


15

เนื่องจากคำถามเฉพาะเจาะจงกับ Python 3 นี่คือการใช้ไวยากรณ์สตริง f ใหม่ซึ่งมีให้ตั้งแต่ Python 3.6:

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

หมายเหตุเครื่องหมายอัญประกาศเดี่ยวด้านนอกและเครื่องหมายอัญประกาศคู่ด้านใน (คุณสามารถทำอีกวิธีหนึ่งได้


ฉันจะบอกว่าการใช้ f-string นั้นสอดคล้องกับแนวทางของ python3 มากกว่า
Jonatas CD

2
โปรดจำไว้ว่า f-strings นั้นใหม่สำหรับ Python 3.6 และไม่ใช่ใน 3.5
Hugo

409

เป็นสิ่งที่ดีสำหรับคุณ

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

2
ลองใช้วิธีนี้และใช้งานได้ แต่ฉันไม่เข้าใจการใช้ 'สัญลักษณ์ตัวชี้' ฉันรู้ว่า Python ไม่ได้ใช้พอยน์เตอร์นี่เป็นตัวอย่างของ kwargs หรือไม่
Homunculus Reticulli

2
@HomunculusReticulli นั่นคือพารามิเตอร์รูปแบบ (ความกว้างของเขตข้อมูลขั้นต่ำ) ไม่ใช่ตัวชี้ไปยังลักษณะตัวชี้ C ++ docs.python.org/release/2.4.4/lib/typesseq-strings.html
D.Rosado

29
งูหลาม 3.2 format_mapแนะนำ คล้ายกับการstr.format(**mapping)ยกเว้นว่าจะใช้โดยตรงและไม่ได้คัดลอกไปยังmapping dictสิ่งนี้มีประโยชน์ถ้าเช่นmappingเป็น subclass dict
diapir

1
@eugene ** ทำอะไรกับพจนานุกรมหลาม? ฉันไม่คิดว่ามันจะสร้างวัตถุเพราะ print (** geopoint) ไม่สามารถให้ข้อผิดพลาดทางไวยากรณ์ได้
Nityesh Agarwal

4
@NityeshAgarwal มันจะกระจายพจนานุกรมที่มีชื่อ = คู่ค่าเป็นข้อโต้แย้งของแต่ละบุคคลเช่นเป็นเช่นเดียวกับprint(**geopoint) print(longitude=71.091, latitude=41.123)ในหลายภาษามันเป็นที่รู้จักในฐานะผู้ประกอบการเครื่องหมาย ใน JavaScript เรียกว่าตัวดำเนินการสเปรด ในหลามไม่มีชื่อเฉพาะที่กำหนดให้กับผู้ประกอบการนี้
abhisekp

79

**จะแกะพจนานุกรมเข้าไปในข้อโต้แย้งคำหลักที่ใช้ นอกจากนี้การจัดรูปแบบสไตล์ใหม่ยังสนับสนุนการอ้างถึงคุณสมบัติของวัตถุและรายการการแมป:

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

2
ฉันพบคำตอบนี้ดีกว่าเนื่องจากการเพิ่มดัชนีตำแหน่งสำหรับตัวยึดตำแหน่งทำให้โค้ดชัดเจนขึ้นและใช้งานง่ายขึ้น โดยเฉพาะอย่างยิ่งหากมีบางสิ่งบางอย่างเช่นนี้:'{0[latitude]} {1[latitude]} {0[longitude]} {1[longitude]}'.format(geopoint0, geopoint1)
Løiten

1
สิ่งนี้มีประโยชน์หากคุณใช้ a defaultdictและไม่มีกุญแจทั้งหมด
Whymarrh

65

เนื่องจาก Python 3.0 และ 3.1 เป็น EOL'ed และไม่มีใครใช้คุณสามารถและควรใช้str.format_map(mapping)(Python 3.2+):

คล้ายกับstr.format(**mapping), ยกเว้นการทำแผนที่ที่ใช้โดยตรงและไม่ได้คัดลอกไปยัง dictสิ่งนี้มีประโยชน์หากตัวอย่างเช่นการจับคู่เป็นdictคลาสย่อย

สิ่งนี้หมายความว่าคุณสามารถใช้ตัวอย่างเช่นdefaultdictที่จะตั้งค่า (และกลับ) ค่าเริ่มต้นสำหรับคีย์ที่หายไป:

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

แม้ว่าการแมปที่ให้ไว้จะdictไม่ใช่คลาสย่อย แต่ก็อาจเร็วกว่านี้เล็กน้อย

ความแตกต่างนั้นไม่ใหญ่มากนัก

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

แล้วก็

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

เร็วกว่าประมาณ 10 ns (2%)

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

บน Python ของฉัน 3.4.3 ความแตกต่างอาจจะมีขนาดใหญ่ขึ้นเนื่องจากมีปุ่มมากกว่าอยู่ในพจนานุกรมและ


โปรดทราบว่าภาษารูปแบบมีความยืดหยุ่นมากกว่านั้น พวกเขาสามารถมีการแสดงออกดัชนีการเข้าถึงคุณลักษณะและอื่น ๆ เพื่อให้คุณสามารถจัดรูปแบบวัตถุทั้งหมดหรือ 2 ของพวกเขา:

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

เริ่มต้นที่ 3.6 คุณสามารถใช้สตริงที่สอดแทรกเช่นกัน:

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

คุณต้องจำไว้ว่าให้ใช้อักขระเครื่องหมายคำพูดอื่นภายในเครื่องหมายคำพูดซ้อน ข้อดีอีกข้อของวิธีนี้ก็คือมันเร็วกว่าการเรียกวิธีการจัดรูปแบบ


เยี่ยมมากมีการปรับปรุงประสิทธิภาพมากกว่านี้formatหรือไม่ (ระบุว่าจะไม่คัดลอกไปยัง dict)
Bhargav Rao

2
@ BhargavRao ไม่มาก 2%: D
Antti Haapala

@BhargavRao หากคุณกำลังมองหาประสิทธิภาพให้ใช้สิ่งนี้'%(latitude)s %(longitude)s'%geopoint;)
Tcll


6

ไวยากรณ์ Python 2 ทำงานใน 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

รวมทั้งมันเป็นนักแสดงที่เด่นชัดกว่าf""หรือ"".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
คุณพลาดอย่างใดอย่างหนึ่ง;) print('%(latitude)s %(longitude)s'%geopoint)สิ่งนี้ยังเร็วกว่าอีก 2
Tcll

@tcll ที่จริงฉันต้องการตัวอย่างที่ฉันสามารถใช้ชื่อพจนานุกรมภายในสตริง บางสิ่งเช่นนี้'%(geopoint["latitude"])s %(geopoint["longitude"])s'%{"geopoint":geopoint}
Sheikh Abdul Wahid

1

คำตอบส่วนใหญ่จะจัดรูปแบบเฉพาะค่าของ dict

หากคุณต้องการจัดรูปแบบคีย์เป็นสตริงคุณสามารถใช้dict.items () :

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

เอาท์พุท:

('ละติจูด', 41.123) ('ลองจิจูด', 71.091)

หากคุณต้องการจัดรูปแบบโดยพลการนั่นคือไม่แสดงคีย์ - ค่าเช่นทูเปิล:

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

เอาท์พุท:

ละติจูดคือ 41.123 และลองจิจูดคือ 71.091


โปรดทราบว่ามี 'ลองจิจูด' ที่อาจเกิดขึ้นก่อน 'ละติจูด' จากgeopoint.items();)
Tcll
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.