Czy istnieje Python równoważny interpolacji ciągów Ruby?


343

Rubinowy przykład:

name = "Spongebob Squarepants"
puts "Who lives in a Pineapple under the sea? \n#{name}."

Udana konkatenacja ciągów w języku Python jest dla mnie pozornie gadatliwa.


2
Problem polega na tym, że namezmienna lokalna leży w ciągu, aw Pythonie musisz jawnie przekazać słownik zmiennych lokalnych do formatera ciągu, jeśli chcesz, aby z nich korzystał.
Katriel

To nie był oryginalny problem, ale dzięki. Twój komentarz dał mi trochę lepsze zrozumienie zmiennego zakresu (coś, co wciąż zyskuje na popularności). :)
Caste



2
Zobacz stackoverflow.com/a/33264516/55721 dla tej dokładnej funkcji w 3.6
dss539,

Odpowiedzi:


413

Python 3.6 doda dosłowną interpolację łańcuchów podobną do interpolacji łańcuchów Ruby. Począwszy od tej wersji Pythona (która ma zostać wydana do końca 2016 r.), Będziesz mógł dołączyć wyrażenia do „f-string”, np.

name = "Spongebob Squarepants"
print(f"Who lives in a Pineapple under the sea? {name}.")

Przed wersją 3.6 najbliżej tego można się dostać

name = "Spongebob Squarepants"
print("Who lives in a Pineapple under the sea? %(name)s." % locals())

%Operator może być używany do interpolacji smyczkowy w Pythonie. Pierwszy argument jest ciągiem, który ma być interpolowany, drugi może mieć różne typy, w tym „mapowanie”, odwzorowywanie nazw pól na wartości, które mają być interpolowane. Tutaj użyłem słownika zmiennych lokalnych locals()do mapowania nazwy pola namena jego wartość jako zmiennej lokalnej.

Ten sam kod przy użyciu .format()metody najnowszych wersji Pythona wyglądałby następująco:

name = "Spongebob Squarepants"
print("Who lives in a Pineapple under the sea? {name!s}.".format(**locals()))

Jest też string.Templateklasa:

tmpl = string.Template("Who lives in a Pineapple under the sea? $name.")
print(tmpl.substitute(name="Spongebob Squarepants"))

@ Wklej zobacz tutaj: docs.python.org/library/stdtypes.html#string-formatting i opublikuj komentarz uzupełniający, jeśli potrzebujesz więcej szczegółów
mikej

Rozumiem jego zasadniczą treść, jednak nie w pełni rozumiem wszystkie dodatkowe symbole i tekst znalezione w przykładzie w dokumentacji. Dlaczego użycie konwersji na ciąg tutaj:% (język) s Co oznaczają cyfry 3 w '03d'? Dlaczego po ciągu jest% \? Przypisanie zmiennych (jeśli tak naprawdę są zmiennymi) po wyrażeniu print, również mnie dezorientuje. Przepraszam, jeśli to jest ból!
Caste,

1
Dwa podstawowe formaty użyte w tym przykładzie dotyczą %słańcucha i %03dliczby dopełnianej do 3 cyfr z zerami wiodącymi. Można to po prostu napisać print "%s has %03d" % ("Python", 2). W przykładzie wykorzystano następnie umieszczenie klucza nawiasowego w nawiasach, po %którym można nadać symbolom zastępczym znaczące nazwy, a nie polegać na ich kolejności w ciągu. Następnie przekazujesz słownik, który mapuje nazwy kluczy na ich wartości. Właśnie dlatego Sven korzysta z locals()funkcji, która zwraca dykt zawierający wszystkie zmienne lokalne, dzięki czemu będzie name
mapowany

Wymagane użycie typu konwersji było tym, co wprawiło mnie w zakłopotanie. Tak więc, używając terminologii dokumentacji. % Uruchamia specyfikator. Nie ma flagi konwersji dla (języka), tylko typ konwersji (końcowe); (liczba) ma jednak jedną (lub dwie) flagi konwersji, które wynoszą odpowiednio „0” (i „3”). „D” jest rodzajem konwersji i oznacza, że ​​jest liczbą całkowitą. Czy zrozumiałem poprawnie?
Caste,

@Caste: Tak, to w zasadzie prawda. Zauważ, że zawsze możesz użyć sjako typu konwersji - Python może konwertować prawie wszystko na ciąg. Ale oczywiście straciłbyś specjalne możliwości formatowania innych typów konwersji.
Sven Marnach,

143

Od wersji Python 2.6.X możesz użyć:

"my {0} string: {1}".format("cool", "Hello there!")

27
Zauważ, że %operator interpolacji łańcuchów nie jest przestarzały w Pythonie 3.x. docs.python.org/dev/py3k/whatsnew/… ogłasza plan wycofania się %z wersji 3.1, ale tak się nigdy nie stało.
Sven Marnach,

8
% -syntax nadal żyje w Pythonie 3 (nie jest przestarzałe w Pythonie 3.2)
Corey Goldberg

9
Tylko uwaga: podany numer {}można wyeliminować.
losowanie

32

Opracowałem pakiet interpy , który umożliwia interpolację łańcuchów w Pythonie .

Wystarczy zainstalować za pośrednictwem pip install interpy. A następnie dodaj linię # coding: interpyna początku swoich plików!

Przykład:

#!/usr/bin/env python
# coding: interpy

name = "Spongebob Squarepants"
print "Who lives in a Pineapple under the sea? \n#{name}."

3
To wydaje się naprawdę niepewne.
d33tah

@ d33tah: Nie, o ile łańcuchy są znane w czasie kompilacji.
Clément

28

Interpolacja ciągów znaków w Pythonie jest podobna do printf () C

Jeśli spróbujesz:

name = "SpongeBob Squarepants"
print "Who lives in a Pineapple under the sea? %s" % name

Tag %szostanie zastąpiony namezmienną. Powinieneś spojrzeć na tagi funkcji drukowania: http://docs.python.org/library/functions.html


1
jak mogę to zrobić z 2 zmiennymi?
Julio Marins,

16
@JulioMarins Użyj krotki: print "First is %s, second is %s" % (var1, var2).
kirbyfan64sos



3
import inspect
def s(template, **kwargs):
    "Usage: s(string, **locals())"
    if not kwargs:
        frame = inspect.currentframe()
        try:
            kwargs = frame.f_back.f_locals
        finally:
            del frame
        if not kwargs:
            kwargs = globals()
    return template.format(**kwargs)

Stosowanie:

a = 123
s('{a}', locals()) # print '123'
s('{a}') # it is equal to the above statement: print '123'
s('{b}') # raise an KeyError: b variable not found

PS: wydajność może stanowić problem. Jest to przydatne w przypadku skryptów lokalnych, a nie dzienników produkcyjnych.

Powielone:


2

W przypadku starego Pythona (testowanego w wersji 2.4) najlepsze rozwiązanie wskazuje drogę. Możesz to zrobić:

import string

def try_interp():
    d = 1
    f = 1.1
    s = "s"
    print string.Template("d: $d f: $f s: $s").substitute(**locals())

try_interp()

I dostajesz

d: 1 f: 1.1 s: s

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.