Search code examples
pythonstring-literals

Using raw literal representations when working with variable strings


I am trying to use a for loop to copy files in different source folders into the same destination folder. I like to use literal representations to avoid issues with multiple backslashes in the file paths. I could not find the proper way to get a literal representation of a variable. Any tip would be appreciated. The code is below:

import shutil
destination_folder=DF

for i in range (1,3):
    new_folder='folder_'+str(i)
    new_path=os.path.join('C:\foo', new_folder, file_to_copy)
    source_file= r(new_path)                #WRONG
    destination= r(destination_folder)      #WRONG
    shutil.copy(source_file, destination)

Solution

  • r is not a function that applies to string objects, it's a modifier that applies to string literals. It changes how the literal gets interpreted as a value. But once it's done, the value is just a plain old string value. In particular:

    >>> a = '\n'
    >>> b = '''
    ... '''
    >>> a == b
    True
    

    So, if a and b are the same value, how can Python possibly know that you want to turn it into r'\n'?

    For that matter, imagine this:

    >>> c = sys.stdin.readline()
    
    >>> c == a
    True
    

    Or this:

    >>> d = chr(10)
    >>> d == a
    

    You can't go back and re-interpret the string literal as a raw string in any of these other cases—in b it would be unchanged, and in c and d there was no string literal in the first place.


    If you want to escape all special characters in a string value, without caring where they came from, you can do that by asking Python to escape the string. For example:

    >>> e = a.encode('unicode-escape').decode('ascii')
    

    But you definitely don't want to do that for constructing filenames to pass to the shutil.copy function.


    If you have a string literal in your code, and you want it to be treated as a raw string literal, just write it as a raw string literal. So:

    new_path=os.path.join(r'C:\foo', new_folder, file_to_copy)
    source_file= new_path
    destination= destination_folder
    

    You could instead manually escape the backslash in your literal, or use forward slashes instead of backslashes, etc. But those are all things you do to the literal before it gets evaluated by Python, not to the string after the fact.