Are f-strings a unique feature to python (3.6 and higher)? - python

With an f-string you can fill in 'placeholders' in a string directly with some variable value. Opposed to, let's say using the str.format() method, often seen.
Example:
In [1]: x=3
In [2]: y=4
In [3]: print(f'The product of {x} and {y} is {x*y}.')
The product of 3 and 4 is 12.
Is this concept of f-strings only found in python? Or is there any other language that supports this, maybe under a different name?

Short answer: No - not unique to python. In python it was introduced with 3.6 by Literal String Interpolation - PEP 498
In C# there is $ - string interpolation as shorthand for some function you would use String.Format for:
string val = "similar";
string s = $"This is {val}" // s == "This is similar"
// vs.
var s2 = string.Format ("This is {0}", val); // {0} = 0th param that follows

You can find it under the name of Template Literals in Javascript as well. In particular, see the section Expression Interpolation for an example similar as the one in OP's question.

The shell: Starting in the Dark Ages shells used to expand parameters in double quoted strings (and unquoted arguments too).
Perl: Perl has a shellish side, and had interpolation in double quoted strings from at least the time I bought the 1st edition of the Camel book and started learning the language.
I think that other people may be more specific on the precise date of introduction of string interpolation in Perl, but I suspect it was there from the beginning.
Many other programming languages, especially those using sigils, share this concept of interpolation.

Related

If the f-string like string formatting available in Julia?

So I am new to Julia and learned various ways of string formatting. Mainly from websites similar to this.
So I use f-strings a lot in Python, not a big fan of .format(). So I was wondering since someone created Formatting.jl Package to bring .format() like feature in Julia, is there any ongoing or useful package which does same for f-strings? Now I googled a bit about it too but didn't find anything.
What my main issue is that I want to replicate this behaviour:
a = 10
b = 20
print(f'The multiplication is = {a * b}')
In case anyone wondering what are f-strings, refer to this.
Yes, it is possible with standard Julia strings:
x = "World!"
y = 42
greeting = "Hello $x, $(y^2) !" # gives "Hello World!, 1764 !"
See also here:
https://docs.julialang.org/en/v1/manual/strings/#string-interpolation
Edit:
The example in the comment above is
j = 10; b = 20
println("The numbers and their square are $j, $b and $(j^2), $(b^2)")
There are multiple packages, of which the least well known but my favourite is PyFormattedStrings.jl.
Compare:
Package
Syntax
PyFormattedStrings.jl
f"Our yield is {harvest(crop):.3G} kg."
Fmt.jl
f"Our yield is {$(harvest(crop)):.3G} kg."
Formatting.jl
fmt("Our yield is {:.3f} kg.", harvest(crop))
(Note that Formatting has no g/G support).
PyFormattedStrings.jl uses the printf syntax, so eg aligning right is done with {var:20g}, and not {var:>20g} as in Python. Fmt.jl does use the Python syntax.
Neither package supports the f"{4+4=}" syntax of Python 3.8. (Though Julia has #show).
If you want more control over numeric formatting than the default string interpolation, you can use the Formatting.jl package in Julia, which provides Python f-string functionality.

What does = (equal) do in f-strings inside the expression curly brackets?

The usage of {} in Python f-strings is well known to execute pieces of code and give the result in string format (some tutorials here). However, what does the '=' at the end of the expression mean?
log_file = open("log_aug_19.txt", "w")
console_error = '...stuff...' # the real code generates it with regex
log_file.write(f'{console_error=}')
This is actually a brand-new feature as of Python 3.8.
Added an = specifier to f-strings. An f-string such as f'{expr=}'
will expand to the text of the expression, an equal sign, then the
representation of the evaluated expression.
Essentially, it facilitates the frequent use-case of print-debugging, so, whereas we would normally have to write:
f"some_var={some_var}"
we can now write:
f"{some_var=}"
So, as a demonstration, using a shiny-new Python 3.8.0 REPL:
>>> print(f"{foo=}")
foo=42
>>>
From Python 3.8, f-strings support "self-documenting expressions", mostly for print de-bugging. From the docs:
Added an = specifier to f-strings. An f-string such as f'{expr=}' will
expand to the text of the expression, an equal sign, then the
representation of the evaluated expression. For example:
user = 'eric_idle'
member_since = date(1975, 7, 31)
f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
The usual f-string format specifiers allow more control over how the
result of the expression is displayed:
>>> delta = date.today() - member_since
>>> f'{user=!s} {delta.days=:,d}'
'user=eric_idle delta.days=16,075'
The = specifier will display the whole expression so that calculations
can be shown:
>>> print(f'{theta=} {cos(radians(theta))=:.3f}')
theta=30 cos(radians(theta))=0.866
This was introduced in python 3.8. It helps reduce a lot of f'expr = {expr} while writing codes. You can check the docs at What's new in Python 3.8.
A nice example was shown by Raymond Hettinger in his tweet:
>>> from math import radians, sin
>>> for angle in range(360):
print(f'{angle=}\N{degree sign} {(theta:=radians(angle))=:.3f}')
angle=0° (theta:=radians(angle))=0.000
angle=1° (theta:=radians(angle))=0.017
angle=2° (theta:=radians(angle))=0.035
angle=3° (theta:=radians(angle))=0.052
angle=4° (theta:=radians(angle))=0.070
angle=5° (theta:=radians(angle))=0.087
angle=6° (theta:=radians(angle))=0.105
angle=7° (theta:=radians(angle))=0.122
angle=8° (theta:=radians(angle))=0.140
angle=9° (theta:=radians(angle))=0.157
angle=10° (theta:=radians(angle))=0.175
...
You can also check out this to get the underlying idea on why this was proposed in the first place.
As mention here:
Equals signs are now allowed inside f-strings starting with Python 3.8. This lets you quickly evaluate an expression while outputting the expression that was evaluated. It's very handy for debugging.:
It mean it will run the execution of the code in the f-string braces, and add the result at the end with the equals sign.
So it virtually means:
"something={executed something}"
f'{a_string=}' is not exactly the same as f'a_string={a_string}'
The former escapes special characters while the latter does not.
e.g:
a_string = 'word 1 tab \t double quote \\" last words'
print(f'a_string={a_string}')
print(f'{a_string=}')
gets:
a_string=word 1 tab double quote \" last words
a_string='word 1 tab \t double quote \\" last words
I just realised that the difference is that the latter is printing the repr while the former is just printing the value. So, it would be more accurate to say:
f'{a_string=}' is the same as f'a_string={a_string!r}'
and allows formatting specifications.

In Julia, insert commas into integers for printing like Python 3.6+

I want to insert commas into large integers for printing.
julia> println(123456789) # Some kind of flag/feature inserts commas.
"123,456,789"
In Python 3.6+ this is easy to do:
>>> print(f"{123456789:,d}")
123,456,789
However, it does not appear that the standard Julia print/println functions have this feature at the present time. What can I do using just the print/println functions?
I guess the most straightforward way in some languages would be to use the ' format modifier in printf. I Julia this WOULD look like so:
using Printf # a stdlib that ships with julia which defines #printf
#printf "%'d" 12345678
However, unfortunately, this flag is not yet supported as you can see from the error you'll get:
julia> #printf "%'d" 12345678
ERROR: LoadError: printf format flag ' not yet supported
If you like this feature, maybe you should think about adding it to the Printf stdlib so that everyone would benefit from it. I don't know how difficult this would be though.
UPDATE: Note that although the macro is defined in stdlib Printf, the error above is explicitly thrown in Base/printf.jl:48. I also filed an issue here
Here is a function based on a Regex from "Regular Expressions Cookbook," by Goyvaerts and Levithan, O'Reilly, 2nd Ed, p. 402, that inserts commas into integers returning a string.
function commas(num::Integer)
str = string(num)
return replace(str, r"(?<=[0-9])(?=(?:[0-9]{3})+(?![0-9]))" => ",")
end
println(commas(123456789))
println(commas(123))
println(commas(123456789123456789123456789123456789))
""" Output
123,456,789
123
123,456,789,123,456,789,123,456,789,123,456,789
"""

Printing subscript in python

In Python 3.3, is there any way to make a part of text in a string subscript when printed?
e.g. H₂ (H and then a subscript 2)
If all you care about are digits, you can use the str.maketrans() and str.translate() methods:
example_string = "A0B1C2D3E4F5G6H7I8J9"
SUB = str.maketrans("0123456789", "₀₁₂₃₄₅₆₇₈₉")
SUP = str.maketrans("0123456789", "⁰¹²³⁴⁵⁶⁷⁸⁹")
print(example_string.translate(SUP))
print(example_string.translate(SUB))
Which will output:
A⁰B¹C²D³E⁴F⁵G⁶H⁷I⁸J⁹
A₀B₁C₂D₃E₄F₅G₆H₇I₈J₉
Note that this won't work in Python 2 - see Python 2 maketrans() function doesn't work with Unicode for an explanation of why that's the case, and how to work around it.
The output performed on the console is simple text. If the terminal supports unicode (most do nowadays) you can use unicode's subscripts. (e.g H₂) Namely the subscripts are in the ranges:
0x208N for numbers, +, -, =, (, ) (N goes from 0 to F)
0x209N for letters
For example:
In [6]: print(u'H\u2082O\u2082')
H₂O₂
For more complex output you must use a markup language (e.g. HTML) or a typesetting language (e.g. LaTeX).
Using code like this works too:
print('\N{GREEK SMALL LETTER PI}r\N{SUPERSCRIPT TWO}')
print('\N{GREEK CAPITAL LETTER THETA}r\N{SUBSCRIPT TWO}')
The output being:
πr²
Θ₂
Note that this works on Python versions 3.3 and higher only. Unicode formatting.
If you want to use it on the axes of a plot you can do:
import matplotlib.pyplot as plt
plt.plot([1])
plt.ylabel(r'$H_{2}$')
plt.show()
which gives
By using this code you can use alphabets on the superscript and subscript
In This code
format() is Function and in Format function ('\unicode')
By using this table (Unicode subscripts and superscripts on Wikipedia) you can give suitable unicode to the suitable one
you can use superscript and sub script
"10{}".format('\u00B2') # superscript 2

Why allow concatenation of string literals?

I was recently bitten by a subtle bug.
char ** int2str = {
"zero", // 0
"one", // 1
"two" // 2
"three",// 3
nullptr };
assert( int2str[1] == std::string("one") ); // passes
assert( int2str[2] == std::string("two") ); // fails
If you have godlike code review powers you'll notice I forgot the , after "two".
After the considerable effort to find that bug I've got to ask why would anyone ever want this behavior?
I can see how this might be useful for macro magic, but then why is this a "feature" in a modern language like python?
Have you ever used string literal concatenation in production code?
Sure, it's the easy way to make your code look good:
char *someGlobalString = "very long "
"so broken "
"onto multiple "
"lines";
The best reason, though, is for weird printf formats, like type forcing:
uint64_t num = 5;
printf("Here is a number: %"PRIX64", what do you think of that?", num);
There are a bunch of those defined, and they can come in handy if you have type size requirements. Check them all out at this link. A few examples:
PRIo8 PRIoLEAST16 PRIoFAST32 PRIoMAX PRIoPTR
It's a great feature that allows you to combine preprocessor strings with your strings.
// Here we define the correct printf modifier for time_t
#ifdef TIME_T_LONG
#define TIME_T_MOD "l"
#elif defined(TIME_T_LONG_LONG)
#define TIME_T_MOD "ll"
#else
#define TIME_T_MOD ""
#endif
// And he we merge the modifier into the rest of our format string
printf("time is %" TIME_T_MOD "u\n", time(0));
I see several C and C++ answers but none of the really answer why or really what was the rationale for this feature? In C++ this is feature comes from C99 and we can find the rationale for this feature by going to Rationale for International Standard—Programming Languages—C section 6.4.5 String literals which says (emphasis mine):
A string can be continued across multiple lines by using the backslash–newline line continuation, but this requires that the continuation of the string start in the first position of the next line. To permit more flexible layout, and to solve some preprocessing problems (see §6.10.3), the C89 Committee introduced string literal concatenation. Two string literals in a row are pasted together, with no null character in the middle, to make one combined string literal. This addition to the C language allows a programmer to extend a string literal beyond the end of a physical line without having to use the backslash–newline mechanism and thereby destroying the indentation scheme of the program. An explicit concatenation operator was not introduced because the concatenation is a lexical construct rather than a run-time operation.
Python which seems to have the same reason, this reduces the need for ugly \ to continue long string literals. Which is covered in section 2.4.2 String literal concatenation of the
The Python Language Reference.
Cases where this can be useful:
Generating strings including components defined by the preprocessor (this is perhaps the largest use case in C, and it's one I see very, very frequently).
Splitting string constants over multiple lines
To provide a more concrete example for the former:
// in version.h
#define MYPROG_NAME "FOO"
#define MYPROG_VERSION "0.1.2"
// in main.c
puts("Welcome to " MYPROG_NAME " version " MYPROG_VERSION ".");
I'm not sure about other programming languages, but for example C# doesn't allow you to do this (and I think this is a good thing). As far as I can tell, most of the examples that show why this is useful in C++ would still work if you could use some special operator for string concatenation:
string someGlobalString = "very long " +
"so broken " +
"onto multiple " +
"lines";
This may not be as comfortable, but it is certainly safer. In your motivating example, the code would be invalid unless you added either , to separate elements or + to concatenate strings...
From the python lexical analysis reference, section 2.4.2:
This feature can be used to reduce the
number of backslashes needed, to split
long strings conveniently across long
lines, or even to add comments to
parts of strings
http://docs.python.org/reference/lexical_analysis.html
For rationale, expanding and simplifying Shafik Yaghmour’s answer: string literal concatenation originated in C (hence inherited by C++), as did the term, for two reasons (references are from Rationale for the ANSI C Programming Language):
For formatting: to allow long string literals to span multiple lines with proper indentation – in contrast to line continuation, which destroys the indentation scheme (3.1.4 String literals); and
For macro magic: to allow the construction of string literals by macros (via stringizing) (3.8.3.2 The # operator).
It is included in the modern languages Python and D because they copied it from C, though in both of these it has been proposed for deprecation, as it is bug-prone (as you note) and unnecessary (since one can just have a concatenation operator and constant folding for compile-time evaluation; you can’t do this in C because strings are pointers, and so you can’t add them).
It’s not simple to remove because that breaks compatibility, and you have to be careful about precedence (implicit concatenation happens during lexing, prior to operators, but replacing this with an operator means you need to be careful about precedence), hence why it’s still present.
Yes, it is in used production code. Google Python Style Guide: Line length specifies:
When a literal string won't fit on a single line, use parentheses for implicit line joining.
x = ('This will build a very long long '
'long long long long long long string')
See “String literal concatenation” at Wikipedia for more details and references.
So that you can split long string literals across lines.
And yes, I've seen it in production code.
While people have taken the words out of my mouth about the practical uses of the feature, nobody has so far tried to defend the choice of syntax.
For all I know, the typo that can slip through as a result was probably just overlooked. After all, it seems robustness against typos wasn't at the front of Dennis's mind, as shown further by:
if (a = b);
{
printf("%d", a);
}
Furthermore, there's the possible view that it wasn't worth using up an extra symbol for concatenation of string literals - after all, there isn't much else that can be done with two of them, and having a symbol there might create temptation to try to use it for runtime string concatenation, which is above the level of C's built-in features.
Some modern, higher-level languages based on C syntax have discarded this notation presumably because it is typo-prone. But these languages have an operator for string concatenation, such as + (JS, C#), . (Perl, PHP), ~ (D, though this has also kept C's juxtaposition syntax), and constant folding (in compiled languages, anyway) means that there is no runtime performance overhead.
Another sneaky error I've seen in the wild is people presuming that two single quotes are a way to escape the quote (as it is commonly used for double quotes in CSV files, for example), so they'll write things like the following in python:
print('Beggars can''t be choosers')
which outputs Beggars cant be choosers instead of the Beggars can't be choosers the coder desired.
As for the original "why" question: why is this a "feature" in a modern language like python? - in my opinion, I concur with the OP, it shouldn't be.

Categories