Python 絶対パスと相対パス

Python学習【365日チャレンジ!】67日目のマスターU(@Udemy11)です。

ナポレオンや明石家さんまさんは、3時間の睡眠で大丈夫らしいですが、やっぱりわたしは少なくとも5時間は睡眠時間を取らないと日中眠くてたまらなくなります。

非常に少ない睡眠時間で日中も元気に活動できる人はショートスリーパーというらしいですが、時間を有効に活用できていいな〜と思う反面、ぐっすりと寝られる幸せを知らないのは嫌だな〜とも思っちゃいます。

太っている人からすると羨ましがられる痩せた人も太っている人を羨ましく思っているかもしれないし、太った人を羨ましく思っている痩せた人もいるかもしれません。

ま〜人それぞれなんでしょうね。

それでは、今日もPython学習をはじめていきましょう!

昨日の復習

昨日は、importasを使ったモジュールの使い方を学習しました。

importで実行するPythonファイルと同じ階層に作ったフォルダの中のモジュール(Pythonファイル)から関数を読み込むことができ、fromasを使って、読み込む実行関数の名称を短縮することができました。

フォルダ階層

session ┳ lesson.py
     ┗ lesson_package ┳ utils.py
                   ┗ __int__.py

lesson_package > utils.py

def say_something(word):
    return (word + '!') * 2

lesson.py

import lesson_package.utils
from lesson_package import utils
from lesson_package.utils import say_something #あまり使ってはいけない
import lesson_package.utils as ut #あまりおすすめできない

r = lesson_package.utils.say_something('Hello')
print(r)

r = utils.say_something('Hi')
print(r)

r = say_something('Good morning')
print(r)

r = ut.say_something('Good bye')
print(r)

lesson.py出力結果

Hello!Hello!
Hi!Hi!
Good morning!Good morning!
Good bye!Good bye!

1行目のimportだけを使った読み込みであれば、6行目のように同じ階層のフォルダlesson_packageから関数名を記述する必要がありました。

2行目のようにfromを使ってモジュールを指定すれば、9行目の関数の実行にはフォルダ名の省略ができ、さらに3行目のように、モジュール内の関数を指定すれば、12行目のようにモジュール名も省略することができました。

ただし、モジュールをimportしているのに、関数名だけの記述になると、どのモジュールの関数なのかわからなくなるので、あまり使用してはいけないとのことでした。

また、4行目のようにasを使って、15行目の関数実行ではimportするモジュール名を短縮することが可能ですが、この方法も関数がどのモジュールのものなのかわかりにくいので、あまりおすすめできませんでした。

さらに詳しいことは機能の記事にまとめています。

それでは、本日のPython学習、絶対パスと相対パスにはいっていきましょう!

絶対パス

絶対パスは、階層化されたパッケージの中で、最上位層から目的のモジュールまでのパスで、どの階層にからでも確実に目的のモジュールにたどり着くことができます。

絶対パスという名のとおり、絶対変わることのないパスで、深い階層に目的のモジュールがある場合はコード表記が長くなります。

相対パス

一方、相対パスは、階層化されたパッケージの中のモジュールから目的のモジュールまでのパスで、一つ下の階層とか一つ上の階層という指定をすることで、目的のモジュールにたどり着けます。

相対的に参照するため、モジュールの階層位置によりパスの書き方が変わるかわり、コード表記が長くなる絶対パスとは違い、コードの表記が短くてすみます。

深い階層のファイルを参照

絶対パス、相対パスを理解したところで、昨日学習したパッケージに、さらに深い階層を作って、絶対パスでモジュールを読み込んでみます。

フォルダ階層

session ┳ lesson.py
        ┗ lesson_package ━ text_box ┳ __int__.py
                                      ┗ emotion.py

lesson_package > text_box > emotion.py

def laugh():
    return 'laugh'

lesson.py

from lesson_package.text_box import emotion

l = emotion.laugh()
print(l)

lesson.py出力結果

laugh

同じ階層のフォルダの中のutils.pyを参照するときは、import lesson_package import utilsと書きましたが、さらに下の階層のフォルダtextを参照するときは、.(ピリオド)でつなげるだけです。

上位階層を参照する

通常、下位の階層から上位階層のモジュールを参照する場合は、通常絶対パスで参照しますが、..ピリオド2つをつなげて上位階層を相対パスで参照することもできます。

ただ、相対パスの場合、どこを参照しているのか分かりづらいので、Pythonではあまり推奨されていません。

フォルダ階層

session ┳ lesson.py
        ┗ lesson_package ┳ __int__.py
                          ┣ utils.py
                          ┗ text_box ┳ __int__.py
                                      ┗ emotion.py

lesson_package > text_box > emotion.py

from .. import utils #本来なら、from lesson_package import utilsと記述

def laugh():
    return 'laugh'

def say_hey():
    return utils.say_words('Hey')

lesson_package > utils.py

def say_words(word):
    return (word + '!') * 2

lesson.py

from lesson_package.text_box import emotion

print(emotion.laugh())

print(emotion.say_hey())

lesson.py出力結果

laugh
Hey!Hey!

lesson.pyは、最下位層にあるemotion.pyだけをimportしています。

そのemotion.pyは、一つ上の階層にあるutils.pyを参照して、関数say_heyの返り値をutils.pyで定義しているsay_wordsにして引数Heyを渡しています。

本来なら、こんなややこしい参照はしないと思うので、参照が複雑になりちょっとややこしいかもしれませんが、モジュールは上からでも下からでも参照できるし、他のモジュールを参照しているモジュールを読み込んで元のモジュールの関数を活用することもできます。

どんどん複雑に

例として、簡単な使い方を紹介してくれているのですが、具体的にどのように使うかはまだ先のような感じです。

酒井さんの講座では、Pycharmを使っているので、Pythonistaに比べると高性能な感じがしないでもありませんが、iPhoneやiPadでPythonistaでPythonを学ぶ人は、これからどんどんと増えていくんだと思います。

実は、今回importでかなりハマってしまったことがあります。

Pythonistaの仕様なのか、パッケージごと複製したPythonファイルの下位層にあるモジュールの名前を変更したら、特定の名前だけエラーが起こったんです。

他の名前にしたり、_(アンダースコア)をつけてみたりしているときちんと処理されるのですが、どうもフォルダ名をtalkという名前にするとエラーになるんですよね。

そんなはずはないと思いながらも、どうあがいてもtalkにするとエラーが起こるので、【これはバグか?】なんて思っていたのですが、普通にアプリを終了して再起動したら、すんなり動くようになりました。

かなり時間を食われてしまいましたが、ほんのちょっとしたことでエラーが起こるということを再認識した出来事でした。

ということで、明日も元気にGood Python!