ソース管理のため、名前空間とファイル構成の両面でプロジェクトの階層化をしたいと考えています。
ファイル構成:
hogepackage +- __init_.py +- foo.py +- bar.py
実現したい名前空間とクラスの構成:
namespace hogepackage +- <init module> +- class Foo +- class Bar
しかし、Pythonではパッケージ(フォルダ)とモジュール(__init__以外のファイル)がそれぞれ名前空間の階層となるので、ファイル構成をそのまま適用すると以下のように余計な名前空間ができてしまいます。
namespace hogepackage +- <init module> +- namespace foo | +- class Foo +- namespace bar +- class Bar
一般には__init__.pyの中でクラスをインポートすることで、利用側ではあたかもパッケージ直下にクラスがあるかのように見せかけることができますが、Pythonの型システム上では依然としてモジュール層が残っています。
hogepackage/__init__.py:
Python
1#!/usr/bin/env python3 2from .foo import Foo 3from .bar import Bar
>>> from hogepackage import Foo >>> type(Foo()) <class 'hogepackage.foo.Foo'>
これはリフレクション上の混乱を招きますし、sphinxのようなドキュメントツールもこの階層のままドキュメントを生成してしまいます。
一方、以下のようにすることで型システム上でも期待通りのクラス構成を実現できることが分かりました。
hogepackage/__init__.py:
python
1#!/usr/bin/env python3 2import sys 3import os 4import codecs 5 6dir = os.path.dirname(os.path.abspath(__file__)) 7with codecs.open(dir + '/foo.py', 'r', 'utf-8'): as file: 8 exec(''.join(file.readlines())) 9with codecs.open(dir + '/bar.py', 'r', 'utf-8'): as file: 10 exec(''.join(file.readlines()))
>>> from hogepackage import Foo >>> type(Foo()) <class 'hogepackage.Foo'>
ただ、これはあまりにも強引な解決法のように見えます。
もっとよい解決方法はないでしょうか?
どうするのがいいのかすぐ分かりませんが、例えばpandasのDataFrameは何もしてなかったりしますね。
>>> import pandas
>>> type(pandas.DataFrame())
pandas.core.frame.DataFrame
割と何もしないのが普通なんじゃと思い始めました。
>>> from sklearn.svm import SVC
>>> SVC
<class 'sklearn.svm.classes.SVC'>
sphinxはsphinx側でうまいこと設定できないのか・・・
確かにDataFrameなど参考になりますよね。C/C++のような一ファイル一クラスといった認識ではなく、一つのpy(foo/barなど)はnamespaceでまとめられた機能群と考えるのがPython流なのではないかと。(なので、解決方法というよりはそれに合った構成にすべきではという意図になります)
ただ、一ファイルが大きくなる傾向が出るので、質問されたように適切に分離したくなるかとは思いますが、その場合も機能毎に分割するようなリファクタリングをするのが良いのではないかと。
回答4件
あなたの回答
tips
プレビュー