以下のコードは、デバッグ時にパス全体を格納するのではなく、最後のエントリだけを格納するため、参加しません。
os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/')
これをテストすると、コードの/new_sandbox/
部分だけが格納されます。
後者の文字列はスラッシュで始めるべきではありません。それらがスラッシュで始まっているなら、それらは「絶対パス」と考えられ、それらの前のすべては捨てられます。
コンポーネントが絶対パスの場合、以前のすべてのコンポーネントは破棄され、結合は絶対パスコンポーネントから続行されます。
Windowsでは、ドライブ文字に関連した動作が以前のPythonバージョンと比べて変更されているように思われることに注意してください。
Windowsでは、絶対パスコンポーネント(例:
r'\foo'
)が検出されてもドライブ文字はリセットされません。コンポーネントにドライブ文字が含まれていると、それ以前のすべてのコンポーネントは破棄され、ドライブ文字はリセットされます。各ドライブには現在のディレクトリがあるため、os.path.join("c:", "foo")
はC:
ではなくドライブc:foo
(c:\foo
)上の現在のディレクトリからの相対パスを表します。
os.path.join()
のアイデアはあなたのプログラムをクロスプラットフォーム(linux/windows/etc)にすることです。
スラッシュが1つでもそれを台無しにします。
そのため、os.environ['HOME']
やos.path.dirname(__file__)
のようなある種の参照ポイントと一緒に使用されている場合にのみ意味があります。
os.path.join()
をos.path.sep
と組み合わせて使用すると、相対パスではなく絶対パスを作成できます。
os.path.join(os.path.sep, 'home','build','test','sandboxes',todaystr,'new_sandbox')
ルートディレクトリを参照する場合を除き、パスコンポーネントの先頭にスラッシュを使用しないでください。
os.path.join('/home/build/test/sandboxes', todaystr, 'new_sandbox')
http://docs.python.org/library/os.path.html#os.path.join もご覧ください。
この驚くべき振る舞いが完全にそれほどひどいものではない理由を理解するのを助けるために、引数として設定ファイル名を受け入れるアプリケーションを考えてください:
config_root = "/etc/myapp.conf/"
file_name = os.path.join(config_root, sys.argv[1])
アプリケーションを次のように実行した場合
$ myapp foo.conf
設定ファイル/etc/myapp.conf/foo.conf
が使用されます。
しかし、アプリケーションが次のように呼び出された場合にどうなるかを考えてください。
$ myapp /some/path/bar.conf
それならmyapp
は/some/path/bar.conf
の設定ファイルを使うべきです(そして/etc/myapp.conf/some/path/bar.conf
のようなものではありません)。
それは素晴らしいことではないかもしれませんが、これが絶対パスの振る舞いの動機であると思います。
それはあなたの'/new_sandbox/'
が/
で始まっているので、ルートディレクトリからの相対パスであると仮定されているからです。先頭の/
を削除してください。
あなたの機能をよりポータブルにするために、それを次のように使用してください。
os.path.join(os.sep, 'home', 'build', 'test', 'sandboxes', todaystr, 'new_sandbox')
または
os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, 'new_sandbox')
既存の結合を持つ文字列に対してsplit("/")
と*
のコンボを試してください。
import os
home = '/home/build/test/sandboxes/'
todaystr = '042118'
new = '/new_sandbox/'
os.path.join(*home.split("/"), todaystr, *new.split("/"))
どのように動作しますか?
split("/")
は既存のパスをリストに変えます:['', 'home', 'build', 'test', 'sandboxes', '']
リストの前にある*
は、リストの各項目をそれ自身のパラメータから取り出します。
new_sandbox
のみで試してください
os.path.join('/home/build/test/sandboxes/', todaystr, 'new_sandbox')
余分なスラッシュもなく、このようにしてください。
root="/home"
os.path.join(root,"build","test","sandboxes",todaystr,"new_sandbox")
os.path.join()
を使用してすでにドットを含む拡張子を含めると、同様の問題が発生する可能性があります。これは、os.path.splitext()
を使用すると自動的に発生します。この例では:
components = os.path.splitext(filename)
prefix = components[0]
extension = components[1]
return os.path.join("avatars", instance.username, prefix, extension)
extension
は.jpg
かもしれませんが、 "foobar.jpg"という名前のファイルではなく "foobar"という名前のフォルダになってしまいます。これを防ぐには、拡張子を別に追加する必要があります。
return os.path.join("avatars", instance.username, prefix) + extension