3

I am trying to get the parent directory's name only. Meaning, only its last component, not the full path.

So for example for the path a/b/c/d/e I want to get d, and not a/b/c/d.

My current code:

import os

path = "C:/example/folder/file1.jpg"
directoryName = os.path.dirname(os.path.normpath(path)) 
print(directoryName)

This prints out C:/example/folder and I want to get just folder.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • just use `split` – SuperStew Apr 02 '20 at 18:24
  • Maybe you can split the ````directoryName````, assuming there is at least one ````/```` at the end? –  Apr 02 '20 at 18:24
  • Similar question: https://stackoverflow.com/questions/3167154/how-to-split-a-dos-path-into-its-components-in-python – VPfB Apr 02 '20 at 18:28
  • @VPfB: that's a bad duplicate target because that OP causes the problem by not using rawstring or escaping, so `\s` gets misinterpreted. We must find a better dupe target. – smci Apr 02 '20 at 18:31
  • @smci: I did not say it's a dup. IMHO some of the answers can be modified to solve this problem. – VPfB Apr 02 '20 at 18:37
  • 1
    @VPfB: this absoutely is a dupe, there are tons of of existing questions. We simply need to find a good dupe target then close it. (I looked and I found lots of bad-quality ones). – smci Apr 02 '20 at 18:40
  • 2
    Why not use ``path``? How about ``pathlib``, is that also forbidden? Does it have to be OS agnostic? What about relative paths, such as ``a/b/../c``? – MisterMiyagi Apr 02 '20 at 18:48
  • 1
    What does _without full path mean_, and how does the "full path" affect the task? – AMC Apr 02 '20 at 18:53
  • Also, to be OS agnostic, and to handle '/' and r'\' on Windows, answers shouldn't assume a fixed separator. This is why `os` has `os.sep`. – smci Apr 02 '20 at 18:56
  • Does this answer your question? [How do I get a file's parent directory?](https://stackoverflow.com/questions/31525697/how-do-i-get-a-files-parent-directory) – Georgy Apr 06 '20 at 09:39

5 Answers5

11

The simplest way to do this would be using pathlib. Using parent will get you the parent's full path, and name will give you just the last component:

>>> from pathlib import Path
>>> path = Path("/a/b/c/d/e")
>>> path.parent.name
'd'

For comparison, to do the same with os.path, you will need to get the basename of the dirname of your path. So that translates directly to:

import os

path = "C:/example/folder/file1.jpg"
print(os.path.basename(os.path.dirname(path)))

Which is the nicer version of:

os.path.split(os.path.split(path)[0])[1]

Where both give:

'folder'

As you can see, the pathlib approach is much clearer and readable. Because pathlib incorporates the OOP approach for representing paths, instead of strings, we get a clear chain of attributes/method calls.

path.parent.name

Is read in order as:

start from path -> take its parent -> take its name

Whereas in the os functions-accepting-strings approach you actually need to read from inside-out!

os.path.basename(os.path.dirname(path))

Is read in order as:

The name of the parent of the path

Which I'm sure you'll agree is much harder to read and understand (and this is just a simple-case example).


You could also use the str.split method together with os.sep:

>>> path = "C:\\example\\folder\\file1.jpg"
>>> path.split(os.sep)[-2]
'folder'

But as the docs state:

Note that knowing this [(the separator)] is not sufficient to be able to parse or concatenate pathnames — use os.path.split() and os.path.join() — but it is occasionally useful.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • 1
    `os.path` is not the way to do it anymore. `pathlib.Path` is the way to go now. Yes it's a downvote, this is bad, error prone advice. – FHTMitchell Apr 02 '20 at 19:05
  • I love to advance and learn and appreciate the advice on `pathlib`, but would like to know what is wrong with using `os` @FHTMitchell – Tomerikoo Apr 02 '20 at 19:10
  • 2
    @Tomerikoo [This](https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/) might be a decent place to start. – AMC Apr 02 '20 at 19:13
  • ultimately because you're using strings to represent paths, which have loads of unpresentable states. You have to pile up these long, poorly described functions which don't work the same on different OSs. Trust me, working with path objects rather than strings is so, so much better – FHTMitchell Apr 02 '20 at 19:14
5

Use pathlib.Path to get the .name of the .parent:

from pathlib import Path

p = Path("C:/example/folder/file1.jpg")
print(p.parent.name)  # folder

Compared to os.path, pathlib represents paths as a separate type instead of strings. It generally is shorter and more convenient to use.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
  • 2
    It helps if you explain why `pathlib` module is now preferred to the older `os.path` – smci Apr 02 '20 at 19:04
  • I saw you changed `.stem` for `.name`, do you know if there is much of a difference here? – AMC Apr 02 '20 at 19:10
  • @AMC See the linked documentation. ``.stem`` strips the suffix, e.g. ``folder.001`` becomes ``folder``. – MisterMiyagi Apr 02 '20 at 19:11
  • 1
    @smci There seem to be a good amount of resources online on the subject, just sharing a link isn't great, but they could grab some points from something like https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/. – AMC Apr 02 '20 at 19:12
  • @MisterMiyagi Ah yes, I was only thinking of file extensions like `abc.jpg`. – AMC Apr 02 '20 at 19:12
  • @AMC: there are lots of links we could cite. But third-party blogs are very ephemeral, link is likely to go stale in a year or so. It's better to cite official doc, whatsnew, developer's own blog, articles. Also, I'd summarize the link's main points here in one terse sentence or paragraph, so that SO readers get the main points, also so search engine picks it up. – smci Apr 02 '20 at 19:26
  • 1
    @smci _Also, I'd summarize the link's main points here in one terse sentence or paragraph, so that SO readers get the main points, also so search engine picks it up._ Sorry if my comment wasn't clear, that's what I was trying to communicate! I didn't even think that the answer should link to the article at all. – AMC Apr 02 '20 at 19:33
  • @AMC: ah we essentially agree. It's best practice to *both* summarize the main points here and also cite the link (both to give due attribution, avoid any appearance of plagiary, gives link-love to the writer, and also demonstrate to the OP that there is an authoritative consensus on those recommendations. And make the 'best' answer more objective.) – smci Apr 02 '20 at 19:36
0

this works

path = "C:/example/folder/file1.jpg"
directoryName = os.path.dirname(path) 
parent = directoryName.split("/")
parent.reverse()
print(parent[0])


  • Do not use os anymore, use pathlib, which can do anything os can do and more than this. And it is by far easier to use. – questionto42 Nov 21 '20 at 22:29
0

Simple to solve using pathlib

0. Import Path from pathlib

from pathlib import Path
path = "C:/example/folder/file1.jpg"

1. Get parent level 1

parent_lv1 = Path(path).parent

2. Get parent level 2

parent_lv2 = parent_lv1.parent

3. Get immediate parent

imm_parent = parent_lv1.relative_to(parent_lv2)
print(imm_parent)
  • _Simple to solve using pathlib_ Yes, by doing what MisterMiyagi suggested in [their answer](https://stackoverflow.com/a/60999114/11301900). This solution was already mentioned by kederrac [here](https://stackoverflow.com/a/60998561/11301900). – AMC Apr 02 '20 at 19:23
  • @AMC This answer is not as simple as the accepted answer. Still, it is creative, using the `relative_to` idea which is too complicated for this question here but might help at some other problem. And even if this solution had been mentioned before by kederrac, that post and the user have gone. The header is totally wrong, since this solution is not simple, therefore no upvote. – questionto42 Nov 21 '20 at 22:27
-1

I prefer regex

import re

def get_parent(path: str) -> str:
    match = re.search(r".*[\\|/](\w+)[\\|/].*", path)
    if match:
        return match.group(1)
    else:
        return ""



if __name__ == '__main__':
    my_path = "/home/tony/some/cool/path"
    print(get_parent(my_path))
    win_path = r"C:\windows\path\has\dumb\backslashes"
    print(get_parent(win_path))

Output

cool
dumb
  • 3
    _I prefer regex_ Why? – AMC Apr 02 '20 at 19:04
  • 3
    Why should anyone prefer regex for this? This is in every objective way worse than `path.split(os.sep)[-2]` (or other approach). Less clear, unnecessary lines of code, less future-proof, more brittle. – smci Apr 02 '20 at 21:25
  • I see your point, my solution is more brittle and less clear. When it comes to string processing which is all a path is I naturally prefer regex. There are many solutions to the same problem. For those of us who don't have the ever-changing stdlib memorized I went with this approach. Sorry I was not more "pythonic". – marketzero Apr 03 '20 at 21:20
  • Taking a side for marketzero, SO is not about offering the fastest or simplest way when you post an answer. You can also offer a too complicated solution, as long as it works. It may still help at other problems. For example, I will take that regex to find all of the paths in a file and replace them with their parent.name. Edit suggestion: I would change the "I prefer regex" to "This is is overcomplicating things, just for completeness:". – questionto42 Nov 21 '20 at 22:36