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.

Kasta
źródło
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
1
Co zatem o tym sądzisz? stackoverflow.com/questions/16504732/…
SalchiPapa
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"))
Sven Marnach
źródło
@ 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!")
EinLama
źródło
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}."
Syrus Akbary Nieto
źródło
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

Oleiade
źródło
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
28

Interpolacja ciągów zostanie uwzględniona w Pythonie 3.6, jak określono w PEP 498 . Będziesz mógł to zrobić:

name = 'Spongebob Squarepants'
print(f'Who lives in a Pineapple under the sea? \n{name}')

Zauważ, że nienawidzę Spongeboba, więc napisanie tego było nieco bolesne. :)

kirbyfan64sos
źródło
Dzięki za odniesienie do Spongebob (/ distast): muszę to teraz głosować.
javadba
4

Możesz też to mieć

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

http://docs.python.org/2/library/string.html#formatstrings

Quan To
źródło
Nie sądzę, żeby OP zamierzał #je wydrukować. Po prostu używają składni Ruby.
jaynp,
Masz rację. Zredagowałem odpowiedź. Nie znam Ruby, więc pomyślałem, że #postać zostanie wydrukowana.
Quan do
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:

Paulo Check
źródło
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
Michael Fox
źródło