標準ライブラリ

前回までで、Pythonを利用するための機能はざっくり説明できたと思う。後は、ライブラリの使い方を押さえておけば、実際に”使える”ツールになるはずだ。

The Python Tutorialでは、クラスの説明をした後に標準ライブラリを取り上げ、デフォルトで提供されている「よく使われるモジュール」を紹介している。ある程度プログラムの経験がある方なら、チュートリアルとしてはここから読んでもよいくらいだ。どういったことができるのか、ざっと追っていこう。

osモジュール

osモジュールにはOSの提供している機能にアクセスするためのインタフェースがまとまっている。カレントディレクトリの獲得、カレントディレクトリの移動、システムコマンドの実行といった処理は次のようにosモジュールを利用することで実現できる。

>>> import os
>>> os.getcwd()
'/home/daichi'
>>> os.system('mkdir testdir')
0
>>> os.chdir('./testdir/')
>>> os.getcwd()
'/home/daichi/testdir'
>>> os.system('ls -al')
total 8
drwxrwxr-x  2 daichi daichi 4096 Apr 26 04:34 .
drwxr-xr-x 11 daichi daichi 4096 Apr 26 04:34 ..
0
>>>

特に、すでにシェルやシェルスクリプトに精通している場合はos.system()を覚えておこう。これはC言語の標準Cライブラリ(stdlib.h)に含まれているsystem(3)関数と同等な処理をするもので、指定された文字列をシェルで実行してくれる。いざとなったらここからコマンドを実行して、Pythonではどう書けばよいかわからない部分はシェルで処理するといったことができる。

このようにモジュールを使う場合、次の2つを知る手段が必要になるだろう。

  • 何をするモジュールなのか
  • どんなクラスや関数、変数が用意されているのか


この2つは「help(モジュール名)」と「dir(モジュール名)」を実行することで解決することができる。「このモジュールって何をするものだったかな」「このモジュールってどういった機能を提供してるんだっけな」というときは、「help(モジュール名)」のように実行すればよい。例えば、次のように「help(os)」のように実行すると、osモジュールの説明をオンラインマニュアルと同じ要領で読むことができる。

>>> help(os)

Help on module os:

NAME
    os - OS routines for NT or Posix depending on what system we're on.

MODULE REFERENCE
    https://docs.python.org/3.6/library/os

    The following documentation is automatically generated from the Python
    source files.  It may be incomplete, incorrect or include features that
    are considered implementation detail and may vary between Python
    implementations.  When in doubt, consult the module reference at the
    location listed above.

DESCRIPTION
    This exports:
      - all functions from posix or nt, e.g. unlink, stat, etc.
      - os.path is either posixpath or ntpath
      - os.name is either 'posix' or 'nt'
      - os.curdir is a string representing the current directory (always '.')
      - os.pardir is a string representing the parent directory (always '..')
      - os.sep is the (or a most common) pathname separator ('/' or '\\')
      - os.extsep is the extension separator (always '.')
      - os.altsep is the alternate pathname separator (None or '/')
      - os.pathsep is the component separator used in $PATH etc
      - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
      - os.defpath is the default search path for executables
      - os.devnull is the file path of the null device ('/dev/null', etc.)

一方、そのモジュールにどういったクラスや関数、変数が用意されているかは「dir(モジュール名)」のように実行すれば調べることができる。osモジュールの場合は次のようになる。

>>> import os
>>> dir(os)
['CLD_CONTINUED', 'CLD_DUMPED', 'CLD_EXITED', 'CLD_TRAPPED', 'DirEntry', 'EX_CANTCREAT', 'EX_CONFIG', 'EX_DATAERR', 'EX_IOERR', 'EX_NOHOST', 'EX_NOINPUT', 'EX_NOPERM', 'EX_NOUSER', 'EX_OK', 'EX_OSERR', 'EX_OSFILE', 'EX_PROTOCOL', 'EX_SOFTWARE', 'EX_TEMPFAIL', 'EX_UNAVAILABLE', 'EX_USAGE', 'F_LOCK', 'F_OK', 'F_TEST', 'F_TLOCK', 'F_ULOCK', 'GRND_NONBLOCK', 'GRND_RANDOM', 'MutableMapping', 'NGROUPS_MAX', 'O_ACCMODE', 'O_APPEND', 'O_ASYNC', 'O_CLOEXEC', 'O_CREAT', 'O_DIRECT', 'O_DIRECTORY', 'O_DSYNC', 'O_EXCL', 'O_LARGEFILE', 'O_NDELAY', 'O_NOATIME', 'O_NOCTTY', 'O_NOFOLLOW', 'O_NONBLOCK', 'O_PATH', 'O_RDONLY', 'O_RDWR', 'O_RSYNC', 'O_SYNC', 'O_TMPFILE', 'O_TRUNC', 'O_WRONLY', 'POSIX_FADV_DONTNEED', 'POSIX_FADV_NOREUSE', 'POSIX_FADV_NORMAL', 'POSIX_FADV_RANDOM', 'POSIX_FADV_SEQUENTIAL', 'POSIX_FADV_WILLNEED', 'PRIO_PGRP', 'PRIO_PROCESS', 'PRIO_USER', 'P_ALL', 'P_NOWAIT', 'P_NOWAITO', 'P_PGID', 'P_PID', 'P_WAIT', 'PathLike', 'RTLD_DEEPBIND', 'RTLD_GLOBAL', 'RTLD_LAZY', 'RTLD_LOCAL', 'RTLD_NODELETE', 'RTLD_NOLOA
', 'RTLD_NOW', 'R_OK', 'SCHED_BATCH', 'SCHED_FIFO', 'SCHED_IDLE', 'SCHED_OTHER', 'SCHED_RESET_ON_FORK', 'SCHED_RR', 'SEEK_CUR', 'SEEK_DATA', 'SEEK_END', 'SEEK_HOLE', 'SEEK_SET', 'ST_APPEND', 'ST_MANDLOCK', 'ST_NOATIME', 'ST_NODEV', 'ST_NODIRATIME', 'ST_NOEXEC', 'ST_NOSUID', 'ST_RDONLY', 'ST_RELATIME', 'ST_SYNCHRONOUS', 'ST_WRITE', 'TMP_MAX', 'WCONTINUED', 'WCOREDUMP', 'WEXITED', 'WEXITSTATUS', 'WIFCONTINUED', 'WIFEXITED', 'WIFSIGNALED', 'WIFSTOPPED', 'WNOHANG', 'WNOWAIT', 'WSTOPPED', 'WSTOPSIG', 'WTERMSIG', 'WUNTRACED', 'W_OK', 'XATTR_CREATE', 'XATTR_REPLACE', 'XATTR_SIZE_MAX', 'X_OK', '_Environ', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_execvpe', '_exists', '_exit', '_fspath', '_fwalk', '_get_exports_list', '_putenv', '_spawnvef', '_unsetenv', '_wrap_close', 'abc', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'chown', 'chroot', 'close', 'closerange', 'confstr', 'confstr_names', 'cpu_count', 'ctermid', 'curdir', 'defpath', 'dev
ce_encoding', 'devnull', 'dup', 'dup2', 'environ', 'environb', 'errno', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fchdir', 'fchmod', 'fchown', 'fdatasync', 'fdopen', 'fork', 'forkpty', 'fpathconf', 'fsdecode', 'fsencode', 'fspath', 'fstat', 'fstatvfs', 'fsync', 'ftruncate', 'fwalk', 'get_blocking', 'get_exec_path', 'get_inheritable', 'get_terminal_size', 'getcwd', 'getcwdb', 'getegid', 'getenv', 'getenvb', 'geteuid', 'getgid', 'getgrouplist', 'getgroups', 'getloadavg', 'getlogin', 'getpgid', 'getpgrp', 'getpid', 'getppid', 'getpriority', 'getrandom', 'getresgid', 'getresuid', 'getsid', 'getuid', 'getxattr', 'initgroups', 'isatty', 'kill', 'killpg', 'lchown', 'linesep', 'link', 'listdir', 'listxattr', 'lockf', 'lseek', 'lstat', 'major', 'makedev', 'makedirs', 'minor', 'mkdir', 'mkfifo', 'mknod', 'name', 'nice', 'open', 'openpty', 'pardir', 'path', 'pathconf', 'pathconf_names', 'pathsep', 'pipe', 'pipe2', 'popen', 'posix_fadvise', 'posix_fallocate', '
read', 'putenv', 'pwrite', 'read', 'readlink', 'readv', 'remove', 'removedirs', 'removexattr', 'rename', 'renames', 'replace', 'rmdir', 'scandir', 'sched_get_priority_max', 'sched_get_priority_min', 'sched_getaffinity', 'sched_getparam', 'sched_getscheduler', 'sched_param', 'sched_rr_get_interval', 'sched_setaffinity', 'sched_setparam', 'sched_setscheduler', 'sched_yield', 'sendfile', 'sep', 'set_blocking', 'set_inheritable', 'setegid', 'seteuid', 'setgid', 'setgroups', 'setpgid', 'setpgrp', 'setpriority', 'setregid', 'setresgid', 'setresuid', 'setreuid', 'setsid', 'setuid', 'setxattr', 'spawnl', 'spawnle', 'spawnlp', 'spawnlpe', 'spawnv', 'spawnve', 'spawnvp', 'spawnvpe', 'st', 'stat', 'stat_float_times', 'stat_result', 'statvfs', 'statvfs_result', 'strerror', 'supports_bytes_environ', 'supports_dir_fd', 'supports_effective_ids', 'supports_fd', 'supports_follow_symlinks', 'symlink', 'sync', 'sys', 'sysconf', 'sysconf_names', 'system', 'tcgetpgrp', 'tcsetpgrp', 'terminal_size', 'times', 'times_result', 'tr
ncate', 'ttyname', 'umask', 'uname', 'uname_result', 'unlink', 'unsetenv', 'urandom', 'utime', 'wait', 'wait3', 'wait4', 'waitid', 'waitid_result', 'waitpid', 'walk', 'write', 'writev']
>>>

上記の出力はdir(os)の実行結果だが、osモジュールという名前の通り、OSが提供している標準ライブラリ関数やシステムコールと同じ名前の関数が大量に存在していることがわかる。osモジュールは、標準ライブラリ関数やシステムコールをそのままPythonの関数として提供するためのモジュールということだ。

「help(モジュール名)」と「dir(モジュール名)」を覚えておけば、かなりの情報が得られるようになる。ぜひこの使い方は覚えておこう。

shutilモジュール

osモジュールよりも、もうちょっとコマンド寄りの機能を提供しているのがshutilモジュールだ。ファイルのコピーや移動、圧縮ファイルの扱い、ディレクトリごとのコピーといった機能が提供されている。実行サンプルは次のとおりだ。

>>> import shutil
>>> dir(shutil)
['Error', 'ExecError', 'ReadError', 'RegistryError', 'SameFileError', 'SpecialFileError', '_ARCHIVE_FORMATS', '_BZ2_SUPPORTED', '_LZMA_SUPPORTED', '_UNPACK_FORMATS', '_ZLIB_SUPPORTED', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_basename', '_check_unpack_options', '_copyxattr', '_destinsrc', '_ensure_directory', '_find_unpack_format', '_get_gid', '_get_uid', '_make_tarball', '_make_zipfile', '_ntuple_diskusage', '_rmtree_safe_fd', '_rmtree_unsafe', '_samefile', '_unpack_tarfile', '_unpack_zipfile', '_use_fd_functions', 'chown', 'collections', 'copy', 'copy2', 'copyfile', 'copyfileobj', 'copymode', 'copystat', 'copytree', 'disk_usage', 'errno', 'fnmatch', 'get_archive_formats', 'get_terminal_size', 'get_unpack_formats', 'getgrnam', 'getpwnam', 'ignore_patterns', 'make_archive', 'move', 'os', 'register_archive_format', 'register_unpack_format', 'rmtree', 'stat', 'sys', 'unpack_archive', 'unregister_archive_format', 'unregister_unpack_
ormat', 'which']
>>> shutil.copy('/dev/null', 'empty.data')
'empty.data'
>>> os.system('ls -al')
total 8
drwxrwxr-x  2 daichi daichi 4096 Apr 26 04:38 .
drwxr-xr-x 11 daichi daichi 4096 Apr 26 04:34 ..
-rw-rw-rw-  1 daichi daichi    0 Apr 26 04:38 empty.data
0
>>> shutil.move('empty.data', 'data2')
'data2'
>>> os.system('ls -al')
total 8
drwxrwxr-x  2 daichi daichi 4096 Apr 26 04:39 .
drwxr-xr-x 11 daichi daichi 4096 Apr 26 04:34 ..
-rw-rw-rw-  1 daichi daichi    0 Apr 26 04:38 data2
0
>>>

globモジュール

シェルにはファイルグロブの機能があり、「*」をワイルドカード的にパスに含めることができるようになっている。Pythonではその機能がglobモジュールにまとまっており、次のような感じで使用できる。

>>> import glob
>>> dir(glob)
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_glob0', '_glob1', '_glob2', '_iglob', '_ishidden', '_isrecursive', '_iterdir', '_rlistdir', 'escape', 'fnmatch', 'glob', 'glob0', 'glob1', 'has_magic', 'iglob', 'magic_check', 'magic_check_bytes', 'os', 're']
>>> glob.glob('*')
['data2']
>>> glob.glob('/etc/*conf')
['/etc/rsyslog.conf', '/etc/deluser.conf', '/etc/libaudit.conf', '/etc/ltrace.conf', '/etc/gai.conf', '/etc/overlayroot.conf', '/etc/sos.conf', '/etc/mke2fs.conf', '/etc/ca-certificates.conf', '/etc/ucf.conf', '/etc/ld.so.conf', '/etc/nsswitch.conf', '/etc/hdparm.conf', '/etc/pam.conf', '/etc/sysctl.conf', '/etc/lftp.conf', '/etc/kernel-img.conf', '/etc/adduser.conf', '/etc/sensors3.conf', '/etc/host.conf', '/etc/fuse.conf', '/etc/logrotate.conf', '/etc/resolv.conf', '/etc/popularity-contest.conf', '/etc/debconf.conf', '/etc/updatedb.conf']
>>>

sysモジュール

標準入力や標準出力、標準エラー出力、引数処理、バージョン、プログラムの終了といった処理はsysモジュールにまとまっている。

>>> import sys
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', '
ath', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'set_asyncgen_hooks', 'set_coroutine_wrapper', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions']
>>> sys.stderr.write('エラーメッセージ\n')
エラーメッセージ
9
>>>

reモジュール

便利なスクリプト言語に欠かすことのできない機能の1つに正規表現があるが、当然Pythonも正規表現の機能を提供している。正規表現に関してはreモジュールに機能がまとまっている。

>>> import re
>>> dir(re)
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_alphanum_bytes', '_alphanum_str', '_cache', '_compile', '_compile_repl', '_expand', '_locale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'template']
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'
>>>

PythonのreモジュールはPerlが提供しているのと同じ種類の正規表現を提供しており、多くのプログラミング言語と互換性がある。正規表現をよく使っているのなら、reモジュールを使うことで目的を達成することができる。

mathモジュール

C言語のmath.hで定義されているような算術演算関数はmathモジュールにまとまっている。

>>> import math
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
>>> math.cos(math.pi / 4)
0.7071067811865476
>>> math.log(1024, 2)
10.0
>>>

システム管理のような用途だと、このモジュールを使うことはあまりないかもしれないが、知っておいて損はないはずだ。

randomモジュール

乱数に関する機能はrandomモジュールにまとまっている。乱数は、プログラムを書く際にはちょいちょい使う機会があるので、どのような機能が存在しているのか知っておくとよいだろう。

>>> import random
>>> dir(random)
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_BuiltinMethodType', '_MethodType', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_acos', '_bisect', '_ceil', '_cos', '_e', '_exp', '_inst', '_itertools', '_log', '_pi', '_random', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.choice(['apple', 'pear', 'banana'])
'banana'
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.choice(['apple', 'pear', 'banana'])
'banana'
>>> random.choice(['apple', 'pear', 'banana'])
'banana'
>>> random.choice(['apple', 'pear', 'banana'])
'pear'
>>> random.sample(range(100), 10)
[24, 33, 44, 71, 80, 61, 3, 48, 52, 20]
>>> random.sample(range(100), 10)
[90, 37, 9, 74, 25, 10, 7, 77, 26, 18]
>>> random.sample(range(100), 10)
[50, 22, 4, 73, 18, 25, 23, 79, 86, 91]
>>> random.sample(range(100), 10)
[77, 24, 72, 1, 9, 97, 69, 93, 40, 46]
>>> random.sample(range(100), 10)
[19, 30, 48, 89, 50, 2, 49, 0, 43, 52]
>>> random.sample(range(100), 10)
[43, 49, 31, 81, 63, 88, 9, 16, 82, 57]
>>> random.random()
0.6137331987481143
>>> random.random()
0.5211269906387623
>>> random.random()
0.05648542401896395
>>> random.random()
0.4094757440429777
>>> random.random()
0.009516574907638353
>>> random.randrange(6)
0
>>> random.randrange(6)
1
>>> random.randrange(6)
0
>>> random.randrange(6)
1
>>> random.randrange(6)
4
>>> random.randrange(6)
5
>>>

statisticsモジュール

統計に関する機能はstatisticsモジュールにまとまっている。こちらはrandomモジュールと違ってそれほど使うことはないかもしれないが、必要になった場合は、このモジュールを使用すればよい。

>>> import statistics
>>> dir(statistics)
['Decimal', 'Fraction', 'StatisticsError', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_coerce', '_convert', '_counts', '_exact_ratio', '_fail_neg', '_find_lteq', '_find_rteq', '_isfinite', '_ss', '_sum', 'bisect_left', 'bisect_right', 'chain', 'collections', 'decimal', 'groupby', 'harmonic_mean', 'math', 'mean', 'median', 'median_grouped', 'median_high', 'median_low', 'mode', 'numbers', 'pstdev', 'pvariance', 'stdev', 'variance']
>>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
>>> statistics.mean(data)
1.6071428571428572
>>> statistics.median(data)
1.25
>>> statistics.variance(data)
1.3720238095238095
>>>

OSに近い低レベルにも素直に対応

C言語の経験があれば、こうした標準モジュールはOSの提供している標準ライブラリ関数がそのままPythonの関数として実装されていることに気がつくと思う。そういった観点から言うと、C言語の経験があるとPythonを使い始める際のハードルはかなり低くなる。

Pythonの場合にはC言語と違ってポインタの扱いに気を配る必要がなく、結構大雑把に扱ってもそれなりに機能するものが作れる。C言語の標準ライブラリ関数について知識があれば、同じ処理がPythonでもすぐに利用できるようになるだろう。”簡素化されたC言語”みたいなものだと割り切って使ってみるのもアリじゃないかと思う。

ここまで理解していれば、例えばこれまでシェルスクリプトで作成して使っていたものや、C言語で作ったツールなんかをPythonで実装し直すといったことができるようになっているはずだ。もしそういったツールをすでに持っているなら、この段階でいったんPythonで実装し直してみてはどうだろうか。一度作ってみれば、Pythonでどういったツールを作成できるのかが実感を持ってわかるはずだ。

【参考資料】
The Python Tutorial