pathlibはファイル操作の新標準!

Python Advent Calendar 2013の13日目です。

Python 3.4ではasyncio functools.singledispatchなど画期的なライブラリがいくつも追加されています。それはアドベンドカレンダーで皆さんが紹介されている通りです。

そして!その中で最も重要で画期的と言えるのがpathlibなのです!

11.1. pathlib ― Object-oriented filesystem paths ― Python v3.4.0b1 documentation

まずは、主な使用例を御覧ください

パスの結合(演算子オーバーロードだ!)

>>> from pathlib import Path
>>> p = Path('/etc')
>>> q = p / 'init.d' / 'reboot'
>>> q
PosixPath('/etc/init.d/reboot')

ファイル属性のチェック

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

パターンマッチで検索

>>> list(p.glob('**/*.py'))
[PosixPath('test_pathlib.py'), PosixPath('setup.py'),
 PosixPath('pathlib.py'), PosixPath('docs/conf.py'),
 PosixPath('build/lib/pathlib.py')]

ファイルを開く

>>> with q.open() as f: f.readline()
...
'#!/bin/bash\n'

オブジェクト指向

オブジェクト指向は後付だとかそうでないとか言われたPythonですが、 ファイルパスの操作は初期からずーっと文字列を直接操作、つまり明らかに非オブジェクト指向でした。

しかし、3.4に至ってとうとう pathlib でパスをオブジェクト指向で扱えるようになります!やったね!

全部入り

いままで、ファイル削除や移動はos・パターンマッチにはglobと、いろいろなライブラリに散らばっていました。

pathlibは以下の機能を統合しています。

  • abspath join basename などのパス操作(os.path
  • rename chmod listdir などのファイル操作(os
  • パターンマッチ(globfnmatch
  • ファイルを開く(io.open

シェルスクリプト代わりに使うなら、8割がたpathlibで完結するのではないでしょうか?

なお、 tempfile shutil subprocess の機能は含まれていないのですが、 pathlib.Path は文字列と相互変換できるので、これらともシームレスに運用できます。

path = Path('/usr/bin/python')

from subprocess import check_call
check_call(['ls', '-l', str(path)])

PurePosixPath/PureWindowsPath

LinuxとWindowsではパスの扱いが違います(区切り文字やドライブの存在)。 なので、 pathlib.Pathインスタンス化すると、実際にはpathlib.PosixPathpathlib.WindowsPathが返されます。Windowsでpathlib.PosixPathを使ったり、その逆はできません。

しかし、URLのパス部の解析など、Windows上でPosixのパスを扱いたいこともあります。

そんなときは、pathlib.PurePosixPathpathlib.PureWindowsPathを使います。 PurePathはパスを文字列として操作することはできますが、 ファイル移動などのファイルシステムへのアクセス操作はできません。

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pathlib
>>>
>>> # WindowsでPosixPathは使えません
>>> pathlib.PosixPath("foo")
NotImplementedError: cannot instantiate 'PosixPath' on your system

>>> # PurePosixPathは使えます!
>>> pathlib.PurePosixPath("foo")
PurePosixPath('foo')

じつは今までもos.path に対して、ntpath posixpath macpath があって、 Windows上でUnixのパス操作が出来たのですがマイナーでした。

旧バージョンでも使えます。

pathlibは元々サードパーティのライブラリなので、2.7・3.2・3.3でも使えます。

pathlib : Python Package Index

その他

ところでPathを呼ぶと、OS用のクラスのインスタンス(PosixPathかWindowsPath)が返ります。

Pathをそのままインスタンス化することは、普通の方法ではできません。

>>> pathlib.Path # Pathはクラス
<class 'pathlib.Path'>

>>> pathlib.Path("foo") #でもサブクラスのインスタンスが返る
WindowsPath('foo')

これはPath.__new__ をオーバーライドすることで実現されています。

class Path(PurePath):
    __slots__ = (
        '_accessor',
        '_closed',
    )

    def __new__(cls, *args, **kwargs):
        if cls is Path:
            cls = WindowsPath if os.name == 'nt' else PosixPath
        self = cls._from_parts(args, init=False)
        if not self._flavour.is_supported:
            raise NotImplementedError("cannot instantiate %r on your system"
                                      % (cls.__name__,))
        self._init()
        return self

詳しくはドキュメントを参照して下さい。

他にもpathlibはクラス・property・contextlibなどの基本的なテクニックが詰まっています。 使用目的が分かりやすく、分量も1300行弱ということで、入ってくる新人のコードリーディング課題に最適ではないでしょうか。

pitrou / pathlib ― Bitbucket

Enjoy!

Python Advent Calendar 2013