相対インポート、便利やで?

     Pythonでモジュールをインポートするにはimport文を使用します。

    # hoge.pyをインポートする。
    import hoge

     これはモジュールであってもパッケージであっても関係ありませんね。
     さて、今度はモジュールをパッケージ化して、複数ファイルを管理することにします。
     今回のサンプルとしてはこんな感じ。

    hoge
        |_  __init__.py
        |_  fuga.py
        |_  piyo.py
    
     このパッケージの中からfuga.pyをインポートしたい場合は以下のように書きます。
    from hoge import fuga
    
    #または
    import hoge.fuga as fuga
    

     どちらでも問題ないのですが、自分はGoogle先生のコーディングルールに則って上の方で書いていきます。
     ここまでも基本的な構文なので、普通にPythonをやっていけば問題ないでしょう。

     さて、今度はfuga.py内でpiyo.pyをインポートする場合を考えます。
     普通に考えれば上記の書き方で問題ないのですが、この場合モジュールのトップであるhogeの名前を変えると、各モジュール内でもimportで使用されているhogeと言う文字を変更しなくてはいけません。

    hoge
        |_  __init__.py
        |_  fuga.py
        |_  piyo.py
    
    # hoge/fuga.py
    
    from hoge import piyo
    


    ↓パッケージ名を変更しなくてはいけなくなった!!


    hogehoge
        |_  __init__.py
        |_  fuga.py
        |_  piyo.py
    
    # hogehoge/fuga.py
    
    from hogehoge import piyo
    # ↑トップのパッケージ名が変わったので、参照しているコード内でも変更しないといけない!!
    

     まだ2,3個くらいのモジュールで形成されているパッケージならいいのですが、これが10個、20個となってくると修正がかなり大変になりますね。
     そこで出て来るのが相対インポートです!!


    ■相対インポート
     相対インポートとは、読み込むモジュールを基準とした階層で読み込む方法なのです!
     ↑の例でいくと
    # hoge/fuga.py
    
    import piyo
    # ↑ fugaと同階層のhoge/piyo.pyがインポートされる
     となり、もしトップモジュールのhogeが変更されても、コードは修正しなくて良いのです!!
     これは便利やね!!

     ・・・と言いたいところなのですが、この場合ちょっと紛らわしいケースが発生します。
     例えば↓みたいな感じの構造だった場合
    hogehoge
        |_  __init__.py
        |_  fuga.py
        |_  piyo.py
    piyo.py
     これだとpiyo.pyはどっちのヤツを読んでるのか分かりづらいですし、トラブルの元になりやすいです。
     って事で、こう言う書き方の相対インポートは推奨致しませんし、されておりません。
     ではどうするか!!?


    ■明示的な相対インポート
     明示的? なにそれ美味しいの?

     その通り!もちろん旨味たっぷりですよ!!!
     明示的インポート、説明は後でするとしてとりあえず書いてみましょう!
    # hogehoge/fuga.py
    
    from . import piyo
    # ↑ fugaと同階層のhoge/piyo.pyがインポートされる
     何か慣れないとムズムズする書き方ですね(; ・`ω・´)
     この場合、fromの後に続く「.」はhoge/huga.pyの親階層・・・つまりhogeを指しています。
     なのでこの場合はhogeのpiyo.pyがインポートされる事になるのです!!
     このようにどこの階層からスタートしているのかを明示的に示しているので、明示的な相対インポートと呼んでおります。


     因みに、この場合「.」や親を指しています。
     なので↓のような場合
    hoge
        |_  hogehoge
                |_  __init__.py
                |_  age.py
        |_  __init__.py
        |_  fuga.py
        |_  piyo.py
    piyo.py
     これのage.py内でpiyo.pyを読みたい場合は
    # hoge/hogehoge/age.py
    
    from .. import piyo
    # ↑ age.pyの1階層上のpiyo.pyがインポートされる
     となります。


    ■暗黙の相対インポートと絶対インポート
     上記のように「from . 」から始まるインポート方法を明示的な相対インポートと呼び、最初の例で示したような相対インポートを暗黙の相対インポートと呼ぶそうです。
     因みに 黙の相対インポートはPython3から廃止されたので、絶対にやってはいけません!!←ここ非常に重要

     また、フルパスでちゃんと書くタイプ「from hoge.hogehoge import age」のようなタイプを絶対インポートと呼びます。


    ■使いすぎは程々に・・・
     相対インポートはパッケージ名が変わった時に、各モジュール内のimport文を変更しなくていいので、改変があった時には非常に便利です。(例えばABCってパッケージが大幅アップデートするのでABC2になるとか)
     ただし、あんまりやり過ぎると後で読み直す時に大変になるので、ほどほどにしましょう。
     Googleのコーディングガイドなんかでも、メンテナンス時の可読性を考慮して、基本的には絶対インポートを推奨しています。

     また、明示的な相対インポートは、あくまで同一パッケージ内での使用を推奨しています。
     他のパッケージのものをインポートする場合は、絶対インポートにしましょう。
    (まぁ、そもそも他パッケージを相対で読む意味がないんですが・・・)
    スポンサーサイト

    コメントの投稿

    非公開コメント

    プロフィール

    Eske

    Author:Eske
    萌えイラストレーターを目指す3DCGイラストレーター。
    現在ポケモンカードゲーム、ガンダムトライエイジ、ガンダムコンクエスト、妖怪ウォッチとりつきカードゲームなどで3DCGを使用したイラストレーターとして参加中。

    主にここでは日々気づいたメモなんかを残してます。
    イラストのお仕事も受け付けております。ココのメールアドレスからご連絡できますので、お気軽にご相談下さい。

    最新記事
    最新コメント
    カテゴリ
    最新トラックバック
    月別アーカイブ
    検索フォーム
    リンク
    QRコード
    QR