I have a path as a string like this:
path = "directory/folder1/folder2/folder3/file1.txt"
I want to know how many levels this path has - in this case 4 (directory, folder1, folder2, folder3).
What's the best way to do it in Python? I thought about counting the "/":
path.count("/")
but I am wondering if there is a better way.
You could do it quite easily using pathlib:
from pathlib import Path
path = Path("directory/folder1/fodler2/folder3/file1.txt")
print(len(path.parents), list(path.parents))
Which gives:
5 [Path('directory/folder1/fodler2/folder3'), Path('directory/folder1/fodler2'), Path('directory/folder1'), Path('directory'), Path('.')]
As can be seen, the results is 5 because "." is also in the list as "directory/folder1/fodler2/folder3/file1.txt" is implicitly equal to "./directory/folder1/fodler2/folder3/file1.txt" so you can always just subtract 1 from the result.
Compared to path.count('/'), this is platform-independent...
It all depends on how precise you want to be. Problems I can think of:
Are you sure the last part of the string is the filename? If it is a directory, does it matter?
Are you sure the path separator is '/'? os.sep is your separator.
What if the string starts with os.sep?
What if some os.sep is repeated? For example os.path.exists("/var//log") returns True.
This might be slightly better, but the solution with pathlib.Path is definitely better.
os.path.normpath(path).count(os.sep)
Maybe one optimal solution could be path.count(os.sep). However, Tomerikoo answer is better than this. However, Make sure that pathlib module is installed, as this module does not come by default in the standard distribution of python2. But if you are using python3. Then it comes by default.
Related
I'm looking for a simple method of identifying the last position of a string inside another string ... for instance. If I had: file = C:\Users\User\Desktop\go.py
and I wanted to crop this so that file = go.py
Normally I would have to run C:\Users\User\Desktop\go.py through a loop + find statement, and Evey time it encountered a \ it would ask ... is the the last \ in the string? ... Once I found the last \ I would then file = file[last\:len(file)]
I'm curious to know if there is a faster neater way to do this.. preferably without a loop.
Something like file = [file('\',last):len(file)]
If there is nothing like what I've shown above ... then can we place the loop inside the [:] somehow. Something like file = [for i in ...:len(file)]
thanks :)
If it is only about file paths, you can use os.path.basename:
>>> import os
>>> os.path.basename(file)
'go.py'
Or if you are not running the code on Windows, you have to use ntpath instead of os.path.
You could split the string into a list then get the last index of the list.
Sample:
>>> file = 'C:\Users\User\Desktop\go.py'
>>> print(file.split('\\')[-1])
go.py
I agree with Felix on that file paths should be handled using os.path.basename. However, you might want to have a look at the built in string function rpartition.
>>> file = 'C:\Users\User\Desktop\go.py'
>>> before, separator, after = file.rpartition('\\')
>>> before
'C:\\Users\\User\\Desktop'
>>> separator
'\\'
>>> after
'go.py'
There's also the rfind function which gives you the last index of a substring.
>>> file.rfind('\\')
21
I realize that I'm a bit late to the party, but since this is one of the top results when searching for e.g. "find last in str python" on Google, I think it might help someone to add this information.
For the general purpose case (as the OP said they like the generalisation of the split solution)...... try the rfind(str) function.
"myproject-version2.4.5.customext.zip".rfind(".")
edit: apologies, I hadn't realized how old this thread was... :-/
For pathname manipulations you want to be using os.path.
For this specific problem you want to use the os.path.basename(path) function which will return the last component of a path, or an empty string if the path ends in a slash (ie. the path of a folder rather than a file).
import os.path
print os.path.basename("C:\Users\User\Desktop\go.py")
Gives:
go.py
I have a directory I want to save files to, saved as a Path object called dir. I want to autogenerate files names at that path using string concatenation.
The only way I can get this to work in a single line is just through string concatenation:
dir = Path('./Files')
constantString = 'FileName'
changingString = '_001'
path2newfile = dir.as_posix() + '/' + constantString + changingString
print(path2newfile) # ./Files/Filename_001
... which is overly verbose and not platform independent.
What I'd want to do is use pathlib's / operator for easy manipulation of the new file path that is also platform independent. This would require ensuring that the string concatenation happens first, but the only way I know how to do that is to set a (pointless) variable:
filename = constantString + changingString
path2newfile = dir / filename
But I honestly don't see why this should have to take two lines.
If I instead assume use "actual" strings (ie. not variables containing strings), I can do something like this:
path2newfile = dir / 'Filename' '_001'
But this doesn't work with variables.
path2newfile = dir / constantString changingString
# SyntaxError: invalid syntax
So I think the base question is how do I control the order of operators in python? Or at least make the concatenation operator + act before the Path operator /.
Keep in mind this is a MWE. My actual problem is a bit more complicated and has to be repeated several times in the code.
Just use parentheses surrounding your string contatenation:
path2newfile = dir / (constantString + changingString)
Have you considered using Python f-strings?
It seems like your real-world example has a "template-y" feel to it, so something like:
path / f"constant part {variable_part}"
may work.
Use os.path.join().
It's both platform-independent and you can plug the desired path parts as arguments.
Relatively new to python, trying to move files based on type from one directory to another.
import shutil
import os
source = 'C:\Users\home\Desktop'
Unsorted = 'C:\Users\home\Desktop\'
Sorted = 'B:\Pictures'
file = os.listdir(source)
for f in file("Unsorted"):
if file.endswith(".png",".jpg"):
print(os.path.join("Sorted", file))
I would appreciate any help. Thank you.
Edit
Thank you for the help and the links. I really appreciate it. I am reading automatetheboringstuff, and Modern Python Cookbook (2018).
import os
source = 'C:\\Users\\home\\Desktop'
sorted = 'B:\\Pictures'
for f in os.listdir(source):
if f.endswith((".png",".jpg",".jpeg")):
print(os.path.join(sorted, f))
I believe it works, since I am not getting any errors, but it's not moving the files. It seems to work here: link. Maybe it doesn't work between drives? Anyway, thank you!
EDIT I got it to work!
import os
import shutil
source = os.path.join('C:\\Users\\home\\Desktop')
sort = os.path.join('B:\\Pictures')
for f in os.listdir(source):
if f.endswith((".png",".jpg",".jpeg")):
shutil.move(os.path.join(source, f), sort)
Thank you everyone for your help! I hope you guys have a great rest of your day! Thanks. :D
See the comments inline.
#import shutil # commented out as this is not used for anything here
import os
# use r'...' strings for file names with backslashes (or use forward slashes instead)
source = r'C:\Users\home\Desktop'
#Unsorted = r'C:\Users\home\Desktop\' # also not used
Sorted = r'B:\Pictures'
# listdir produces an unsorted list of files so no need to muck with it
for f in os.listdir(source):
# you had the wrong variable name here, and missing parens around the tuple
if f.endswith((".png",".jpg")):
# again, the variable is f
# and of course "Sorted" is just a string, you want the variable
print(os.path.join(Sorted, f))
Some general advice:
Python has good documentation and is easy to play around with; just starting up Python and typing in a fragment of your program lets you try things until you can see what to write in your program to make it do what you want, without guesswork, typos, or unfounded expectations.
Don't use reserved keywords for your variables. Understand the difference between a string and a variable name (and a keyword).
Many of the things you had wrong are extremely common beginner errors. A bit of googling (especially with an error message or a phrase describing what's not working) will very often lead you to an excellent answer on Stack Overflow explaining exactly what's wrong and how to fix it.
Thus, don't cram too much into a single question. Most of the time, if your question is specific enough, you don't even have to ask it once you see what's wrong.
To concretize with an example, in the Python interactive REPL, maybe you are actually wondering whether endswith works with an uppercase file name, so you try it:
>>> 'PANGEA.PNG'.endswith(".png",".jpg")
This gives you a somewhat incredulous message that "slice indices must be integers" which isn't very helpful by itself (until you understand what it's trying to say -- endswith wants a "suffix" argument and an (optional) "start" argument, which is then used to "slice" the string; and ".jpg" isn't a valid value for start, so slicing fails because of that) but very easy to search for -- this Stack Overflow question is literally my first google hit for the search endswith "slice indices must be integers" and so you figure out what was wrong with your attempt, and what the error message is telling you, and now you go ahead and fix one of the small bugs in your code so far, and proceed with the next experiment (maybe check that os.path.join("Sorted", "PANGEA.PNG") looks like what you expect?)
System: Python 2.6 on Windows 7 64 bit
Recently I did a lot of path formatting in Python. Since the string modifications are always dangerous I started to do it the proper way by using the 'os.path' module.
The first question is if this is the right way to to handle incoming paths? Or can I somehow optimize this?
sCleanPath = sRawPath.replace('\n', '')
sCleanPath = sCleanPath.replace('\\', '/')
sCleanPythonPath = os.path.normpath(sCleanPath)
For formatting the 'sCleanPythonPath' now I use only functions from the 'os.path' module. This works very nice and I didn't had any problems so far.
There is only one exception. I have to change paths so they point not longer on a network storage but on a local drive. Is started to use 'os.path.splitunc()' in conjunction with 'os.path.join()'.
aUncSplit = os.path.splitunc(sCleanPythonUncPath)
sLocalDrive = os.path.normpath('X:/mount')
sCleanPythonLocalPath = (os.path.join(sLocalDrive, aUncSplit[1]))
Unfortunately this doesn't work due to the nature of how absolute paths are handled using 'os.path.join()'. All the solutions I found in the web are using string replacements again which I want to avoid by using the 'os.path' module. Have I overseen anything? Is there another, maybe a better way to do this?
All comments on this are very welcome!
You could optimize the first part slightly by removing the replace() call because on Windows normpath() converts forward slashes to backward slashes:
sCleanPath = sRawPath.replace('\n', '')
sCleanPythonPath = os.path.normpath(sCleanPath)
Here's something that would make the second part of your question work without doing a string replacement:
sSharedFolder = os.path.relpath(os.path.splitunc(sCleanPythonUncPath)[1], os.sep)
sLocalDrive = os.path.normpath('X:/mount') # why not hardcode the result?
sCleanPythonLocalPath = os.path.join(sLocalDrive, sSharedFolder)
I have two strings:
C:\Data
and another folder
Foo1
I need, the windows output to be
C:\Data\Foo1
and the Linux output to be
/data/foo1
assuming /data is in linux. Is there any constant separator that can be used in Python, that makes it easy to use irrespective of underlying OS?
Yes, python provides os.sep, which is that character, but for your purpose, the function os.path.join() is what you are looking for.
>>> os.path.join("data", "foo1")
"data/foo1"
os.path.normpath() will normalize a path correctly for Linux and Windows. FYI, Windows OS calls can use either slash, but should be displayed to the user normalized.
The os.path.join() is always better. As Mark Tolonen wrote (my +1 to him), you can use a normal slash also for Windows, and you should prefer this way if you have to write the path explicitly. You should avoid using the backslash for paths in Python at all. Or you would have to double them in strings or you would have to use r'raw strings' to suppress the backslash interpretation. Otherwise, 'c:\for\a_path\like\this' actually contains \f, \a, and \t escape sequences that you may not notice in the time of writing... and they may be source of headaches in future.