How to implement conditional string formatting? [duplicate] - python

This question already has answers here:
Does Python have a ternary conditional operator?
(31 answers)
Closed last month.
I've been working on a text-based game in Python, and I've come across an instance where I want to format a string differently based on a set of conditions.
Specifically, I want to display text describing items in a room. I want this to be displayed, in the room's description, if and only if the item object in question is in the room object's list of items. The way it is set up, I feel that simply concatenating strings based on conditionals will not output as I want, and it would be better to have a different string for each case.
My question is, is there any pythonic method for formatting strings based on the result of a Boolean conditional? I could use a for loop structure, but I was wondering if there was something easier, similar to a generator expression.
I'm looking for something similar to this, in string form
num = [x for x in xrange(1,100) if x % 10 == 0]
As a general example of what I mean:
print "At least, that's what %s told me." %("he" if gender == "male", else: "she")
I realize that this example is not valid Python, but it shows, in general, what I'm looking for. I'm wondering if there is any valid expression for boolean string formatting, similar to the above.
After searching around a bit, I was unable to find anything pertaining specifically to conditional string formatting. I did find several posts on format strings in general, but that is not what I'm looking for.
If something like that does indeed exist, it would be very useful. I'm also open to any alternate methods that may be suggested.

Your code actually is valid Python if you remove two characters, the comma and the colon.
>>> gender= "male"
>>> print "At least, that's what %s told me." %("he" if gender == "male" else "she")
At least, that's what he told me.
More modern style uses .format, though:
>>> s = "At least, that's what {pronoun} told me.".format(pronoun="he" if gender == "male" else "she")
>>> s
"At least, that's what he told me."
where the argument to format can be a dict you build in whatever complexity you like.

Use an f-string:
plural = ''
if num_doors != 1:
plural = 's'
print(f'Shut the door{plural}.')
Or in one line with a conditional expression (a one-line version of the if/else statement):
print(f'Shut the door{"s" if num_doors != 1 else ""}.')
Note that in this case you have to mix double " and single ' quotes because you can't use backslashes to escape quotes in the expression part of an f-string, but this might change in Python 3.12. You can still use backslashes in the outer part of an f-string, so f'{2+2}\n' is fine.

There is a conditional expression in Python which takes the form:
A if condition else B
Your example can easily be turned into valid Python by omitting just two characters:
print ("At least, that's what %s told me." %
("he" if gender == "male" else "she"))
An alternative I'd often prefer is to use a dictionary:
pronouns = {"female": "she", "male": "he"}
print "At least, that's what %s told me." % pronouns[gender]

Related

Python is there a way to count the number of string inserts into a string?

Say let's say there's a string in python like
'f"{var_1} is the same as {var_2}"'
or something like
"{} is the same as {}".format(var_1, var_2)
Is there a way to count the number of insertion strings that exist in the string?
I'm trying to create a function that counts the number of insertions in a string. This is because I have code for generating a middle name and it could generate 2 or 1 middle name and just to keep the code consistent I'd rather it count the number of insertions exists in the string.
you could use a regular expression:
import re
s = 'f"{var_1} is the same as {var_2}"'
len(list(re.finditer(r'{.+?}', s)))
output:
2
For simple cases you can just count the number of open braces
nsubst = "{var_1} is the same as {var_2}".count("{")
for complex cases this however doesn't work and there is no easy solution as you need to do a full parser of format syntax or handle quite a few special cases (the problem are for example escaped braces or nested field substitution in field format specs). Moreover for f-strings you're allowed quite a big subset of valid python expressions as fields, including literal nested dictionaries and things are even more complex.

Indexing the wrong character for an expression

My program seems to be indexing the wrong character or not at all.
I wrote a basic calculator that allows expressions to be used. It works by having the user enter the expression, then turning it into a list, and indexing the first number at position 0 and then using try/except statements to index number2 and the operator. All this is in a while loop that is finished when the user enters done at the prompt.
The program seems to work fine if I type the expression like this "1+1" but if I add spaces "1 + 1" it cannot index it or it ends up indexing the operator if I do "1+1" followed by "1 + 1".
I have asked in a group chat before and someone told me to use tokenization instead of my method, but I want to understand why my program is not running properly before moving on to something else.
Here is my code:
https://hastebin.com/umabukotab.py
Thank you!
Strings are basically lists of characters. 1+1 contains three characters, whereas 1 + 1 contains five, because of the two added spaces. Thus, when you access the third character in this longer string, you're actually accessing the middle element.
Parsing input is often not easy, and certainly parsing arithmetic expressions can get tricky quite quickly. Removing spaces from the input, as suggested by #Sethroph is a viable solution, but will only go that far. If you all of a sudden need to support stuff like 1+2+3, it will still break.
Another solution would be to split your input on the operator. For example:
input = '1 + 2'
terms = input.split('+') # ['1 ', ' 2'] note the spaces
terms = map(int, terms) # [1, 2] since int() can handle leading/trailing whitespace
output = terms[0] + terms[1]
Still, although this can handle situations like 1 + 2 + 3, it will still break when there's multiple different operators involved, or there are parentheses (but that might be something you need not worry about, depending on how complex you want your calculator to be).
IMO, a better approach would indeed be to use tokenization. Personally, I'd use parser combinators, but that may be a bit overkill. For reference, here's an example calculator whose input is parsed using parsy, a parser combinator library for Python.
You could remove the spaces before processing the string by using replace().
Try adding in:
clean_input = hold_input.replace(" ", "")
just after you create hold_input.

string template substitution: each and every occurrence must be substituted

I have the following MWE:
import string
class MyTemplate(string.Template):
delimiter = '$'
pattern = r'''
\$(?:
(?P<escaped>\$)|
(?P<named>[_a-z][_a-z0-9]*)\$|
(?P<braced>[_a-z][_a-z0-9]*)\$|
(?P<invalid>)
)
'''
data1="max=$max$ min=$min$"
data2="max=$max$ "
print MyTemplate(data1).substitute({"max":"10","min":"1"})
print MyTemplate(data2).substitute({"max":"10","min":"1"})
print MyTemplate(data1).substitute({"max":"10"})
Of the 3 prints, I want that the only acceptable case is the first;
the last one raise an exception, but the second simply writes:
max=10
How can I detect this case (more values than placeholder)?
Is it possible to verify that a value is substituted only once?
Thanks!
The real questions here are "what are you trying to achieve?" and "is it needed?" and "why is it needed?"
If you still need it after answering all this, then override substitute in your MyTemplate class. You'll be able to do any check you like. It might slow down your program, though.
On the other hand, string.Template (from python 2.6) are mostly used through mystr.format(). And then, replaced by f-strings (3.6) https://www.python.org/dev/peps/pep-0498/

Python 2.7: % string format vs. calling variable outside string?

I'm teaching myself Python and can't see a huge difference between these two examples except the extra formatting options (eg. %r) that string formatting provides.
name = "Bob"
print "Hi, my name is %s." % name
print "Hi, my name is", name
Is there any reason in general why you'd prefer one over the other?
I realise that .format() is the preferred way to do this now, but this just for me to better understand how Python operates.
The primary difference between the two (which no one else seems to be describing) is this:
print "Hi, my name is %s." % name
Here, a new string is being constructed from the two strings (the string literal and the value of name). Interpolation (the % operator) is an operation you could use anywhere—for example, in a variable assignment or a function call—not just in a print statement. This newly-minted string is then printed (then discarded, because it is not given a name).
print "Hi, my name is", name
Here, the two strings are simply printed one after the other with a space in between. The print statement is doing all the work. No string operations are performed and no new string is created.
It is programming choice:
1) Using % clarifies the type to the reader of the code, but for each additional variable used, the programmer will need to spend time in modifying in 2 places
2) Using , implicitly does % so the reader will have to look back to know about he type. But it is quick and if code is intuitively written removes a lot of burdon of maintenance
So yes, it is choice of maintaining balance between, maintenance, readability and convenience.
The difference is that the comma is part of the print statement, not of the string. Attempting to use it elsewhere, e.g. binding a string to a name, will not do what you want.

Multiple conditions with if/elif statements [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 5 years ago.
I'm trying to get an if statement to trigger from more than one condition without rewriting the statement multiple times with different triggers. e.g.:
if user_input == "look":
print description
if user_input == "look around":
print description
How would you condense those into one statement?
I've tried using 'or' and it caused any raw_input at all to trigger the statement regardless of whether the input matched either of the conditions.
if user_input == "look" or "look around":
print description
What you're trying to do is
if user_input == "look" or user_input == "look around":
print description
Another option if you have a lot of possibilities:
if user_input in ("look", "look around"):
print description
Since you're using 2.7, you could also write it like this (which works in 2.7 or 3+, but not in 2.6 or below):
if user_input in {"look", "look around"}:
print description
which makes a set of your elements, which is very slightly faster to search over (though that only matters if the number of elements you're checking is much larger than 2).
The reason your first attempt always went through is this. Most things in Python evaluate to True (other than False, None, or empty strings, lists, dicts, ...). or takes two things and evaluates them as booleans. So user_input == "look" or "look around" is treated like (user_input == "look") or "look_around"; if the first one is false, it's like you wrote if "look_around":, which will always go through.
You could use regular expressions to match the strings if they follow a pattern with
optional sections or you could do an array lookup:
if user_input in ["look", "look around"]:
print description
The boolean operator or only works with boolean values, it evaluates the expressions
on both sides and returns True if one of the expressions evaluates to True.
It has nothing to do with the natural language '

Categories