今まで知らなかったメソッド(expanduser)を見つけたのでその紹介を兼ねて小ネタの紹介です。
※注: Windowsでも動作する様に書いていますが、手元にWindowsのPython環境を持っていないのでこの記事の内容はWindowsでは未検証です。
今回の記事でやるのはタイトルの通り、ユーザーのホームディレクトリの取得です。
ホームディレクトリの下に作業ディレクトリやログディレクトリを作ってプログラムで使うと言う状況はそこそこある事だと思っています。書き捨てのスクリプトであればホームディレクトリのパスを直書きしてしまえばいいのですが、どこかに公開する場合や自分で使いまわしたい場合はそれでは不便が起きます。僕の場合でもAWS環境と、複数台のMacを使っているので、ホームディレクトリを直書きしてしまうと使い回しに修正が必要です。そのため、ホームディレクトリは自動的に取得することが望ましく、この記事のテクニックが必要になります。
いくつか方法があるので順番に紹介していきます。ちなみに、サンプルコードではユーザー名がyutaroだと仮定します。そのため結果として得られるホームディレクトリは ‘/Users/yutaro’ です。
環境変数を使う方法
一番簡単なのは環境変数から取得してしまうことですね。Mac/LinuxではHOME、WindowsではHOMEPATHやUSERPROFILEという環境変数に格納されています。次の様にするとどの環境でも動く様に書くことができます。orで繋いで最初に見つかったものを採用しているだけです。なお、絶対Windowsでは使わないよ、って場合はもうHOMEだけ見たら良いです。
import os
home_directory = (
os.environ.get('HOME') or
os.environ.get('HOMEPATH') or
os.environ.get('USERPROFILE')
)
print(home_directory)
# /Users/yutaro
上記の方法は特別なメソッドの知識とかいらないのですがご覧の通り記述量が多いので他の方法をつづいて紹介していきます。以降の方法の方がお勧めです。
osモジュールのメソッドを使う方法
(環境変数の取得もosモジュールでやってるので表題困りましたが、) osモジュールにはexpanduserという専用のメソッドを持っています。これは与えられたパスの先頭の ~ (チルダ) や ~user という文字列をホームディレクトリのパスに置換してくれるものです。
参考: os.path — 共通のパス名操作 — Python 3.11.4 ドキュメント
いくつか実験したのでコードを載せておきます。 ‘~user’って文字列でもいい様なことがドキュメントに書いてますが、これはuserじゃなくてOSのユーザー名を入れないといけない様です。環境ごとの記述の差異を吸収してほしいという今回の記事の主題的にはちょっとダメですね。素直に~だけ使いましょう。
# チルダをHOMEディレクトリに書き換えてくれる。
print(os.path.expanduser("~"))
# /Users/yutaro
# ドキュメントの ~user は ~userという文字列を指してるものではないらしく、~userはそのまま。
print(os.path.expanduser("~user"))
# ~user
# ~ユーザー名、僕の場合は ~yutaro は置換される。
print(os.path.expanduser("~yutaro"))
# /Users/yutaro
# ~の後ろにそのまま文字列が続いていたら置換されない。
print(os.path.expanduser("~work"))
# ~work
# ~の後ろに小ディレクトリを書いておくことができる。
print(os.path.expanduser("~/folder/subfolder"))
# /Users/yutaro/folder/subfolder
# ~が先頭でない場合は置換されない。
print(os.path.expanduser("/~/subfolder"))
# /~/subfolder
最後にpathlibって別のモジュールを使った方法もあるのでそれも紹介します。
pathlibモジュールを使った方法
こちらは、home()っていうズバリなメソッドを持ってます。
参考: pathlib — オブジェクト指向のファイルシステムパス — Python 3.11.4 ドキュメント
これが一番いいかな。(ネックは、pathlibの存在を忘れがちなことくらいか。)
from pathlib import Path
print(Path.home())
# /Users/yutaro
# 実はデータ型が違う
print(type(Path.home()))
# <class 'pathlib.PosixPath'>
print(type(os.path.expanduser("~")))
# <class 'str'>
内部的には、実質的に os.path.expanduser(“~”) と同等の処理をやってるみたいですね。ただし、上のサンプルコードの後半で見ている通り、Path.home()はPathオブジェクトを返してくれているので、その後のパス操作がより直感的になります。
話のついでにもう一つ紹介しておくと、 pathlibもexpanduserを持ってます。ただ、これは文字列を受け付けてくれないのでosのそれより使い勝手が悪いです。(個人の感想)
# Path.expanduser は文字列を受け付けないので例外が発生する。
try:
print(Path.expanduser("~"))
except Exception as e:
print(e)
# 'str' object has no attribute '_drv'
from pathlib import PosixPath
# PosixPath型に変換して使う
print(Path.expanduser(PosixPath(("~"))))
# /Users/yutaro
まとめ
以上で、Pythonでホームディレクトリを取得する方法をまとめてきました。ハードコーディングをやめてこれらの方法を使うとコードの使い回しがよりやりやすくなると思います。
個人的にはイチオシは pathlibの Path.home() ですかね。ただ自分でも忘れてosで環境変数取りに行くことが多そうですが。