Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ModuleNotFoundErrorの傾向と対策:仕組みから学ぶImport / Unpac...
Search
Toshifumi Tsutsumi
October 27, 2023
Programming
6.6k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ModuleNotFoundErrorの傾向と対策:仕組みから学ぶImport / Unpacking ModuleNotFoundError
PyCon APAC 2023 登壇資料
https://2023-apac.pycon.jp/timetable?id=9TKP3P
Toshifumi Tsutsumi
October 27, 2023
More Decks by Toshifumi Tsutsumi
See All by Toshifumi Tsutsumi
CDCデータパイプラインを止めないために / One Stream of the CDC
tosh2230
0
1.7k
ニアリアルタイム分析の実現に向けたChange Data Captureの導入 / Change data capture for near realtime analytics
tosh2230
3
2.5k
データリネージの組織導入事例と今後の戦略 / Introduction to an example of data lineage in GMO Pepabo
tosh2230
0
1.2k
SQLクエリ解析によるE2Eデータリネージの実現 / E2E-data-lineage
tosh2230
0
4.2k
データ抽出基盤 Yeti をつくっている話 / Yeti - Yet another Extract-Transfer Infrastructure
tosh2230
1
5.6k
Loggingモジュールではじめるログ出力入門 / Introduction to Python Logging
tosh2230
33
17k
データ基盤チームの設立と直近の取り組み / the-establishment-of-pepabo-data-platform-team
tosh2230
5
4.8k
Other Decks in Programming
See All in Programming
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
110
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
130
AI駆動開発勉強会 広島支部 第一回勉強会 AI駆動開発概要とワークショップ
hayatoshimiu
0
450
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
17
6.2k
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
230
AIエージェントの隔離技術の徹底比較
kawayu
0
470
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
1.8k
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.3k
A2UI という光を覗いてみる
satohjohn
1
110
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
150
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
180
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
240
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Optimizing for Happiness
mojombo
378
71k
Designing for Timeless Needs
cassininazir
1
250
How to Ace a Technical Interview
jacobian
281
24k
The Curious Case for Waylosing
cassininazir
1
380
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
Navigating Weather and Climate Data
rabernat
0
210
Principles of Awesome APIs and How to Build Them.
keavy
128
17k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
200
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Transcript
#pyconapac_5 ModuleNotFoundErrorの 傾向と対策 PyCon APAC 2023 2023-10-27(Day1) 仕組みから学ぶ Import
#pyconapac_5 堤 利史 Toshifumi Tsutsumi @tosh2230 Data Engineer GMO Pepabo,
inc. 風来のシレン 最新作を待ちわびています 2 自己紹介
#pyconapac_5 3 PyCon JP 2021 Loggingモジュールではじめるログ出力入門 / Introduction to Python
Logging
#pyconapac_5 4 PyCon JP 2022 SQLクエリ解析によるE2Eデータリネージの実現 / E2E-data-lineage
#pyconapac_5 このスライドは公開されています 5
#pyconapac_5 目的 🎯 6 ModuleNotFoundError の 解消にかける時間を減らすこと
#pyconapac_5 話すこと 😀 7 - ModuleNotFoundError - Import の仕組み(特に探す部分)
#pyconapac_5 話さないこと 😷 8 - Python 環境構築 - パッケージ管理ツール
#pyconapac_5 表記例 🖋 9 # これはコメント # 先頭が $ はコマンド
$ bash # 先頭が >>> は Python インタプリタ >>> import os # 先頭に何もなければ Python モジュールのコード import os
#pyconapac_5 1. Pythonのモジュールと ModuleNotFoundError 2. Importの役割 3. Importの仕組み 4. ModuleNotFoundErrorの
傾向と対策 10 Contents 📋
#pyconapac_5 1. Pythonのモジュールと ModuleNotFoundError 2. Importの役割 3. Importの仕組み 4. ModuleNotFoundErrorの
傾向と対策 11 Contents 📋
#pyconapac_5 12 ModuleNotFoundError: No module named 'foo'
#pyconapac_5 13 ModuleNotFoundError: No module named 'foo'
#pyconapac_5 14 そもそも モジュール とは?
#pyconapac_5 モジュールとは 15 - 定義や文をファイルに保存、再利用できるようにしたもの - 拡張子が .py のファイル -
Python コードの組織単位として機能する - モジュールに含まれるものの例 - 関数 - クラス - 変数
#pyconapac_5 - 複数のモジュールやサブパッケージを “ドット付きモジュール名”で構造化したもの - foo.bar は、 foo パッケージの モジュール
bar - 多くのパッケージが PyPI; Python Package Index で公開されている - パッケージには2種類ある。今回は前者を紹介 - Regular packages - Namespace packages パッケージとは 16
#pyconapac_5 Regular packages 17 - __init__.py を含む単一のディレクトリ - 読み込まれるときに __init__.py
が実行される - パッケージの初期化 - ディレクトリとパッケージが対応しているので わかりやすい
#pyconapac_5 Regular packages 18 $ tree ./greetings/friends -I __pycache__ ./greetings/friends
├── __init__.py ├── cat.py ├── dog.py └── human.py greetings friends cat dog human
#pyconapac_5 Import* 別のモジュールにある Python コードを 使えるようにすること モジュールは基本的に import して使う 19
* Import 文の解説は Python 言語リファレンス 7.11. The import statement を参照
#pyconapac_5 greetings friends # greetings.friends パッケージから # cat モジュールをインポート from
greetings.friends import cat Import の例 20 cat dog human # ./greetings/friends/cat.py class Cat: def __init__(self): self.phrase = "meow" ./greetings/friends ├── __init__.py ├── cat.py ├── dog.py └── human.py
#pyconapac_5 話は戻って ModuleNotFoundError 21 「import を試みます」 「モジュールを探しました」 「見つかりませんでした」 greetings friends
cat dog human ./greetings/friends ├── __init__.py ├── cat.py ├── dog.py └── human.py
#pyconapac_5 22 Import の 役割と仕組みが分かれば 原因を特定できるかも?
#pyconapac_5 1. Pythonのモジュールと ModuleNotFoundError 2. Importの役割 3. Importの仕組み 4. ModuleNotFoundErrorの
傾向と対策 23 Contents 📋
#pyconapac_5 Import の役割 24 > 別のモジュールにある Python コードを使えるようにすること 指定したモジュールを モジュールが存在する場所から
import を実行した名前空間へ追加する どこから 何を どこへ ✅
#pyconapac_5 Import の役割 25 > 別のモジュールにある Python コードを使えるようにすること 指定したモジュールを モジュールが存在する場所から
import を実行した 名前空間 へ追加する どこから 何を どこへ ✅ ?
#pyconapac_5 名前空間 26 - 変数や関数、クラス、モジュールの名前から オブジェクトへの対応関係を管理するもの - 各モジュールは専用の名前空間をもっているので 異なるモジュールに同じ名前の何かがあっても平気 >>>
from greetings.friends import cat >>> cat <module 'greetings.friends.cat' from '/foo/bar/greetings/friends/cat.py'>
#pyconapac_5 スコープ 27 変数や関数、クラスなどの名前が参照可能な範囲 from greetings.friends.cat import Cat global_cat =
Cat() def greet_cat_and_dog(): from greetings.friends.dog import Dog local_dog = Dog() local_cat = Cat() Global Local
#pyconapac_5 Import の役割 28 > 別のモジュールにある Python コードを使えるようにすること 指定したモジュールを モジュールが存在する場所から
import を実行した名前空間へ追加する どこから 何を どこへ ✅ ✅
#pyconapac_5 Import の役割 29 > 別のモジュールにある Python コードを使えるようにすること 指定したモジュールを モジュールが
存在する場所 から import を実行した名前空間へ追加する どこから 何を どこへ ? ✅ ✅
#pyconapac_5 1. Pythonのモジュールと ModuleNotFoundError 2. Importの役割 3. Importの仕組み 4. ModuleNotFoundErrorの
傾向と対策 30 Contents 📋
#pyconapac_5 31 同名で Import 済みの モジュールオブジェクトはあるか? 再利用 モジュールを探索 ModuleSpec はあるか?
ModuleSpec に書かれた Loader を起動 ModuleNotFoundError Import の仕組み - ModuleNotFoundError まで -
#pyconapac_5 32 同名で Import 済みの モジュールオブジェクトはあるか? 再利用 モジュールを探索 ModuleSpec はあるか?
ModuleSpec に書かれた Loader を起動 ModuleNotFoundError Import の仕組み - ModuleNotFoundError まで -
#pyconapac_5 sys.modules 33 - インポート済み モジュールオブジェクトのリスト - どの名前空間にインポートしていても再利用可能 >>> import
sys >>> sys.modules { 'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, … }
#pyconapac_5 34 同名で Import 済みの モジュールオブジェクトはあるか? 再利用 モジュールを探索 ModuleSpec はあるか?
ModuleSpec に書かれた Loader を起動 ModuleNotFoundError Import の仕組み - ModuleNotFoundError まで -
#pyconapac_5 ModuleSpec* 35 モジュールの仕様に関する情報を扱うクラス - モジュールがある場所 - ロード方法の指定(loader) - 親モジュール・子モジュールの有無
など * PEP 451 – A ModuleSpec Type for the Import System
#pyconapac_5 1. Pythonインタプリタに組み込まれているビルトインモジュールが対象。 sys.builtin_module_names で確認可 2. フリーズされているモジュールが対象(フリーズ: Python スクリプトをバイナリフォーマット に変換して、Python
なしに直接実行できる形に変換すること) ModuleSpec の探索 sys.meta_path に設定されている Importer/Finder が探索。 主要なのは下記の3つ - BuiltinImporter1 - FlozenImporter2 - PathFinder → ModuleNotFoundError が起きやすい 36
#pyconapac_5 PathFinder 37 下記パッケージやそれに含まれる .py/.pyc* ファイルを 対象として探索 - Python にプリインストールされているパッケージ
- Python 環境にインストールしたパッケージ - 自作パッケージ * .py ファイルから生成されるバイトコードファイル 読み込みを高速化する目的で Import のタイミングで生成される
#pyconapac_5 sys.path 38 PathFinder が探しに行くディレクトリのリスト 下記の数字順に探す 1. 実行したスクリプトがあるディレクトリ (指定されなかった場合はカレントディレクトリ) 2.
PYTHONPATH 環境変数に設定されているディレクトリ 3. Python がデフォルトで検索するディレクトリ - Python のインストール方法によって異なる - site-packages ディレクトリとするのが慣例
#pyconapac_5 PathFinder で ModuleSpec を探す 39 >>> from _frozen_importlib_external import
PathFinder >>> spec = PathFinder.find_spec("greetings") # 見つからなかった場合は None が戻る >>> spec ModuleSpec( name='greetings', loader=<_frozen_importlib_external.SourceFileLoader object at 0x104eb0310>, origin='/foo/bar/greetings/__init__.py', submodule_search_locations=['/foo/bar/greetings'] )
#pyconapac_5 40 同名で Import 済みの モジュールオブジェクトはあるか? 再利用 モジュールを探索 ModuleSpec はあるか?
ModuleSpec に書かれた Loader を起動 ModuleNotFoundError Import の仕組み - ModuleNotFoundError まで -
#pyconapac_5 Import の役割 41 > 別のモジュールにある Python コードを使えるようにすること 指定したモジュールを モジュールが存在する場所から
import を実行した名前空間へ追加する どこから 何を どこへ ✅ ✅ ✅
#pyconapac_5 1. Pythonのモジュールと ModuleNotFoundError 2. Importの役割 3. Importの仕組み 4. ModuleNotFoundErrorの
傾向と対策 42 Contents 📋
#pyconapac_5 よくある原因 43 分類 原因 モジュールがない 1. 異なる仮想環境を起動している 2. パッケージのインストールを忘れている
モジュールはあるが 見つけられない 3. モジュール名を typo している 4. 同名のパッケージとモジュールがある 5. 自作パッケージが認識されていない 6. Python から見えないところにある
#pyconapac_5 分類 原因 モジュールがない 1. 異なる仮想環境を起動している 2. パッケージのインストールを忘れている モジュールはあるが 見つけられない
3. モジュール名を typo している 4. 同名のパッケージとモジュールがある 5. 自作パッケージが認識されていない 6. Python から見えないところにある よくある原因 44 実装を 見直す 環境を 見直す 起動方法を 見直す
#pyconapac_5 原因1. 異なる仮想環境を起動している 45 対策: 起動している環境が期待どおりか確認する 環境を見直す # 仮想環境のディレクトリ >>>
sys.prefix '/Users/tosh2230/Library/Caches/pypoetry/virtualenvs/unpacking -module-not-found-error-tiYZ59tI-py3.11' # 仮想環境の元となった Python のインストール先 >>> sys.base_prefix '/opt/homebrew/opt/
[email protected]
/Frameworks/Python.framework/ Versions/3.11'
#pyconapac_5 原因2. パッケージのインストールを忘れている 46 対策: パッケージの一覧を確認して、なければインストールする 環境を見直す # インストールパッケージ一覧を表示 $
pip list # カレントディレクトリから参照できるモジュールやパッケージの一覧 # モジュールを Import する前にも使える >>> help(‘modules’)
#pyconapac_5 原因3. モジュール名を typo している 47 対策: 1. IDE に誤りを指摘してもらう
2. モジュールの有無を確認する linter でチェックする - pylint - mypy など 環境を見直す 実装を見直す
#pyconapac_5 原因4. 同名のパッケージとモジュールがある 48 判別方法: 1. 標準モジュールやインストールしたパッケージと 同じ名称のモジュールはないか? → 同名の場合は自作モジュールが優先される
2. 自作パッケージと同じ名称のファイルはないか? 対策: モジュールの命名を再検討する → モジュールの役割を十分に考慮すると、名前は意外と被らない 実装を見直す
#pyconapac_5 原因5. 自作パッケージが認識されていない 49 判別方法: Import 可能なパッケージの一覧を確認する 対策: Regular package
がおすすめ。__init__.py を配置する 実装を見直す # カレントディレクトリから参照できるモジュール(パッケージ含む)の一覧 >>> help(‘modules’) # パッケージ名を指定すると、属するモジュールやサブパッケージを表示 >>> help(‘modules greetings.friends’)
#pyconapac_5 原因6. Python から見えないところにある 50 判別方法: 期待したパスが sys.path にセットされているか確認する$ python
foo/bar.py 対策: 1. PYTHONPATH 環境変数の使用を検討する 2. 設計・実装段階で起動方法を考慮に入れる → どのように起動するかで sys.path の先頭に入る値は変わる - スクリプトを起動 - モジュールをスクリプトとして起動 起動方法を 見直す >>> sys.path
#pyconapac_5 起動方法1: スクリプト 51 引数で指定したものを main モジュール* として実行する 指定可能なものは下記の3つ -
Python ファイル - __main__.py を含むディレクトリ - __main__.py を含む zip ファイル $ python foo/bar.py * __name__ に ‘__main__’ が設定されたスクリプト環境のこと。 Python 標準ライブラリ __main__ トップレベルのスクリプト環境 を参照 sys.path の先頭には 指定したファイルを含むディレクトリ がセットされる
#pyconapac_5 52 指定されたモジュールを探して、その内容を main モジュールとして実行 指定されたのがパッケージなら、そのパッケージの __main__.py を実行 sys.path の先頭には
カレントディレクトリ がセットされる # 指定するのはファイルではなく モジュール名 $ python -m foo.bar 起動方法2: モジュール* * PEP 338 – Executing modules as scripts
#pyconapac_5 Python インタプリタで import を再現してみよう 53 # ModuleSpec を探す >>>
from _frozen_importlib_external import PathFinder >>> src_spec = PathFinder.find_spec("src") >>> greetings_spec = PathFinder.find_spec("src.greetings", src_spec.submodule_search_locations, None) # モジュールをロード >>> from importlib.util import module_from_spec >>> greetings = module_from_spec(greetings_spec) >>> greetings_loader = greetings_spec.loader >>> greetings_loader.exec_module(greetings) # モジュール内の関数を実行 >>> greetings.greet_all()
#pyconapac_5 54 まとめ
#pyconapac_5 Import の役割 55 > 別のモジュールにある Python コードを使えるようにすること 指定したモジュールを モジュールが存在する場所から
import を実行した名前空間へ追加する どこから 何を どこへ ✅ ✅ ✅
#pyconapac_5 56 同名で Import 済みの モジュールオブジェクトはあるか? 再利用 モジュールを探索 ModuleSpec はあるか?
ModuleSpec に書かれた Loader を起動 ModuleNotFoundError Import の仕組み - ModuleNotFoundError まで -
#pyconapac_5 分類 原因 モジュールがない 1. 異なる仮想環境を起動している 2. パッケージのインストールを忘れている モジュールはあるが 見つけられない
3. モジュール名を typo している 4. 同名のパッケージとモジュールがある 5. 自作パッケージが認識されていない 6. Python から見えないところにある よくある原因 57 実装を 見直す 環境を 見直す 起動方法を 見直す
#pyconapac_5 ドキュメント紹介 58 Python チュートリアル 6. モジュール モジュールとパッケージの解説 Python チュートリアル
9.2. Python のスコープと名前空間 名前空間とスコープの解説 Python 標準ライブラリ importlib Approximating importlib.import_module() Import が主にやっていることを Python コードで示している Python 言語リファレンス 5. インポートシステム Import の詳細な仕様解説
#pyconapac_5 59 Thank you ! https://github.com/tosh2230/pycon-apac-2023