1. ホーム
  2. パイソン

[解決済み】周期的インポートを使用しないPythonのタイプヒンティング

2022-04-08 14:45:19

質問

巨大なクラスを2つに分割しようとしているのですが、基本的には "main" クラスと、追加機能を持つミキシンに、以下のように分割します。

main.py ファイルを作成します。

import mymixin.py

class Main(object, MyMixin):
    def func1(self, xxx):
        ...

mymixin.py ファイルを作成します。

class MyMixin(object):
    def func2(self: Main, xxx):  # <--- note the type hint
        ...

さて、これは問題なく動作しますが、型ヒントの MyMixin.func2 もちろん、うまくいくはずがない。私は main.py なぜなら、循環的なインポートが発生し、ヒントがなければ、私のエディタ(PyCharm)は何をするのか分からないからです。 self があります。

私はPython 3.4を使っていますが、もしそこで解決策が得られるなら3.5に移行しても構いません。

クラスを2つのファイルに分割して、すべての "connection" を維持し、IDE が自動補完や型を知ることによって得られる他のすべての利点を提供できる方法はありますか?

どのように解決するのですか?

一般的にインポートサイクルを処理するための非常にエレガントな方法はありません、私は怖いです。あなたの選択肢は、周期的な依存関係を取り除くためにコードを再設計するか、それが実行可能でない場合は、次のようなことを行うことです。

# some_file.py

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    def func2(self, some_param: 'Main'):
        ...

TYPE_CHECKING 定数は常に False は実行時に評価されませんが、mypy(や他の型チェックツール)はそのブロックの中身を評価します。

また Main 型アノテーションを文字列にすることで、事実上の前方宣言を行います。 Main シンボルは実行時に利用できない。

Python 3.7+を使用している場合、少なくとも明示的な文字列アノテーションを提供する必要はありません。 PEP 563 :

# some_file.py

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    # Hooray, cleaner annotations!
    def func2(self, some_param: Main):
        ...

from __future__ import annotations インポートすると すべて の型ヒントは文字列であり、その評価はスキップされます。これによって、ここでのコードが多少なりとも人間工学的になる。

とはいえ、mypyでmixinを使うには、現在持っているものよりもう少し構造が必要になりそうです。mypy は、次のようなアプローチを推奨しています。 というのは、基本的に deceze が説明しているのは、ABCを作成することで、あなたの MainMyMixin クラスが継承します。Pycharmのチェッカーを満足させるために、同じようなことをする必要があったとしても、私は驚かないでしょう。