web-dev-qa-db-ja.com

入力しますか?

タイピングでobjectを使用するのとは異なり、typing.Anyを使用することに違いはありますか?例えば:

def get_item(L: list, i: int) -> typing.Any:
    return L[i]

に比べ:

def get_item(L: list, i: int) -> object:
    return L[i]
27
Markus Meskanen

はい、違いがあります。 Python 3では、すべてのオブジェクトはobject自体を含むobjectのインスタンスですが、戻り値を無視する必要があるのはAnyドキュメントのみですタイプチェッカーによって。

Anyタイプのdocstringは、オブジェクトがAnyのサブクラスであり、その逆も同様であることを示しています。

_>>> import typing
>>> print(typing.Any.__doc__)
Special type indicating an unconstrained type.

    - Any object is an instance of Any.
    - Any class is a subclass of Any.
    - As a special case, Any and object are subclasses of each other.
_

ただし、適切なタイプチェッカー(isinstance()チェックを超え、オブジェクトが実際に使用されているかどうかを検査する(== --- ==)関数内で) objectは常に受け入れられるAnyにすぐに反対できます。

Any type documentation から:

タイプAnyの値をより正確なタイプに割り当てる場合、タイプチェックは実行されないことに注意してください。

そして

Anyの動作とobjectの動作を比較してください。 Anyと同様に、すべての型はobjectのサブタイプです。ただし、Anyとは異なり、その逆は当てはまりません。オブジェクトは他のすべてのタイプのサブタイプではありません。

つまり、値の型がobjectの場合、型チェッカーはそのほとんどすべての操作を拒否し、より特殊な型の変数に割り当てる(または戻り値として使用する)型です。エラー。

そしてmypyドキュメントセクションから Any vs.object

タイプobjectは、値として任意のタイプのインスタンスを持つことができる別のタイプです。 Anyとは異なり、objectは通常の静的型(JavaのObjectに類似)であり、オブジェクト値に対して受け入れられるのは、すべての型に有効な操作のみです。

objectcast より具体的な型にできますが、Anyは実際にすべてが意味することを意味しますと型チェッカーは、オブジェクトの使用から解放されます(後でそのようなオブジェクトをistypecheckedという名前に割り当てた場合でも)。

listを受け入れることにより、関数を型なしのコーナーにすでにペイントしました。これは、_List[Any]_と同じものになります。タイプチェッカーが解除され、戻り値は重要ではなくなりましたが、関数はAnyオブジェクトを含むリストを受け入れるため、適切な戻り値ここではAnyになります。

型チェックされたコードに適切に参加するには、型チェッカーが戻り値を処理できるように、入力を_List[T]_(一般的に型付きのコンテナー)としてマークする必要があります。リストから値を取得しているので、どちらの場合はTになります。 TからTypeVarを作成します。

_from typing import TypeVar, List

T = TypeVar('T')

def get_item(L: List[T], i: int) -> T:
    return L[i]
_
29
Martijn Pieters

Anyobjectは表面的には似ていますが、実際には完全に反対です。

objectは、Pythonのメタクラス階層のrootです。すべてのクラスはobjectから継承します。つまり、objectは、ある意味で、値を指定できる最も限定的なタイプです。タイプobjectの値がある場合、呼び出すことが許可されているメソッドは、すべてのオブジェクトの一部であるメソッドのみです。例えば:

foo = 3  # type: object

# Error, not all objects have a method 'hello'
bar = foo.hello()   

# OK, all objects have a __str__ method
print(str(foo))   

対照的に、Anyエスケープハッチであり、動的に型付けされたコードと静的に型付けされたコードを混在させることができます。 Anyは、最も制限の少ないタイプです。タイプAnyの値では、可能なメソッドまたは操作がすべて許可されます。例えば:

from typing import Any
foo = 3  # type: Any

# OK, foo could be any type, and that type might have a 'hello' method
# Since we have no idea what hello() is, `bar` will also have a type of Any
bar = foo.hello()

# Ok, for similar reasons
print(str(foo))

通常、Anyを試して使用する必要があるのは、次の場合のみです。

  1. 動的に型付けされたコードと静的に型付けされたコードを混合する方法として。たとえば、多くの動的で複雑な関数があり、それらすべてを完全に静的に入力する時間がない場合は、Anyの戻り値の型を与えるだけで解決でき、名目上は型チェック済みの作業にそれらを取り込むことができます。 (言い換えると、Anyは、型チェックされていないコードベースを型付きのコードベースに段階的に移行するのに役立つ便利なツールです)。
  2. タイプするのが難しい式にタイプを与える方法として。たとえば、Pythonの型注釈は現在、再帰型をサポートしていないため、任意のJSON辞書などの入力が困難になります。一時的な手段として、JSON辞書にDict[str, Any]のタイプを与えることができます。これは、何よりも少し優れています。

対照的に、値が存在する可能性のあるすべてのオブジェクトで文字通り機能する必要があることをタイプセーフな方法で示したい場合は、objectを使用します。

私の推奨は、代替手段がない場合を除いて、Anyの使用を避けることです。 Anyは譲歩です。つまり、タイプセーフな世界で実際に生活したいというダイナミズムを可能にするメカニズムです。

詳細については、以下を参照してください。


特定の例では、オブジェクトやAnyではなく、TypeVarsを使用します。あなたがしたいことは、リストに含まれているもののタイプを返したいことを示すことです。リストに常に同じタイプが含まれる場合(通常はそうです)、次のようにします。

from typing import List, TypeVar

T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
    return L[i]

このようにして、get_item関数は可能な限り最も正確な型を返します。

8
Michael0x2a