Column address: a Python module per week

Meanwhile, welcome to follow my wechat official account AlwaysBeta, more exciting content waiting for you.

This article writes tests based on Python3.

The os.path module is cross-platform, so you should use os.path even if you don’t plan to port your own applications between platforms.

Parsing path

The first set of os.path functions can be used to parse a string representing a filename into its constituent parts. It is important to realize that these capabilities do not depend on actual paths.

Path resolution depends on some OS variables defined as follows:

  • os.sep– Delimiter between path sections (for example,”/“Or”\“).
  • os.extsep– Separator between file name and file “extension” (for example,”.“).
  • os.pardir– Path component, which means traversing the directory tree up one level (for example,”.“).
  • os.curdir– Path components that reference the current directory (for example,”.“).

The split() function splits the path into two separate parts and returns a tuple result. The second element is the last element of the path, and the first element is all the elements before it.

import os.path

PATHS = [
    '/one/two/three'.'/one/two/three/'.'/'.'. '.' ',]for path in PATHS:
    print('{! r:>17} : {}'.format(path, os.path.split(path)))
    
# output
# '/one/two/three' : ('/one/two', 'three')
# '/one/two/three/' : ('/one/two/three', '')
# '/' : ('/', '')
# '.' : ('', '.')
# ": (",")
Copy the code

When the input argument ends in os.sep, the last element of the path is an empty string.

The basename() function returns a value equal to the second part of the value returned by split().

import os.path

PATHS = [
    '/one/two/three'.'/one/two/three/'.'/'.'. '.' ',]for path in PATHS:
    print('{! r:>17} : {! r}'.format(path, os.path.basename(path)))
    
# output
# '/one/two/three' : 'three'
# '/one/two/three/' : ''
# '/', ' '
# '. ':'. '
# ' ':' '
Copy the code

The full path is stripped down to the last element, either a file or a directory.

The dirname() function returns the first part of the split path:

import os.path

PATHS = [
    '/one/two/three'.'/one/two/three/'.'/'.'. '.' ',]for path in PATHS:
    print('{! r:>17} : {! r}'.format(path, os.path.dirname(path)))
    
# output
# '/one/two/three' : '/one/two'
# '/one/two/three/' : '/one/two/three'
# '/', '/'
# '. ':'
# ' ':' '
Copy the code

The results of basename() and dirname() are combined to return the original path.

Splitext () is similar to split(), but splits paths on extension separators instead of directory separators.

import os.path

PATHS = [
    'filename.txt'.'filename'.'/path/to/filename.txt'.'/'.' '.'my-archive.tar.gz'.'no-extension.',]for path in PATHS:
    print('{! r:>21} : {! r}'.format(path, os.path.splitext(path)))
    
# output
# 'filename.txt' : ('filename', '.txt')
# 'filename' : ('filename', '')
# '/path/to/filename.txt' : ('/path/to/filename', '.txt')
# '/' : ('/', '')
# ": (",")
# 'my-archive.tar.gz' : ('my-archive.tar', '.gz')
# 'no-extension.' : ('no-extension', '.')
Copy the code

Os.extsep only matches the last occurrence of the separator when looking for an extension, so if a file name has more than one extension, it is split by the last extension.

Commonprefix () takes a list of paths as an argument and returns a single string representing the common prefixes that exist in all paths. This value can also represent paths that do not actually exist, and path separators are not included in the consideration.

import os.path

paths = ['/one/two/three/four'.'/one/two/threefold'.'/one/two/three/',]for path in paths:
    print('PATH:', path)

print()
print('PREFIX:', os.path.commonprefix(paths))

# output
# PATH: /one/two/three/four
# PATH: /one/two/threefold
# PATH: /one/two/three/
# 
# PREFIX: /one/two/three
Copy the code

In this example, the common prefix string is /one/two/three, even though a path does not contain the directory named three.

Commonpath () takes path separators into account and returns a prefix that does not contain partial path values.

import os.path

paths = ['/one/two/three/four'.'/one/two/threefold'.'/one/two/three/',]for path in paths:
    print('PATH:', path)

print()
print('PREFIX:', os.path.commonpath(paths))

# output
# PATH: /one/two/three/four
# PATH: /one/two/threefold
# PATH: /one/two/three/
# 
# PREFIX: /one/two
Copy the code

Build path

In addition to separating existing paths, you often need to build paths from other strings. To combine multiple paths into a single value, use join() :

import os.path

PATHS = [
    ('one'.'two'.'three'),
    ('/'.'one'.'two'.'three'),
    ('/one'.'/two'.'/three'),]for parts in PATHS:
    print('{} : {!r}'.format(parts, os.path.join(*parts)))
    
# output
# ('one', 'two', 'three') : 'one/two/three'
# ('/', 'one', 'two', 'three') : '/one/two/three'
# ('/one', '/two', '/three') : '/three'
Copy the code

If any of the arguments start with os.sep, all previous arguments are discarded and this value is used as the beginning of the return value.

You can also use paths that contain “mutable” components that can be automatically extended. For example, expandUser () converts the ~ character to the name of the user’s home directory.

import os.path

for user in [' '.'dhellmann'.'nosuchuser']:
    lookup = '~' + user
    print('{! r:>15} : {! r}'.format(lookup, os.path.expanduser(lookup)))
    
# output
# '~' : '/Users/dhellmann'
# '~dhellmann' : '/Users/dhellmann'
# '~nosuchuser' : '~nosuchuser'
Copy the code

If the user’s home directory cannot be found, the string is returned unchanged, such as ~nosuchuser.

Expandvars () is more general, extending any shell environment variable that exists in the path.

import os.path
import os

os.environ['MYVAR'] = 'VALUE'

print(os.path.expandvars('/path/to/$MYVAR'))	# /path/to/VALUE
Copy the code

The existence of files or paths is not verified.

Normalized path

Paths that use join() combinations may have additional delimiters or relative paths. Use normpath() to clean them up:

import os.path

PATHS = [
    'one//two//three'.'one/./two/./three'.'one/.. /alt/two/three',]for path in PATHS:
    print('{! r:>22} : {! r}'.format(path, os.path.normpath(path)))
    
# output
# 'one//two//three' : 'one/two/three'
# 'one/./two/./three' : 'one/two/three'
# 'one/.. /alt/two/three' : 'alt/two/three'
Copy the code

To convert a relative path to an absolute file name, use abspath().

import os
import os.path

os.chdir('/usr')

PATHS = [
    '. '.'.. '.'./one/two/three'.'.. /one/two/three',]for path in PATHS:
    print('{! r:>21} : {! r}'.format(path, os.path.abspath(path)))
    
# output
# '.' : '/usr'
# '.. ':'/'
# './one/two/three' : '/usr/one/two/three'
# '.. /one/two/three' : '/one/two/three'
Copy the code

File time

In addition to using paths, os.path also includes functions to retrieve file attributes, similar to os.stat() :

import os.path
import time

print('File :', __file__)
print('Access time :', time.ctime(os.path.getatime(__file__)))
print('Modified time:', time.ctime(os.path.getmtime(__file__)))
print('Change time :', time.ctime(os.path.getctime(__file__)))
print('Size :', os.path.getsize(__file__))

# output
# File : ospath_properties.py
# Access time : Sun Mar 18 16:21:22 2018
# Modified time: Fri Nov 11 17:18:44 2016
# Change time : Fri Nov 11 17:18:44 2016
# Size : 481
Copy the code

Os.path.getatime () returns the access time, os.path.getmtime() returns the modification time, and os.path.getctime() returns the creation time. Os.path.getsize () returns the amount of data in the file, in bytes.

The test file

When a program encounters a pathname, it usually needs to know whether the path refers to a file, directory, or symbolic link, and whether it exists. Os.path includes the ability to test all of these conditions.

import os.path

FILENAMES = [
    __file__,
    os.path.dirname(__file__),
    '/'.'./broken_link',]for file in FILENAMES:
    print('File : {! r}'.format(file))
    print('Absolute :', os.path.isabs(file))
    print('Is File? : ', os.path.isfile(file))
    print('Is Dir? : ', os.path.isdir(file))
    print('Is Link? : ', os.path.islink(file))
    print('Mountpoint? : ', os.path.ismount(file))
    print('Exists? : ', os.path.exists(file))
    print('Link Exists? : ', os.path.lexists(file))
    print()
    
# output
# File : 'ospath_tests.py'
# Absolute : False
# Is File? : True
# Is Dir? : False
# Is Link? : False
# Mountpoint? : False
# Exists? : True
# Link Exists? : True
# 
# File : ''
# Absolute : False
# Is File? : False
# Is Dir? : False
# Is Link? : False
# Mountpoint? : False
# Exists? : False
# Link Exists? : False
# 
# File : '/'
# Absolute : True
# Is File? : False
# Is Dir? : True
# Is Link? : False
# Mountpoint? : True
# Exists? : True
# Link Exists? : True
# 
# File : './broken_link'
# Absolute : False
# Is File? : False
# Is Dir? : False
# Is Link? : True
# Mountpoint? : False
# Exists? : False
# Link Exists? : True
Copy the code

All test functions return a Boolean value.

Related documents:

Pymotw.com/3/os.path/i…