113

I'm wondering how to use an f-string whilst using r to get a raw string literal. I currently have it as below but would like the option of allowing any name to replace Alex I was thinking adding an f-string and then replacing Alex with curly braces and putting username inside but this doesn't work with the r.

username = input('Enter name')
download_folder = r'C:\Users\Alex\Downloads'
Granny Aching
  • 1,295
  • 12
  • 37
lammyalex
  • 1,179
  • 2
  • 7
  • 8

6 Answers6

222

You can combine the f for an f-string with the r for a raw string:

user = 'Alex'
dirToSee = fr'C:\Users\{user}\Downloads'
print (dirToSee) # prints C:\Users\Alex\Downloads

The r only disables backslash escape sequence processing, not f-string processing.

Quoting the docs:

The 'f' may be combined with 'r', but not with 'b' or 'u', therefore raw formatted strings are possible, but formatted bytes literals are not.

...

Unless an 'r' or 'R' prefix is present, escape sequences in string and bytes literals are interpreted...

user2357112
  • 260,549
  • 28
  • 431
  • 505
rajah9
  • 11,645
  • 5
  • 44
  • 57
  • 3
    Ahh great thank you. I tried doing it rf but didn't work. – lammyalex Oct 09 '19 at 11:20
  • 7
    @lammyalex `rf` should also work. See [String and Bytes literals](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals) – Georgy Oct 09 '19 at 11:22
  • 3
    when using `fr` PyCharm IDE shows an error but when you run the code, it works without any issue. – VBJ Dec 02 '20 at 16:44
  • 4
    For me, that's a warning, not an error: it is not backward compatible with earlier versions of Python. It will run fine for Python 3.6 and later. – rajah9 Dec 02 '20 at 16:59
  • 2
    f-strings are already not supported in 3.5 and below, so it's not as if using `rf` or `fr` as a prefix causes a special compatibility problem. – Karl Knechtel Nov 16 '21 at 04:41
  • When combining both, just be mindful that `{}` won't be 'raw' any more. This is annoying for regex patterns: `r'{user}\w+{4}'` will not be `'Alex\w+{4}'` but `'Alex\w+4'`! Of course, fix is simple: `f'{user}'r'\w+{4}'` – legends2k Jul 18 '23 at 11:04
18

Alternatively, you could use the str.format() method.

name = input("What is your name? ")
print(r"C:\Users\{name}\Downloads".format(name=name))

This will format the raw string by inserting the name value.

clubby789
  • 2,543
  • 4
  • 16
  • 32
3

Since you are working with file paths, I would avoid f-strings and rather use a library geared for path manipulation. For example pathlib would allow you to do:

from pathlib import Path
username = input('Enter name')
download_folder = Path('C:/Users', username, 'Downloads')

This approach also offers some other common file operations such as, such as is_dir open.

Alternatively you could also use os.path.join)

Nameless One
  • 1,615
  • 2
  • 23
  • 39
3

As others have mentioned, it's indeed possible to mix r and f. Be careful, though, since the interpolated strings will not be raw by default:

not_escaped = "\not_escaped"
half_escaped = rf"escaped_{not_escaped}"

print(half_escaped)
### outputs:
# escaped_
# ot_escaped

You'd have to use r for the interpolated strings too:

escaped = r"\n_escaped"
full_escaped = rf"escaped_too_{escaped}"

print(full_escaped)
# escaped_too_\n_escaped
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
2

The simplest way I've found of doing this is to use implicit line continuation to split my strings up into component parts, i.e. separate out 'r' and 'f' strings inside parenthases. Here's an example matplotlib title with 'normal', 'formatted', and 'raw' string literals (read more here):

plt.title('Blind Surveys 01-FEB-2022\n'
         f'Recording{n}; Mean dose rate: {m.get_mean_doserate()*1000:.4f}'
         r' $\mathrm{\mu}$Sv/hr', fontsize='x-large')

enter image description here

Just to make it more applicable to the question, you can also use implicit line continuation in variable declaration:

user = ‘Alex’
dir_out = (r‘C:\Users\’
           f‘{user}’
           r‘\Downloads’)
print(dir_out) #C:\Users\Alex\Downloads

Admittedly this seems a bit overkill for this simple scenario but will be your friend when strings become more complex!

compuphys
  • 1,289
  • 12
  • 28
  • 1
    Interesting. The last example looks nice and readable. Yet another alternative would be to use pathlib and let it join paths with `/`. – Eric Duminil Nov 28 '22 at 06:54
-2

you can try:

username = input('Enter name')
download_folder = r'C:\Users\Alex\Downloads'
download_folder = download_folder.replace("Alex", username)
print(download_folder)
Yone
  • 867
  • 1
  • 7
  • 22