5

Recently, I found ''.format function very useful because it can improve readability a lot comparing to the % formatting. Trying to achieve simple string formatting:

data = {'year':2012, 'month':'april', 'location': 'q2dm1'}

year = 2012
month = 'april'
location = 'q2dm1'
a = "year: {year}, month: {month}, location: {location}"
print a.format(data)
print a.format(year=year, month=month, location=location)
print a.format(year, month, location)

Whilst two first prints do format as I expect (yes, something=something looks ugly, but that's an example only), the last one would raise KeyError: 'year'. Is there any trick in python to create dictionary so it will automatically fill keys and values, for example somefunc(year, month, location) will output {'year':year, 'month': month, 'location': location}?

I'm pretty new to python and couldn't find any info on this topic, however a trick like this would improve and shrink my current code drastically.

Thanks in advance and pardon my English.

5 Answers 5

6

The first print should be

print a.format(**data)

Also, if you are finding some shortcuts, you could write one like, no big difference.

def trans(year, month, location):
    return dict(year=year, month=month, location=location)
Sign up to request clarification or add additional context in comments.

2 Comments

Seems there's no way to shrink this repeating code:) Function is good and it was what i did, actually, but later i found it hard to sustain because with lots of arguments i needed to change code in several places, which turned out to be even worse than actually creating dict by hands.
@duke_nukem yes it depends on your actual usage. The code is fine and the format api is clear enough. If you what to achieve something like format(*args, **kwargs), it could be done also, but I don't think it could make things easier.
3
data = {'year':2012, 'month':'april', 'location': 'q2dm1'}
a = "year: {year}, month: {month}, location: {location}"

print a.format(**data)

..is what you are looking for. It's functionally identical to doing .format(year=data['year'], ...), or the other examples you gave.

The double-asterix thing is a hard thing to search for, so it's usually referred to as "kwargs". Here's a good SO question on this syntax

Comments

1

You can use the dict() callable:

dict(year=yeah, month=month, location=location)

When passing keyword arguments it creates a dict containing the elements you specified as kwargs.

If you do not want to specify the argument names, use the positional style of .format():

>>> a = 'year {0} month {1} location {2}'
>>> print a.format(2012, 'april', 'abcd')
year 2012 month april location abcd

However, if you try to do something similar to what compact() in PHP does (create a dict mapping variable names to its values without specifying name and variable separately), please don't. It just results in ugly unreadable code and would require nasty hacks anyway.

6 Comments

Yes, i'm aware of dict() but i'm trying to avoid unnecessary code and shrink it down a bit. .format can accept your option without dict() by the way. Thank you.
Thanks, it's close to what i need, however with 10-12 arguments it becomes pretty hard to navigate through indices.
Well in this case you are supposed to use the dict syntax. However, depending on what you want to do, consider using a real template engine such as jinja2.
Thanks for the template direction.
Also, just adding, dict is not a function. dict is a type.
|
1

You could pass locals():

a.format(**locals())

Of course, this has issues: you will have to pass everything in locals, and it can be difficult to understand the effect of renaming or removing a variable.

A better way would be:

a.format(**{k:v for k,v in locals() if k in ('year', 'month')})
# or; note that if you move the lambda expression elsewhere, you will get a different result
a.format(**(lambda ld = locals(): {k:ld[k] for k in ('year', 'month')})())

But this is not any more concise, unless you wrap it up with a function (which must of course take a dict parameter).

Comments

0

As of Python 3.6, you can also use the new Formatted string literals (f-strings), which you can use with variables:

year = 2012
month = 'april'
location = 'q2dm1'
a = f"year: {year}, month: {month}, location: {location}"
print(a)

or a dictionary:

data = {'year': 2012, 'month': 'april', 'location': 'q2dm1'}
a = f"year: {data['year']}, month: {data['month']}, location: {data['location']}"
print(a)

Note the f prefix before the string literal.

PEP 498: Formatted string literals:

Formatted string literals are prefixed with 'f' and are similar to the format strings accepted by str.format(). They contain replacement fields surrounded by curly braces. The replacement fields are expressions, which are evaluated at run time, and then formatted using the format() protocol:

>>>
>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'

...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.