Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
When not to use f-strings?
#1
Hi!

I knew nothing about f-strings until on this site somebody suggested them as a more appropriate and straightforward way to print strings. The books I was using didn't say anything about them, as f-strings appeared with Python 3.6. Such is the case, that even in books printed in 2018 and 2019, you are lucky if more than a paragraph is dedicated to them!!!

So I looked for sites on the internet, and I found more information. I did even write a couple of simple programs comparing the printing time for strings printed with the %-format, strings printed with the .format() type, and f-strings. The f-string formatting seems to be the fastest, at least when the strings are simple. The second place is for %-formatted strings, which is curious, as they seem to be deprecated in the near future. I think I read it's due to some collateral problems... Not sure which ones...

Then, I decided to complicate things a bit more, with multiline strings with even lines in blank, like citing a few quotes attributed to somebody. While I had no problems at printing them, I encountered problems at trying to time them (I tried different functions from different modules, with similar problems). It seems that then, f-strings is not very new line (\n) friendly, and although I tried some suggestions I found, they didn't work. They were too many quotation marks; I tried adding quotation marks used in other languages, but it was of no use either. I tried using strings as a concatenation of strings, I tried also to make one of those concatenated strings equal to "\n", but neither of them managed to work...

So, my questions are:

1) When it's better not to use f-strings?
2) As my purpose was to compare the printing time for complex strings formatted differently, is there a way to do it, or it cannot be used for f-strings?

All the best,
newbieAuggie2019

"That's been one of my mantras - focus and simplicity. Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains."
Steve Jobs
Reply
#2
This is not really an answer, but don't forget that templating systems also exist for "complex" string formatting, such as Mako templates. For me, fstrings are only designed for simple string interpolations, in the same category as format() or %.
Reply
#3
There is website with examples dedicated to show differences in possibilities of % and .format method: PyFormat: Using % and .format() for great good!. No f-strings but I believe it can be source of some ideas.

I approach string formatting this way: start with f-strings. If it seems too complicated or non-pythonic then fall back to .format.

f-strings are 'not \ friendly' i.e. one cannot use escaping in placeholders.

Regarding speed. One can test it, on my machine I get this:

In [122]: timeit.timeit("""name = 'Internet' 
     ...: age = 30 
     ...: '%s is %s' % (name, age)""", number = 100000)                         
Out[122]: 0.03204629699757788

In [123]: timeit.timeit("""name = 'Internet' 
     ...: age = 30 
     ...: '{} is {}'.format(name, age)""", number = 100000)                     
Out[123]: 0.04341071600356372

In [124]: timeit.timeit("""name = 'Internet' 
     ...: age = 30 
     ...: '{name} is {age}'""", number = 100000)                                
Out[124]: 0.002835419996699784
At the beginning f-string were slower than .format but this was fixed (Make f'' strings faster than .format: BUILD_STRING opcode?)
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#4
just to mention that if there is need for escaping within placeholder than it's a case of having expression IN the placeholder. In this case it would be better and more readable to have the expression prepared and assigned to a variable beforehand and use that variable in the f-string
I would prefer f-strings over .format or % in any case
Of course there are cases where using template engine is warranted or like in SQL statements where you should not use string formatting with untrusted input
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#5
(Sep-16-2019, 06:09 AM)buran Wrote: just to mention that if there is need for escaping within placeholder than it's a case of having expression IN the placeholder. In this case it would be better and more readable to have the expression prepared and assigned to a variable beforehand and use that variable in the f-string

To showcase buran's suggestion:

>>> newline = '\n'                                                        
>>> first = 'first'                                                       
>>> second = 'second'  
>>> print(f'{first}{newline}{second}')
first
second
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#6
(Sep-16-2019, 04:54 AM)Gribouillis Wrote: This is not really an answer, but don't forget that templating systems also exist for "complex" string formatting, such as Mako templates. For me, fstrings are only designed for simple string interpolations, in the same category as format() or %.
Hi!
Thank you for your answer. I didn't know about Mako templates (as I don't know many other things in Python Blush ).

I checked and it seems that it is used by reddit.com, for example.
The problem is that I'm just starting, and it uses classes, something that I don't know how to use yet. But I don't have problems printing complex f-string formatting. I DO have problems when trying to time the printing of that complex f-string.

For instance, for very simple strings:
import timeit

integer1 = 25
string1 = 'TWENTY-FIVE'

setup = """
integer1 = 25
string1 = 'TWENTY-FIVE'
""".strip()

print('\nString number %s, or simply %d' % (string1, integer1))
print('String number {}, or simply {}'.format(string1, integer1))
print(f'String number {string1}, or simply {integer1}')

percent_stmt = "'String number %s, or simply %d' % (string1, integer1)"
call_stmt = "'String number {}, or simply {}'.format(string1, integer1)"
fstr_stmt = """f'String number {string1}, or simply {integer1}'"""

def time(stmt):
    return f"{timeit.timeit(stmt, setup, number=int(1e4)):.5f}"

print(f"\nThe printing times of the different formatting types are:\n")
print(f"Timing percent formating:      {time(percent_stmt)}s" )
print(f"Timing call formating:         {time(call_stmt)}s")
print(f"Timing f-string formating:     {time(fstr_stmt)}s\n")
and that produced on one of the occasions, the following ouput:
Output:
String number TWENTY-FIVE, or simply 25 String number TWENTY-FIVE, or simply 25 String number TWENTY-FIVE, or simply 25 The printing times of the different formatting types are: Timing percent formating: 0.00296s Timing call formating: 0.00333s Timing f-string formating: 0.00147s
or even with a bit longer strings:

import timeit

name = "Arnold Schwarzenegger"
age = 72

print("\n\nThis is printing strings with %-formatting (not recommended by the Python docs):") 
print('%s is %s.' % (name, age))
t1 = timeit.timeit("""name = "Arnold Schwarzenegger"
age = 72
'%s is %s.' % (name, age)""", number = 10000)
print("That took", t1, end='s to print.')

print("\n\nThis is printing strings with str.format():")
print('{} is {}.'.format(name, age))
t2 = timeit.timeit("""name = "Arnold Schwarzenegger"
age = 72
'{} is {}.'.format(name, age)""", number = 10000)
print("That took", t2, end='s to print.')

print("\n\nThis is printing strings with f-formatting:")
print(f'{name} is {age}.')
t3 = timeit.timeit("""name = "Arnold Schwarzenegger"
age = 72
f'{name} is {age}.'""", number = 10000)
print("That took", t3, end='s to print.\n')

print(f"""
It seems that {t3}s (f-formatting) is < {t1}s (%-formatting)
(%-formatting is not recommended by the Python docs).

It seems also that {t3}s (f-formatting) is < {t2}s (str.format()).

So it appears clearly that F-FORMATTING IS INDEED THE FASTEST WAY TO PRINT STRINGS.
   """)
which in one of the instances, produced this output:
Output:
This is printing strings with %-formatting (not recommended by the Python docs): Arnold Schwarzenegger is 72. That took 0.0026088639999999885s to print. This is printing strings with str.format(): Arnold Schwarzenegger is 72. That took 0.00298629899999997s to print. This is printing strings with f-formatting: Arnold Schwarzenegger is 72. That took 0.0014626989999999562s to print. It seems that 0.0014626989999999562s (f-formatting) is < 0.0026088639999999885s (%-formatting) (%-formatting is not recommended by the Python docs). It seems also that 0.0014626989999999562s (f-formatting) is < 0.00298629899999997s (str.format()). So it appears clearly that F-FORMATTING IS INDEED THE FASTEST WAY TO PRINT STRINGS.
but when the strings are more complex, even not having problems at printing them, I'm having problems at timing the printing of those examples.

(Sep-16-2019, 04:54 AM)Gribouillis Wrote: For me, fstrings are only designed for simple string interpolations, in the same category as format() or %.
I was trying to find out where I saw that %-formatting is going to be deprecated (I thought it was in the Python docs, but I cannot find it now, although they referred to it, as the old %-formatting). Huh

All the best,

(Sep-16-2019, 06:20 AM)perfringo Wrote:
(Sep-16-2019, 06:09 AM)buran Wrote: just to mention that if there is need for escaping within placeholder than it's a case of having expression IN the placeholder. In this case it would be better and more readable to have the expression prepared and assigned to a variable beforehand and use that variable in the f-string

To showcase buran's suggestion:

>>> newline = '\n'                                                        
>>> first = 'first'                                                       
>>> second = 'second'  
>>> print(f'{first}{newline}{second}')
first
second
Thank you to both of you, Buran and Perfringo!

What I meant is this, by modifying your program:

import timeit

newline = '\n'
first = 'first'
second = 'second'
print("\n\nThis is printing strings with f-formatting:")
print(f'{first}{newline}{second}')
t3 = timeit.timeit("""newline = '\n'
first = 'first'
second = 'second'
f'{first}{newline}{second}'""", number = 10000)
print("That took", t3, end='s to print.\n')
And when I run it, I have this output with an error message:
Output:
This is printing strings with f-formatting: first second
Error:
Traceback (most recent call last): File "C:/Users/User1/AppData/Local/Programs/Python/Python37/compare_speed_strings_03.py", line 15, in <module> f'{first}{newline}{second}'""", number = 10000) File "C:\Users\User1\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:\Users\User1\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 121, in __init__ compile(stmtprefix + stmt, dummy_src_name, "exec") File "<timeit-src>", line 2 newline = ' ^ SyntaxError: EOL while scanning string literal
1) Is it something that I'm doing wrong? (with my other example programs that I attached in my previous posts, I didn't have problems)
2) Is it something with f-strings and newlines to be timed? (no problems to print)

All the best,
newbieAuggie2019

"That's been one of my mantras - focus and simplicity. Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains."
Steve Jobs
Reply
#7
I use only f-string for string formatting now,and have done so for a while(years).
They are more readable,more concise,and less prone to error than other ways of formatting,they are also faster!.

For me is very simple to see this.
>>> name = "Kent"
>>> age = 30
# The  expressions is in the string where the belong
>>> print(f"Hello, {name}. You are {age}.")
Hello, Kent. You are 30.

# The  expressions is behind and not where the should be,and only {} in string
>>> print("Hello, {}. You are {}.".format(name, age))
Hello, Kent. You are 30.
(Sep-16-2019, 06:31 AM)newbieAuggie2019 Wrote: 2) Is it something with f-strings and newlines to be timed? (no problems to print)
Don't pack in a string,use a function.
There is no need to measure,they are faster.
import timeit

def run_me():
    newline = '\n'
    first = 'first'
    second = 'second'
    "\n\nThis is printing strings with f-formatting:"
    f'{first}{newline}{second}'
    #'{}{}{}'.format(first, newline, second)

print(timeit.Timer("run_me()",'from __main__ import run_me').timeit(number=10000000))
Output:
f-string: 3.2901052 .format(): 6.3253624
Reply
#8
In line 8 a r in front of the quote.
This suppresses the interpretation of \n.
Otherwise \n is replaced with a newline.

The r comes from regex. This type of string is called regex-string.
If you use regex, you have many backslashes and some of them change the meaning, if a character comes after.
For example:
  • \t
  • \n
  • \"
  • \b
  • ...

To prevent interpretation in regular strings, you can use double backslash.
text1 = "Text with\nline break"
text2 = "Text without\\nline break"
text3 = "Text with \"Quotes\""
print(text1, text2, text3, sep='\n')
import timeit
 
newline = '\n'
first = 'first'
second = 'second'
print("\n\nThis is printing strings with f-formatting:")
print(f'{first}{newline}{second}')
t3 = timeit.timeit(r"""newline = '\n'
first = 'first'
second = 'second'
f'{first}{newline}{second}'""", number = 10000)
print("That took", t3, end='s to print.\n')
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Trying to understand strings and lists of strings Konstantin23 2 699 Aug-06-2023, 11:42 AM
Last Post: deanhystad
  Splitting strings in list of strings jesse68 3 1,704 Mar-02-2022, 05:15 PM
Last Post: DeaD_EyE
  Finding multiple strings between the two same strings Slither 1 2,482 Jun-05-2019, 09:02 PM
Last Post: Yoriz
  lists, strings, and byte strings Skaperen 2 4,183 Mar-02-2018, 02:12 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020