ChatGPT解决这个技术问题 Extra ChatGPT

constructing absolute path with os.path.join()

I'd like to construct an absolute path in python, while at the same time staying fairly oblivious of things like path-separator.

edit0: for instance there is a directory on the root of my filesystem /etc/init.d (or C:\etc\init.d on w32), and I want to construct this only from the elements etc and init.d (on w32, I probably also need a disk-ID, like C:)

In order to not having to worry about path-separators, os.join.path() is obviously the tool of choice. But it seems that this will only ever create relative paths:

 print("MYPATH: %s" % (os.path.join('etc', 'init.d'),)
 MYPATH: etc/init.d

Adding a dummy first-element (e.g. '') doesn't help anything:

 print("MYPATH: %s" % (os.path.join('', 'etc', 'init.d'),)
 MYPATH: etc/init.d

Making the first element absolute obviously helps, but this kind of defeats the idea of using os.path.join()

 print("MYPATH: %s" % (os.path.join('/etc', 'init.d'),)
 MYPATH: /etc/init.d

edit1: using os.path.abspath() will only try to convert a relative path into an absolute path. e.g. consider running the following in the working directory /home/foo:

 print("MYPATH: %s" % (os.path.abspath(os.path.join('etc', 'init.d')),)
 MYPATH: /home/foo/etc/init.d

So, what is the standard cross-platform way to "root" a path?

 root = ??? # <--
 print("MYPATH: %s" % (os.path.join(root, 'etc', 'init.d'),)
 MYPATH: /etc/init.d

edit2: the question really boils down to: since the leading slash in /etc/init.d makes this path an absolute path, is there a way to construct this leading slash programmatically? (I do not want to make assumptions that a leading slash indicates an absolute path)

I'm not sure I'm reading your question correctly, but could you simply: os.path.abspath('python.exe') which on my windows machine returns 'C:\\Python27\\python.exe'
i've updated the question to (hopefully) clarify what i want.
btw, relevant near-duplicate: stackoverflow.com/questions/12041525/…
None of these answers work for me. How can I join root_dir="C:/Users/folder" with filename="data/file1.txt" to get an absolute path? In not-windows it's easy with just os.path.join(root_dir, filename), but I can't find a solution in Windows.

g
girardc79

Using os.sep as root worked for me:

path.join(os.sep, 'python', 'bin')

Linux: /python/bin

Windows: \python\bin

Adding path.abspath() to the mix will give you drive letters on Windows as well and is still compatible with Linux:

path.abspath(path.join(os.sep, 'python', 'bin'))

Linux: /python/bin

Windows: C:\python\bin


Seems to work on Linux and Win, so +1. But feels wrong. Might break on some other obscure system, but I can think of none. Still feels like python should give us an explicit way to do that. This depends on absolute paths starting with the path-separator.
J
Jack O'Connor

I think you can use os.path.normpath. Here's what I get on Windows:

>>> os.path.normpath("/etc/init.d")
'\\etc\\init.d'

I'm not sure exactly what the right thing to do with the drive prefix is, but I think leaving it off means something like "keep using the drive I'm on now," which is probably what you want. Maybe someone more familiar with Windows can clarify?


this is the right answer, let python do the work of figuring out which platform you're on
I agree with the sentiment, yet this uses a fully qualified path and NOT os.path.join(). While it is useful to know, it does not qualify as a solution.
u
umläute

so the solution i came up with, is to construct the root of the filesystem by following a given file to it's root:

def getRoot(file=None):
  if file is None:
      file='.'
  me=os.path.abspath(file)
  drive,path=os.path.splitdrive(me)
  while 1:
    path,folder=os.path.split(path)
    if not folder:
       break
  return drive+path

 os.path.join(getRoot(), 'etc', 'init.d')

could even be simpler: drive,path=os.path.splitdrive(me) if not drive: return os.path.split(path)[0] else: return drive
hmm, i'm sure that my solution is not the most pythonic way; but your solution will return /foo/bar/baz if the file evaulates to /foo/bar/baz (basically the problem you mentioned for Ansuman's answer)
darn it, you're right. got misled by another answer on SO >.<
I find this interesting but I am somewhat puzzled on the reason why it is still the accepted answer.
A
Ansuman Bebarta

So you can do a check for running os by sys.platfrom

on windows

>>> sys.platform
'win32'

on linux

>>> sys.platform
'linux2'

then

if sys.platform == 'win32':
    ROOT = os.path.splitdrive(os.path.abspath('.'))[0]
elif sys.platform == 'linux2':
    ROOT = os.sep

Please note that 'linux2' may not cover all linux distros


no, i really want the ROOT of my filesystem (regardless where the python modules are located). os.path.abspath('foo') will return (e.g.) /home/me/foo (if i run it within /home/me) while i really need /foo (or C:\\foo)
i've updated the question to clarify why os.path.abspath() does not seem to help me.
If you want to have a ROOT which is not based on file and same ROOT for all files in a specific project. Than you can store the ROOT (a string value) in a config file or you can define a ROOT by hardcoded values in all the file. I have added this in my answer.
the question is: what makes /etc an absolute path? (obviously the / prefix, but is there a programmatic way to get this suffix?)
OK. I think I got it. There is os.path.splitdrive() which returns you the drive os.path.splitdrive(os.path.abspath('.')) but on linux it will not return you the root ie. '/'
C
Christoph

you could try with os.path.splitdrive to get the name of your drive/filesystem, then join this with your foo string.

http://docs.python.org/2/library/os.path.html#os.path.splitdrive

something like (untested!)

(drive, tail) = os.path.splitdrive(os.getcwd())
os.path.join(drive, 'foo')

should do the trick.


doesn't work on linux - drive gets set to '' and joining with that doesn't give a rooted path