158

I know it's a really simple question, but I have no idea how to google it.

how can I do

print '<a href="%s">%s</a>' % (my_url)

So that my_url is used twice? I assume I have to "name" the %s and then use a dict in the params, but I'm not sure of the proper syntax?


just FYI, I'm aware I can just use my_url twice in the params, but that's not the point :)

Ben Blank
  • 54,908
  • 28
  • 127
  • 156
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • The title of the question is a bit misleading. This has nothing to do with the print statement, just with how string interpolation works. – Greg Ball Mar 16 '10 at 05:47
  • When you have no idea how to google it, go here to use search: http://python.org/doc/. It's better than Google for one important reason. – S.Lott Mar 16 '10 at 10:20
  • 1
    @S.Lott [That's really helpful](https://www.python.org/search/?q=String+formatting+named+parameters&submit=) /s – mpen Sep 04 '15 at 17:50

8 Answers8

236
print '<a href="%(url)s">%(url)s</a>' % {'url': my_url}
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 3
    I prefer creating the dict with kwargs: `'%(url)s' % dict(url=my_url)` – schlamar Oct 14 '13 at 07:23
  • 11
    I wonder why you prefer that schmlamar? I would not have readily known what that meant, compared the the normal declaration of a dict that the OP uses... – GreenAsJade Oct 25 '13 at 10:38
  • 1
    The **[documentation](https://docs.python.org/2/library/stdtypes.html#string-formatting)** doesn't say when this was introduced, so it's probably in all Python 2 versions. – Evgeni Sergeev Sep 12 '15 at 11:25
  • 2
    Use format() if you can, it works better and in more places. Use % if you MUST. – uchuugaka Apr 05 '17 at 06:44
105

In Python 2.6+ and Python 3, you might choose to use the newer string formatting method.

print('<a href="{0}">{0}</a>'.format(my_url))

which saves you from repeating the argument, or

print('<a href="{url}">{url}</a>'.format(url=my_url))

if you want named parameters.

print('<a href="{}">{}</a>'.format(my_url, my_url))

which is strictly positional, and only comes with the caveat that format() arguments follow Python rules where unnamed args must come first, followed by named arguments, followed by *args (a sequence like list or tuple) and then *kwargs (a dict keyed with strings if you know what's good for you). The interpolation points are determined first by substituting the named values at their labels, and then positional from what's left. So, you can also do this...

print('<a href="{not_my_url}">{}</a>'.format(my_url, my_url, not_my_url=her_url))

But not this...

print('<a href="{not_my_url}">{}</a>'.format(my_url, not_my_url=her_url, my_url))
uchuugaka
  • 12,679
  • 6
  • 37
  • 55
Greg Ball
  • 3,671
  • 3
  • 22
  • 15
  • 1
    It's nice to see the influence shift from ++ to # – cod3monk3y Jan 28 '14 at 23:29
  • 3
    The above method is not for *named* string formatting though, this is positional string formatting. So this does not really answer the question. – jaapz Nov 10 '14 at 12:55
  • 1
    The `"literal {arg1}".format(arg1="arg!")` named format works with Python 3.5, whereas the terser `f"literal {arg1}"` is a newer innovation in Python 3.6 or newer, AFAIK. – MarkHu Aug 23 '19 at 21:14
  • 1
    The comment from @jaapz is no longer valid considering the changes to this answer that include the non-positional syntax `print('{url}'.format(url=my_url))`. This works great both with Python 2 and 3. – Danila Vershinin Sep 13 '20 at 12:50
  • @uchuugaka The examples you added, even the "you can do this" one, has two placeholders but three arguments. You need to drop the second `my_url`. (Although it seems like it does still work - it's just silently ignored by Python, which is a surprise to me.) – Arthur Tacca Dec 09 '22 at 15:39
  • It’s not ignored exactly. Reread my explanation. – uchuugaka Dec 10 '22 at 17:25
48

Solution in Python 3.6+

Python 3.6 introduces literal string formatting, so that you can format the named parameters without any repeating any of your named parameters outside the string:

print(f'<a href="{my_url:s}">{my_url:s}</a>')

This will evaluate my_url, so if it's not defined you will get a NameError. In fact, instead of my_url, you can write an arbitrary Python expression, as long as it evaluates to a string (because of the :s formatting code). If you want a string representation for the result of an expression that might not be a string, replace :s by !s, just like with regular, pre-literal string formatting.

For details on literal string formatting, see PEP 498, where it was first introduced, and PEP 701, where permitted syntax was extended (starting with Python 3.12).

gerrit
  • 24,025
  • 17
  • 97
  • 170
  • 2
    That PEP doesn't seem to cover all the formatters; I think they're the same as str.format which is documented here: https://docs.python.org/3.4/library/string.html#formatstrings – mpen Feb 05 '20 at 19:20
7

You will be addicted to syntax.

Also C# 6.0, EcmaScript developers has also familier this syntax.

In [1]: print '{firstname} {lastname}'.format(firstname='Mehmet', lastname='Ağa')
Mehmet Ağa

In [2]: print '{firstname} {lastname}'.format(**dict(firstname='Mehmet', lastname='Ağa'))
Mehmet Ağa
guneysus
  • 6,203
  • 2
  • 45
  • 47
5

For building HTML pages, you want to use a templating engine, not simple string interpolation.

Mike Graham
  • 73,987
  • 14
  • 101
  • 130
  • I'm using Django, but this is going into an email. – mpen Mar 16 '10 at 03:26
  • 2
    Django's templating engine may also prove to be the ideal tool for the emails you are making. – Mike Graham Mar 16 '10 at 03:30
  • 6
    What's stopping you from using a Django template to generate an email body with its `render()` method? Nothing says you have to feed template output to `HttpResponse()`. Django is *embarrassingly* versatile. – Mike DeSimone Mar 16 '10 at 03:32
  • 1
    @Mike: I *thought* Django might have a solution for this too, but I hadn't found it yet :p I probably will move my emails into templates then! Thanks. Maybe I'm 'tarded, but I've found it to be pretty rigid in some areas. – mpen Mar 16 '10 at 05:09
  • 2
    @random people that read these comments: found more detail on how to do that here http://www.rossp.org/blog/2006/jul/11/sending-e-mails-templates/ – mpen Mar 16 '10 at 05:18
  • 2
    For commenting on questions, you want to use comments, not answers. – suriv Oct 01 '14 at 04:37
4

Another option is to use format_map:

print('<a href="{s}">{s}</a>'.format_map({'s': 'my_url'}))
Danny Varod
  • 17,324
  • 5
  • 69
  • 111
2

As well as the dictionary way, it may be useful to know the following format:

print '<a href="%s">%s</a>' % (my_url, my_url)

Here it's a tad redundant, and the dictionary way is certainly less error prone when modifying the code, but it's still possible to use tuples for multiple insertions. The first %s is substituted for the first element in the tuple, the second %s is substituted for the second element in the tuple, and so on for each element in the tuple.

Ponkadoodle
  • 5,777
  • 5
  • 38
  • 62
  • I just told a guy off for suggesting this :) He deleting his post. I feel kind of bad now. Yes, I'm aware I can do this, but it just wasn't what I was looking for. As you said, it's redundant, and `my_url` is actually a function call that I don't want to have to be evaluated twice. Twice isn't so bad, but it could just have easily been 20 times :) – mpen Mar 16 '10 at 03:31
  • 5
    I figured I'd keep mine, just in case it helps somebody else. Well the dictionary way is likely the best way to go. But for redundancy, `(get_my_url(), )*20` only calls the function once, and duplicates it 20 times. – Ponkadoodle Mar 16 '10 at 03:36
1

I recommend this syntax

dictionary_of_string_values = {
                               "my_text" : "go to w3schools",
                               "my_url" : "https://www.w3schools.com",
                               }

print ('<a href="{my_url}">{my_text}</a>'.format(**dictionary_of_string_values))

It is very useful when you have to format a string with lots of placeholders.

You can also make it shorter like this:

print ('<a href="{my_url}">{my_text}</a>'.format(
                             **{
                               "my_text" : "go to w3schools",
                               "my_url" : "https://www.w3schools.com",
                               }
                            )
                        )
Tms91
  • 3,456
  • 6
  • 40
  • 74