[解決済み】メソッドの型ヒントは、どのようにエンクロージャクラスの型を使用するのですか?
質問
Python 3で以下のようなコードを書いています。
class Position:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def __add__(self, other: Position) -> Position:
return Position(self.x + other.x, self.y + other.y)
しかし、私のエディタ (PyCharm) では、参照先である
Position
は解決できません。
__add__
メソッド) を使用します。の型であることを期待することをどのように指定すればよいのでしょうか?
Position
?
編集部:これは実はPyCharmの問題だと思います。実際に警告やコード補完にその情報を使っています。
しかし、私が間違っていて、他の構文を使用する必要がある場合は、訂正してください。
どのように解決するのですか?
TL;DR
: 本日(2019年)現在、Python 3.7+では、"future"ステートメントを使用してこの機能をオンにする必要があります。
from __future__ import annotations
.
(で有効な動作)。
from __future__ import annotations
かもしれない
は将来のバージョンのPythonではデフォルトになり
は行っていた
は、Python 3.10でデフォルトになる予定でした。しかし、3.10での変更点である
は元に戻された
というのも、最後の最後で、全く実現しないかもしれないからです)。
Python 3.6以下では、文字列を使用する必要があります。
この例外が発生したのでしょう。
NameError: name 'Position' is not defined
これは、以下の理由からです。
Position
を使用している場合を除き、アノテーションの中で使用する前に定義する必要があります。
PEP 563
の変更を有効にします。
Python 3.7+の場合。
from __future__ import annotations
Python 3.7 の紹介
PEP 563:アノテーションの評価の延期
. futureステートメントを使用するモジュールは
from __future__ import annotations
は、アノテーションを自動的に文字列として格納します。
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
Python 3.10でデフォルトになる予定でしたが、この変更は現在延期されています。Pythonはまだ動的型付け言語であり、実行時に型チェックは行われないので、型付けアノテーションはパフォーマンスに影響を与えないはずですよね?そうではありません。Python 3.7 以前では、 typing モジュールは
コアで最も遅いPythonモジュールの一つです。
そこで
をインポートするようなコードでは
typing
モジュールでは
最大7倍のパフォーマンスアップ
3.7にアップグレードした場合
Python <3.7: 文字列を使用する
PEP 484によると の場合、クラス自体の代わりに文字列を使用する必要があります。
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
Django フレームワークを使用している場合、これは馴染みがあるかもしれません。Django のモデルも前方参照 (外部キー定義で、外部モデルが
self
またはまだ宣言されていない)。これはPycharmなどでも動作するはずです。
ソース
PEP484とPEP563の関連部分です。
<ブロッククオート前方参照
タイプヒントがまだ定義されていない名前を含んでいる場合、その定義は文字列リテラルとして表現され、後で解決されることがあります。
このような状況がよく起こるのは、コンテナ・クラスの定義で、いくつかのメソッドのシグネチャに定義されているクラスが登場する場合です。例えば、以下のコード(単純なバイナリツリー実装の開始点)は動作しない。
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
これに対応するために、次のように書きます。
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
文字列リテラルは有効な Python 式を含み (すなわち compile(lit, '', 'eval') は有効なコードオブジェクトでなければなりません)、モジュールが完全にロードされた後はエラーなしで評価されなければなりません。評価されるローカルおよびグローバルの名前空間は、同じ関数へのデフォルトの引数が評価されるのと同じ名前空間でなければなりません。
とPEP563に記載されています。
実装
Python 3.10では、関数と変数のアノテーションは定義時に評価されなくなりました。その代わり、文字列の形式がそれぞれの
__annotations__
辞書を使用します。静的なタイプチェッカーでは動作に違いはありませんが、実行時にアノテーションを使用するツールでは、評価を先延ばしにする必要があります。...
Python 3.7で未来の動作を有効にする
Python 3.7から、以下の特別なインポートを使って、上記の機能を有効にすることができます。
from __future__ import annotations
代わりにやりたくなるようなこと
A. ダミーを定義する
Position
クラス定義の前に、ダミー定義を配置します。
class Position(object):
pass
class Position(object):
...
これで
NameError
で、見た目もOKかもしれません。
>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}
しかし、そうでしょうか?
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: False
other is Position: False
B. アノテーションを追加するためにモンキーパッチする。
Pythonのメタプログラミングのマジックを試して、デコレーターを書きたいかもしれません。 を使用して、アノテーションを追加するためにクラス定義を猿真似しています。
class Position:
...
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
デコレーターはこれに相当する部分を担当する必要があります。
Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position
少なくとも正しいような気がします。
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: True
other is Position: True
たぶん、面倒なんでしょうね。
関連
-
Python 可視化 big_screen ライブラリ サンプル 詳細
-
Evidentlyを用いたPythonデータマイニングによる機械学習モデルダッシュボードの作成
-
[解決済み】TypeErrorを取得しました。エントリを持つ子テーブルの後に親テーブルを追加しようとすると、 __init__() missing 1 required positional argument: 'on_delete'
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] リストの最後の要素を取得する方法
-
[解決済み] pipでPythonの全パッケージをアップグレードする方法
-
[解決済み] オブジェクトの種類を決定しますか?
-
[解決済み] インスタンスのクラス名を取得する?
-
[解決済み] 億の相対的輸入
-
[解決済み】指定された型のコレクションをタイプヒンティングする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Pythonの非常に便利な2つのデコレーターを解説
-
Python 人工知能 人間学習 描画 機械学習モデル作成
-
Python カメの描画コマンドとその例
-
Python機械学習Githubが8.9Kstarsに達したモデルインタープリタLIME
-
Python入門 openを使ったファイルの読み書きの方法
-
風力制御におけるKS原理を深く理解するためのpythonアルゴリズム
-
[解決済み】ImportError: sklearn.cross_validation という名前のモジュールがない。
-
[解決済み】Python regex AttributeError: 'NoneType' オブジェクトに 'group' 属性がない。
-
[解決済み】TypeError: 系列を <class 'float'> に変換することができません。
-
[解決済み] 現在のクラスを戻り値の型アノテーションとして置く [重複] 。