Mushroom Man
Mushroom Man

Reputation: 400

str.replace not appearing to function properly when target string is contained in a list

In my program I have a section of code that looks in one of my computer's directories for pickle files and puts their names in a list using a list comprehension. After this I am attempting to remove the ".pickle" file extension from each of the file names in the list, for reasons unnecessary to explain here. However, after iterating through the list and redefining each element as what it would be when passed into the str.replace built-in function and replacing the ".pickle" string with "", the names in the list do not appear to have changed. Here is my code:

import os
file_names = [file for file in os.listdir("C:/~~/dir") if file.endswith(".pickle")]
for each in file_names:
    each = each.replace(".pickle","")

The one pickle file that I'm using in the early stage of my program's development is the only in the directory.
The program has thrown no errors.

The name of the file itself is called "debugger.pickle" and when printing the "file_names" list it prints

['debugger.pickle']

instead of just

['debugger']

which is my desired result.

Upvotes: 1

Views: 164

Answers (2)

Burhan Khalid
Burhan Khalid

Reputation: 174662

You can't replace items inline; try using map or a list comprehension to recreate the list:

import glob
import os

original_files = glob.glob(r'C:/foo/blah/*.pickle')
files = [os.path.basename(os.path.splitext(i)[0]) for i in original_files]

You can also combine it:

files = [os.path.basename(os.path.splitext(i)[0]) for i in glob.iglob(r'C:/foo/*.pickle')]

Upvotes: 0

PM 2Ring
PM 2Ring

Reputation: 55489

each = each.replace(".pickle","") creates a new string and binds it to the name each. This has no effect on the original string object in file_names.

If the .replace method mutated its string in-place then

for each in file_names:
    each.replace(".pickle","")

would work, but that code won't actually do what you want because Python strings are immutable.

So you need to save the pruned strings, the simple way to do that is with a list comprehension:

file_names = [each.replace(".pickle","") for each in file_names]

Note that this replaces the original file_names list object with a new object. If you'd like to instead modify the original file_names object you can do

file_names[:] = [each.replace(".pickle","") for each in file_names]

That's slightly less efficient (and slower), but it can be useful if you have other objects referring to the original file_names object.

Upvotes: 3

Related Questions