ฉันจะรับไดเรกทอรีหลักใน Python ได้อย่างไร


350

มีคนบอกฉันเกี่ยวกับวิธีรับไดเรกทอรีพาเรนต์ใน Python แบบข้ามแพลตฟอร์ม เช่น

C:\Program Files ---> C:\

และ

C:\ ---> C:\

หากไดเรกทอรีไม่มีไดเรกทอรีหลักจะส่งคืนไดเรกทอรีเอง คำถามอาจดูเหมือนง่าย แต่ฉันไม่สามารถขุดผ่าน Google

คำตอบ:


481

อัพเดทจาก Python 3.4

ใช้pathlibโมดูล

from pathlib import Path
path = Path("/here/your/path/file.txt")
print(path.parent)

คำตอบเก่า

ลองสิ่งนี้:

import os.path
print os.path.abspath(os.path.join(yourpath, os.pardir))

ที่yourpathอยู่ในเส้นทางที่คุณต้องการสำหรับผู้ปกครอง


137
คำตอบของคุณถูกต้อง แต่มีความซับซ้อน os.path.dirnameเป็นฟังก์ชั่นนี้เหมือนจะซับซ้อนมากกว่าa+=5-4 a+=1คำถามที่ร้องขอเฉพาะไดเรกทอรีหลักไม่ว่าจะมีอยู่หรือไดเรกทอรีหลักจริงสมมติว่ามีการเชื่อมโยงสัญลักษณ์เข้าทาง
tzot

16
มันไม่ได้os.pardir os.path.pardir
bouteillebleu

9
@bouteillebleu: ทั้งสองos.pardirและos.path.pardirเป็นจริงที่ถูกต้อง (พวกเขาเป็นเหมือนกัน)
Eric O Lebigot

45
@tzot: น่าเสียดายที่os.path.dirnameให้ผลลัพธ์ที่แตกต่างกันขึ้นอยู่กับว่ามีการรวมเครื่องหมายสแลชต่อท้ายในเส้นทางหรือไม่ หากคุณต้องการผลลัพธ์ที่เชื่อถือได้คุณต้องใช้os.path.joinวิธีการดังกล่าวข้างต้น
Artfunkel

21
เนื่องจากนี่ซับซ้อนพอที่จะรับประกันคำถาม StackOverflow ฉันรู้สึกว่าควรเพิ่มสิ่งนี้ในไลบรารี os.path เป็นฟังก์ชันในตัว
2559

324

การใช้os.path.dirname:

>>> os.path.dirname(r'C:\Program Files')
'C:\\'
>>> os.path.dirname('C:\\')
'C:\\'
>>>

Caveat: os.path.dirname()ให้ผลลัพธ์ที่แตกต่างกันขึ้นอยู่กับว่ามีการต่อท้ายสแลชในเส้นทางหรือไม่ นี่อาจเป็นหรือไม่เป็นความหมายที่คุณต้องการ cf เลย @ คำตอบ kender os.path.join(yourpath, os.pardir)โดยใช้


6
os.path.dirname(r'C:\Program Files')อะไร? Python เพียงแค่ให้ไดเรกทอรีที่ไฟล์ 'Program Files' แก่คุณ ยิ่งไปกว่านั้นมันไม่จำเป็นต้องมีอยู่อีกแล้วดูเถิด: os.path.dirname(r'c:\i\like\to\eat\pie')เอาท์พุท'c:\\i\\like\\to\\eat'
นิค T

41
โปสเตอร์ต้นฉบับไม่ได้ระบุว่าต้องมีไดเรกทอรีอยู่ มีเมธอดชื่อพา ธ จำนวนมากที่ไม่ได้ทำอะไรนอกจากการจัดการสตริง ในการตรวจสอบว่าชื่อพา ธ มีอยู่จริงต้องการการเข้าถึงดิสก์หรือไม่ ขึ้นอยู่กับแอพพลิเคชั่นนี้อาจเป็นหรือไม่ต้องการก็ได้
Wai Yip Tung

10
โซลูชันนี้มีความไวต่อการติดตาม os.sep พูดว่า os.sep == '/' dirname (foo / bar) -> foo แต่ dirname (foo / bar /) -> foo / bar
marcin

6
นั่นคือจากการออกแบบ มันแปลความหมายของเส้นทางด้วยการลาก / คุณพิจารณา "path1" เท่ากับ "path1 /" หรือไม่ ห้องสมุดใช้การตีความโดยทั่วไปที่แตกต่าง ในบางบริบทผู้คนอาจต้องการปฏิบัติต่อพวกเขาอย่างเสมอภาค ในกรณีนี้คุณสามารถทำ rstrip ('/') ก่อน หากห้องสมุดเลือกการตีความอื่น ๆ คุณจะสูญเสียความจงรักภักดี
Wai Yip Tung

3
@ ไรอันฉันไม่รู้เกี่ยวกับสิ่งนั้น มี RFC 1808 ทั้งหมดที่เขียนขึ้นเพื่อแก้ไขปัญหาของเส้นทางสัมพัทธ์ใน URI และความละเอียดอ่อนทั้งหมดของการมีอยู่และไม่มีร่องรอย / หากคุณทราบถึงเอกสารใด ๆ ที่ระบุว่าควรได้รับการปฏิบัติที่เท่าเทียมกันโดยทั่วไปโปรดชี้ให้เห็น
Wai Yip Tung

112

วิธี Pathlib (Python 3.4+)

from pathlib import Path
Path('C:\Program Files').parent
# Returns a Pathlib object

วิธีการดั้งเดิม

import os.path
os.path.dirname('C:\Program Files')
# Returns a string


ฉันควรใช้วิธีใด

ใช้วิธีการดั้งเดิมถ้า:

  • คุณเป็นห่วงเกี่ยวกับข้อผิดพลาดในการสร้างรหัสที่มีอยู่หากใช้วัตถุ Pathlib (เนื่องจากวัตถุ Pathlib ไม่สามารถต่อกับสตริงได้)

  • Python เวอร์ชันของคุณน้อยกว่า 3.4

  • คุณต้องการสตริงและคุณได้รับสตริง พูดเช่นคุณมีสตริงที่แสดงถึงพา ธ ไฟล์และคุณต้องการรับพาเรนต์ไดเร็กทอรีเพื่อให้คุณสามารถวางไว้ในสตริง JSON มันจะเป็นการโง่ที่จะแปลงเป็นวัตถุ Pathlib และกลับมาอีกครั้งสำหรับสิ่งนั้น

หากไม่มีข้อใดข้อหนึ่งข้างต้นให้ใช้ Pathlib



Pathlib คืออะไร

หากคุณไม่ทราบว่า Pathlib คืออะไรโมดูล Pathlib เป็นโมดูลที่ยอดเยี่ยมที่ทำให้การทำงานกับไฟล์ง่ายขึ้นสำหรับคุณ ส่วนใหญ่หากไม่ใช่โมดูล Python ในตัวทั้งหมดที่ทำงานกับไฟล์จะยอมรับทั้งวัตถุและสตริง Pathlib ฉันได้เน้นด้านล่างตัวอย่างจากเอกสาร Pathlibที่แสดงบางสิ่งที่เรียบร้อยที่คุณสามารถทำได้กับ Pathlib

การนำทางภายในแผนผังไดเรกทอรี:

>>> p = Path('/etc')
>>> q = p / 'init.d' / 'reboot'
>>> q
PosixPath('/etc/init.d/reboot')
>>> q.resolve()
PosixPath('/etc/rc.d/init.d/halt')

การค้นหาคุณสมบัติพา ธ :

>>> q.exists()
True
>>> q.is_dir()
False

4
นี่เป็นคำตอบเดียวที่มีสติ หากคุณถูกบังคับให้ใช้ Python 2 เพียงpip install pathlib2และใช้ backport
Navin

1
วิธีนี้ไม่ไวต่อการตามมาos.sep!
Dylan F

35
import os
p = os.path.abspath('..')

C:\Program Files ---> C:\\\

C:\ ---> C:\\\


7
สิ่งนี้รับเฉพาะพาเรนต์ของ CWD ไม่ใช่พาเรนต์ของพา ธ โดยพลการตามที่ OP ถาม
Sergio

เพิ่มจุดคู่ที่ท้าย URL ของคุณและมันจะทำงานเช่น os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') ผล:E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury

หมายความว่า: /.
loretoparisi

26

โซลูชันสำรองของ @kender

import os
os.path.dirname(os.path.normpath(yourpath))

ที่yourpathอยู่ในเส้นทางที่คุณต้องการสำหรับผู้ปกครอง

แต่วิธีการแก้ปัญหานี้ไม่สมบูรณ์แบบเพราะมันจะไม่จัดการกับกรณีที่yourpathสตริงว่างหรือจุด

โซลูชันอื่น ๆ นี้จะจัดการกับกรณีมุมนี้ได้ดียิ่งขึ้น:

import os
os.path.normpath(os.path.join(yourpath, os.pardir))

นี่คือผลลัพธ์สำหรับทุก ๆ กรณีที่สามารถค้นหาได้ (เส้นทางเข้านั้นสัมพันธ์กัน):

os.path.dirname(os.path.normpath('a/b/'))          => 'a'
os.path.normpath(os.path.join('a/b/', os.pardir))  => 'a'

os.path.dirname(os.path.normpath('a/b'))           => 'a'
os.path.normpath(os.path.join('a/b', os.pardir))   => 'a'

os.path.dirname(os.path.normpath('a/'))            => ''
os.path.normpath(os.path.join('a/', os.pardir))    => '.'

os.path.dirname(os.path.normpath('a'))             => ''
os.path.normpath(os.path.join('a', os.pardir))     => '.'

os.path.dirname(os.path.normpath('.'))             => ''
os.path.normpath(os.path.join('.', os.pardir))     => '..'

os.path.dirname(os.path.normpath(''))              => ''
os.path.normpath(os.path.join('', os.pardir))      => '..'

os.path.dirname(os.path.normpath('..'))            => ''
os.path.normpath(os.path.join('..', os.pardir))    => '../..'

เส้นทางอินพุตเป็นสัมบูรณ์ (เส้นทาง Linux):

os.path.dirname(os.path.normpath('/a/b'))          => '/a'
os.path.normpath(os.path.join('/a/b', os.pardir))  => '/a'

os.path.dirname(os.path.normpath('/a'))            => '/'
os.path.normpath(os.path.join('/a', os.pardir))    => '/'

os.path.dirname(os.path.normpath('/'))             => '/'
os.path.normpath(os.path.join('/', os.pardir))     => '/'

การทำให้เส้นทางเป็นมาตรฐานเป็นแนวปฏิบัติที่ดีเสมอโดยเฉพาะอย่างยิ่งเมื่อทำงานข้ามแพลตฟอร์ม
DevPlayer

นี่คือคำตอบที่ถูกต้อง! มันทำให้เส้นทางญาติสัมพันธ์ ขอบคุณ!
Maxim

@Maxim การแก้ปัญหานี้ไม่ได้สมบูรณ์แบบฉันไม่ดีขึ้นมันตั้งแต่วิธีการแก้ปัญหาเดิมไม่ได้จัดการกับกรณีหนึ่ง
benjarobin

@benjarobin ใช่ฉันไม่เคยนึกถึงกรณีมุม ขอบคุณ
Maxim

18
os.path.split(os.path.abspath(mydir))[0]

สิ่งนี้จะใช้ไม่ได้กับพา ธ ที่ไปยังไดเรกทอรี แต่จะส่งคืนไดเรกทอรีอีกครั้ง
Anthony Briggs

2
@ AnthonyBriggs ฉันลองใช้ Python 2.7.3 บน Ubuntu 12.04 และดูเหมือนว่าจะทำงานได้ดี os.path.split(os.path.abspath("this/is/a/dir/"))[0]ผลตอบแทน'/home/daniel/this/is/a'ตามที่คาดไว้ ฉันไม่มีกล่อง Windows ที่ใช้งานอยู่เพื่อตรวจสอบที่นั่น คุณได้สังเกตเห็นการทำงานของการตั้งค่าที่คุณรายงานไว้หรือไม่
Dan Menes

parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]คุณสามารถทำ สิ่งนี้ - ฉันมั่นใจ - ทำงานได้เพราะหากมีเครื่องหมายทับอยู่ท้ายสุดมันจะถูกลบออก หากไม่มีเครื่องหมายทับจะยังคงใช้งานได้ (แม้ว่าส่วนสุดท้ายของเส้นทางจะยาวเพียงหนึ่งอักขระเท่านั้น) เนื่องจากเครื่องหมายทับก่อนหน้า แน่นอนว่านี้ถือว่าเส้นทางนั้นเหมาะสมและไม่พูดอะไรบางอย่าง/a//b/c///d////(ในระบบยูนิกซ์ที่ใช้ได้) ซึ่งโดยส่วนใหญ่แล้วจะเป็น (เหมาะสม) โดยเฉพาะอย่างยิ่งเมื่อคุณทำบางสิ่งบางอย่างเช่นos.path.abspathหรือos.pathฟังก์ชั่นอื่น ๆ
dylnmc

นอกจากนี้ในการที่จะตอบโต้สแลชจำนวนมากในตอนท้ายคุณสามารถเขียนลูปเล็ก ๆ ที่ลบวงนั้นออกได้ ฉันแน่ใจว่าอาจมีหนึ่งซับฉลาดที่จะทำมันหรืออาจจะทำอย่างนั้นและ os.path.split ในบรรทัดเดียว
dylnmc

@Den Menes ฉันเพิ่งเห็นคุณแสดงความคิดเห็น มันไม่ทำงานถ้าคุณมีบางอย่างเช่นos.path.split("a/b//c/d///")และcd //////dev////// is equivalent to cd / dev / `หรือcd /dev; ทั้งหมดนี้ใช้ได้ใน linux ฉันเพิ่งมากับสิ่งนี้และมันอาจจะมีประโยชน์แม้ว่า: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (นี้เป็นหลักค้นหาสำหรับที่ผ่านมาไม่ใช่เฉือนและได้รับการย่อยของเส้นทางขึ้นไปถ่านนั้น.) ฉันใช้แล้ววิ่งคำสั่งดังกล่าวและได้path = "/a//b///c///d////" '/a//b///c'
dylnmc

14
os.path.abspath(os.path.join(somepath, '..'))

สังเกต:

import posixpath
import ntpath

print ntpath.abspath(ntpath.join('C:\\', '..'))
print ntpath.abspath(ntpath.join('C:\\foo', '..'))
print posixpath.abspath(posixpath.join('/', '..'))
print posixpath.abspath(posixpath.join('/home', '..'))

7
import os
print"------------------------------------------------------------"
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
print("example 1: "+SITE_ROOT)
PARENT_ROOT=os.path.abspath(os.path.join(SITE_ROOT, os.pardir))
print("example 2: "+PARENT_ROOT)
GRANDPAPA_ROOT=os.path.abspath(os.path.join(PARENT_ROOT, os.pardir))
print("example 3: "+GRANDPAPA_ROOT)
print "------------------------------------------------------------"

6

หากคุณต้องการเพียงชื่อของโฟลเดอร์ที่เป็นผู้ปกครองทันทีของไฟล์ที่มีให้เป็นอาร์กิวเมนต์และไม่เส้นทางที่แน่นอนไปยังแฟ้มที่:

os.path.split(os.path.dirname(currentDir))[1]

เช่นที่มีcurrentDirค่า/home/user/path/to/myfile/file.ext

คำสั่งดังกล่าวจะกลับมา:

myfile


3
os.path.basename (os.path.dirname (current_dir)) สามารถใช้งานได้ที่นี่
DevPlayer

4
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

ตัวอย่างใน Ubuntu:

>>> my_path = '/home/user/documents'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'user'

ตัวอย่างเช่นใน Windows:

>>> my_path = 'C:\WINDOWS\system32'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'WINDOWS'

ทั้งสองตัวอย่างพยายามใน Python 2.7


3
import os.path

os.path.abspath(os.pardir)

สิ่งนี้จะถือว่าคุณต้องการไดเรกทอรีหลักของ "ไดเรกทอรีการทำงานปัจจุบัน" และไม่ใช่ไดเรกทอรีหลักที่มีเส้นทางทั่วไป
DevPlayer

3

สมมติว่าเรามีโครงสร้างไดเรกทอรีเช่น

1]

/home/User/P/Q/R

เราต้องการเข้าถึงเส้นทางของ "P" จากไดเรกทอรี R จากนั้นเราสามารถเข้าถึงการใช้

ROOT = os.path.abspath(os.path.join("..", os.pardir));

2]

/home/User/P/Q/R

เราต้องการเข้าถึงเส้นทางของไดเรกทอรี "Q" จากไดเรกทอรี R จากนั้นเราสามารถเข้าถึงการใช้

ROOT = os.path.abspath(os.path.join(".", os.pardir));

2

เพียงเพิ่มบางสิ่งในคำตอบของตุง (คุณต้องใช้rstrip('/')เพื่อให้เป็นด้านที่ปลอดภัยยิ่งขึ้นถ้าคุณอยู่ในกล่องยูนิกซ์)

>>> input = "../data/replies/"
>>> os.path.dirname(input.rstrip('/'))
'../data'
>>> input = "../data/replies"
>>> os.path.dirname(input.rstrip('/'))
'../data'

แต่ถ้าคุณไม่ใช้rstrip('/')ให้ป้อนข้อมูลของคุณคือ

>>> input = "../data/replies/"

จะเอาท์พุท

>>> os.path.dirname(input)
'../data/replies'

ซึ่งอาจไม่ใช่สิ่งที่คุณกำลังดูอยู่ตามที่คุณต้องการทั้งสอง"../data/replies/"และ"../data/replies"ประพฤติแบบเดียวกัน


1
ฉันขอแนะนำให้ไม่ใช้ "อินพุต" เป็นตัวแปร / การอ้างอิง มันเป็นฟังก์ชั่นในตัว
DevPlayer


1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

คุณสามารถใช้สิ่งนี้เพื่อรับไดเร็กทอรีพาเรนต์ของตำแหน่งปัจจุบันของไฟล์ py ของคุณ


2
คำแนะนำนั้นมักจะนำไปสู่ข้อบกพร่อง os.getcwd () มักจะไม่ใช่ที่ "ไฟล์ py ของคุณ" อยู่ คิดว่าแพ็คเกจ ถ้าฉัน "นำเข้า some_package_with_subpackages" โมดูลจำนวนมากจะไม่อยู่ในไดเรกทอรีบนสุดของแพ็คเกจนั้น os.getcwd () ส่งคืนตำแหน่งที่คุณเรียกใช้สคริปต์สูงสุด และนั่นก็หมายความว่าคุณกำลังทำมันจากบรรทัดคำสั่ง
DevPlayer

0

รับพา ธ ไดเร็กทอรีพาเรนต์และสร้างไดเร็กทอรีใหม่ (ชื่อnew_dir)

รับพา ธ ไดเร็กทอรีพาเรนต์

os.path.abspath('..')
os.pardir

ตัวอย่างที่ 1

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.pardir, 'new_dir'))

ตัวอย่างที่ 2

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.path.abspath('..'), 'new_dir'))


0
import os

def parent_filedir(n):
    return parent_filedir_iter(n, os.path.dirname(__file__))

def parent_filedir_iter(n, path):
    n = int(n)
    if n <= 1:
        return path
    return parent_filedir_iter(n - 1, os.path.dirname(path))

test_dir = os.path.abspath(parent_filedir(2))

0

คำตอบที่ให้ไว้ข้างต้นล้วนเป็นสิ่งที่สมบูรณ์แบบสำหรับการเพิ่มระดับไดเรกทอรีหนึ่งหรือสองระดับ แต่พวกเขาอาจได้รับความยุ่งยากเล็กน้อยหากต้องการสำรวจแผนผังไดเรกทอรีโดยใช้หลายระดับ (เช่น 5 หรือ 10) สิ่งนี้สามารถทำได้อย่างกระชับโดยการเข้าร่วมรายการของสิ่งN os.pardirต่อos.path.joinไปนี้ ตัวอย่าง:

import os
# Create list of ".." times 5
upup = [os.pardir]*5
# Extract list as arguments of join()
go_upup = os.path.join(*upup)
# Get abspath for current file
up_dir = os.path.abspath(os.path.join(__file__, go_upup))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.