Store formatted strings, pass in values later? - python

I have a dictionary with a lot of strings.
Is it possible to store a formatted string with placeholders and pass in a actual values later?
I'm thinking of something like this:
d = {
"message": f"Hi There, {0}"
}
print(d["message"].format("Dave"))
The above code obviously doesn't work but I'm looking for something similar.

You use f-string; it already interpolated 0 in there. You might want to remove f there
d = {
# no f here
"message": "Hi There, {0}"
}
print(d["message"].format("Dave"))
Hi There, Dave

Issue: mixing f-String with str.format
Technique
Python version
f-String
since 3.6
str.format
since 2.6
Your dict-value contains an f-String which is immediately evaluated.
So the expression inside the curly-braces (was {0}) is directly interpolated (became 0), hence the value assigned became "Hi There, 0".
When applying the .format argument "Dave", this was neglected because string already lost the templating {} inside. Finally string was printed as is:
Hi There, 0
Attempt to use f-String
What happens if we use a variable name like name instead of the constant integer 0 ?
Let's try on Python's console (REPL):
>>> d = {"message": f"Hi There, {name}"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'name' is not defined
OK, we must define the variable before. Let's assume we did:
>>> name = "Dave"; d = {"message": f"Hi There, {name}"}
>>> print(d["message"])
Hi There, Dave
This works. But it requires the variable or expression inside the curly-braces to be valid at runtime, at location of definition: name is required to be defined before.
Breaking a lance for str.format
There are reasons
when you need to read templates from external sources (e.g. file or database)
when not variables but placeholders are configured independently from your source
Then indexed-placeholders should be preferred to named-variables.
Consider a given database column message with value "Hello, {1}. You are {0}.". It can be read and used independently from the implementation (programming-language, surrounding code).
For example
in Java: MessageFormat.format(message, 74, "Eric")
in Python: message.format(74, 'Eric').
See also:
Format a message using MessageFormat.format() in Java

Related

Python print output containing two variables?

I'm very new to Python and working with an existing python script, presently it outputs a message with a variable tagged on the end:
print "ERROR: did not find any details inside \"{0}".format(filename)
I want to modify this adding in another variable so the output reads:
print "ERROR: did not find \"{name}\" inside \"{file}\""
Where {name} and {file} are replaced with the variables, what is the correct way to achieve this?
In Python 2, you can use format to pass named parameters and it plugs the names into the variables. Note you can quote strings with single quotes or double quotes, so you can prevent having to escape double quotes by using single quotes:
>>> name = 'John'
>>> file = 'hello.txt'
>>> print 'ERROR: did not find "{name}" inside "{file}"'.format(name=name,file=file)
ERROR: did not find "John" inside "hello.txt"
A shortcut for this is to use the ** operator to pass a dictionary of key/value pairs as parameters. locals() returns all the local variables in this format, so you can use this pattern:
>>> name = 'John'
>>> file = 'hello.txt'
>>> print 'ERROR: did not find "{name}" inside "{file}"'.format(**locals())
ERROR: did not find "John" inside "hello.txt"
Python 3.6+ makes this cleaner with f-strings:
>>> name = 'John'
>>> file = 'hello.txt'
>>> print(f'ERROR: did not find "{name}" in "{file}"')
ERROR: did not find "John" in "hello.txt"
You seem to be using Python 2, so the correct way would be like:
print "ERROR: did not find \"{0}\" inside \"{1}\"".format(name, file)
{0} means to take the first argument from the format() argument list and so on.
Moving to Python 3 and f-strings is preferable, all other things being equal.
.format is a very useful method in python. Check this link for better understanding. https://www.w3schools.com/python/ref_string_format.asp
I hope the examples will help you understand the method well.
You can also try this:
print "ERROR: did not find \"{}\" inside \"{}\"".format(name, file)
f"ERROR: did not find \{name}\ inside \{file}\"
If you need to encapsulate the variables, you just need to put f which means format string so that instead of just printing it out it inserts the value of the variable.

Use Python reserved words in an XML File

I'm currently trying to use python's (3.6) xml.etree.ElementTree commands to write an xml file. Some of the Elements and Subelements I need to write must have "id" and "map" fields, which are reserved python words.
My problem is contained in the following line of code:
ET.SubElement(messages,'trigger',thing='1',bob='a', max='5')
But "max" is a function and I can't use it. Is there a character I can place there to allow me to write this field as I desire? Or some sort of known workaround?
EDIT: I am aware that an '_' stops the python from processing the word, but unfortunately this underscore will show up in my file...so I am trying to see if there is an 'invisible' option for the file I will later be writing.
Thanks much!
Python functions are no problem in the left side of a keyword expression:
>>> def abc(**kwargs):
print kwargs
>>> abc(id=2)
{'id': 2}
>>>
id, map, int, float, str, repr, etc. are built in symbols, not reserved words. You may use them like any other bunch of letters, but assigning it another value replaces the built in symbol:
>>> int(2.5)
2
>>> int = "5"
>>> int(2.5)
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
int(2.5)
TypeError: 'str' object is not callable
Notice how the first line is entirely legal, but will trigger a warning if you have a good IDE like pycharm.
If you want to send a actual reserved word to a function, like print, None, yield, or try, you can use the double star ** to convert a dictionary into keyword arguments, for example:
>>> abc(**{"print":2, "None":3})
{'print': 2, 'None': 3}
I hope this answers your question!

Python string formatting of multi-level dict

A common technique for rendering values from template strings looks like this:
>>> num = 7
>>> template = 'there were {num} dwarves'
>>> print template.format(**locals())
there were 7 dwarves
This approach works for any data type that has a __str__ method, e.g. dicts:
>>> data = dict(name='Bob', age=43)
>>> template = 'goofy example 1 {data}'
>>> print template.format(**locals())
goofy example 1 {'age': 43, 'name': 'Bob'}
However it doesn't work when a dict item is referenced by key:
>>> template = 'goofy example 2 {data["name"]}'
>>> print template.format(**locals())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: '"name"'
It's inconvenient, and seems odd, that an identifier that's valid in code outside the format string is invalid when used within the format string. Am I missing something? Is there a way to do this?
I'd like to be able to reference an element several layers down in a nested dictionary structure, like somedict['level1key']['level2key']['level3key']. So far my only workable approach has been to copy these values to a scalar variable just for string formatting, which is icky.
You can do it by using {data[name]} instead of {data["name"]} in the string.
The types of things you can specify in a format string are restricted. Arbitrary expressions aren't allowed, and keys are interpreted in a simplified way, as described in the documentation:
it is not possible to specify arbitrary dictionary keys (e.g., the strings '10' or ':-]') within a format string.
In this case, you can get your key out because it's a simple alphanumeric string, but, as the docs suggest, you can't always necessarily do it. If you have weird dict keys, you may have to change them to use them in a format string, or resort to other methods (like concatening string values explicitly with +).

Replacing a substring of a string with Python

I'd like to get a few opinions on the best way to replace a substring of a string with some other text. Here's an example:
I have a string, a, which could be something like "Hello my name is $name". I also have another string, b, which I want to insert into string a in the place of its substring '$name'.
I assume it would be easiest if the replaceable variable is indicated some way. I used a dollar sign, but it could be a string between curly braces or whatever you feel would work best.
Solution:
Here's how I decided to do it:
from string import Template
message = 'You replied to $percentageReplied of your message. ' +
'You earned $moneyMade.'
template = Template(message)
print template.safe_substitute(
percentageReplied = '15%',
moneyMade = '$20')
Here are the most common ways to do it:
>>> import string
>>> t = string.Template("Hello my name is $name")
>>> print t.substitute(name='Guido')
Hello my name is Guido
>>> t = "Hello my name is %(name)s"
>>> print t % dict(name='Tim')
Hello my name is Tim
>>> t = "Hello my name is {name}"
>>> print t.format(name='Barry')
Hello my name is Barry
The approach using string.Template is easy to learn and should be familiar to bash users. It is suitable for exposing to end-users. This style became available in Python 2.4.
The percent-style will be familiar to many people coming from other programming languages. Some people find this style to be error-prone because of the trailing "s" in %(name)s, because the %-operator has the same precedence as multiplication, and because the behavior of the applied arguments depends on their data type (tuples and dicts get special handling). This style has been supported in Python since the beginning.
The curly-bracket style is only supported in Python 2.6 or later. It is the most flexible style (providing a rich set of control characters and allowing objects to implement custom formatters).
There are a number of ways to do it, the more commonly used would be through the facilities already provided by strings. That means the use of the % operator, or better yet, the newer and recommended str.format().
Example:
a = "Hello my name is {name}"
result = a.format(name=b)
Or more simply
result = "Hello my name is {name}".format(name=b)
You can also use positional arguments:
result = "Hello my name is {}, says {}".format(name, speaker)
Or with explicit indexes:
result = "Hello my name is {0}, says {1}".format(name, speaker)
Which allows you to change the ordering of the fields in the string without changing the call to format():
result = "{1} says: 'Hello my name is {0}'".format(name, speaker)
Format is really powerful. You can use it to decide how wide to make a field, how to write numbers, and other formatting of the sort, depending on what you write inside the brackets.
You could also use the str.replace() function, or regular expressions (from the re module) if the replacements are more complicated.
Checkout the replace() function in python. Here is a link:
http://www.tutorialspoint.com/python/string_replace.htm
This should be useful when trying to replace some text that you have specified. For example, in the link they show you this:
str = "this is string example....wow!!! this is really string"
print str.replace("is", "was")
For every word "is", it would replace it with the word "was".
Actually this is already implemented in the module string.Template.
You can do something like:
"My name is {name}".format(name="Name")
It's supported natively in python, as you can see here:
http://www.python.org/dev/peps/pep-3101/
You may also use formatting with % but .format() is considered more modern.
>>> "Your name is %(name)s. age: %(age)i" % {'name' : 'tom', 'age': 3}
'Your name is tom'
but it also supports some type checking as known from usual % formatting:
>>> '%(x)i' % {'x': 'string'}
Traceback (most recent call last):
File "<pyshell#40>", line 1, in <module>
'%(x)i' % {'x': 'string'}
TypeError: %d format: a number is required, not str

String formatting named parameters?

I know it's a really simple question, but I have no idea how to google it.
how can I do
print '%s' % (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 :)
print '%(url)s' % {'url': my_url}
In Python 2.6+ and Python 3, you might choose to use the newer string formatting method.
print('{0}'.format(my_url))
which saves you from repeating the argument, or
print('{url}'.format(url=my_url))
if you want named parameters.
print('{}'.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('{}'.format(my_url, my_url, not_my_url=her_url))
But not this...
print('{}'.format(my_url, not_my_url=her_url, my_url))
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'{my_url:s}')
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.
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
For building HTML pages, you want to use a templating engine, not simple string interpolation.
Another option is to use format_map:
print('{s}'.format_map({'s': 'my_url'}))
As well as the dictionary way, it may be useful to know the following format:
print '%s' % (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.
I recommend this syntax
dictionary_of_string_values = {
"my_text" : "go to w3schools",
"my_url" : "https://www.w3schools.com",
}
print ('{my_text}'.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 ('{my_text}'.format(
**{
"my_text" : "go to w3schools",
"my_url" : "https://www.w3schools.com",
}
)
)

Categories

Resources