Pythonのos.path.joinの仕様にちょっとハマった
Pythonでパスを結合しようと思って、こんな感じでコードを書いていたのですが、どうにも思った通りに動かない…
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from os.path import join >>> a = 'a' >>> b = '/b' >>> print(join(a, b)) /b
なんでa
は結合されないのだろー、と悩みました。
で、実際にPythonのos.py(厳密にはos.pathはposixpath.py)を見ると、以下のようなコードでした。 (必要な箇所のみ抜粋)
import os def get_sep(path): if isinstance(path, bytes): return b'/' else: return '/' def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components will be discarded. An empty last part will result in a path that ends with a separator.""" a = os.fspath(a) sep = get_sep(a) path = a try: if not p: path[:0] + sep #23780: Ensure compatible data type even if p is null. for b in map(os.fspath, p): if b.startswith(sep): path = b elif not path or path.endswith(sep): path += b else: path += sep + b except (TypeError, AttributeError, BytesWarning): genericpath._check_arg_types('join', a, *p) raise return path
細かく読むと if b.startswith(sep)
で、セパレータ(posixでは/
)で始まっていると先頭は無視する模様….
確かにdocstringにも書いているが、この仕様はなんなのだろうか...
ちなみにPythonのドキュメントにもちゃんと書いていましたね。
11.2. os.path — 共通のパス名操作 — Python 3.6.5 ドキュメント
そして、Pythonをもう数年書いているのに知らない自分もちょっと情けないですが...