web-dev-qa-db-ja.com

データ型に基づいてpythonで条件をどのように設定しますか?

この質問は気が遠くなるほど単純なようですが、それを理解することはできません。 Pythonでデータ型をチェックできることはわかっていますが、データ型に基づいて条件を設定するにはどうすればよいですか?たとえば、辞書/リストをソートしてすべての整数を合計するコードを記述する必要がある場合、整数のみを検索するように検索を分離するにはどうすればよいですか?

簡単な例は次のようになると思います:

y = []
for x in somelist:
    if type(x) == <type 'int'>:  ### <--- psuedo-code line
    y.append(x)
print sum(int(z) for z in y)

では、3行目では、このような条件をどのように設定しますか?

22
01110100

いかがですか、

if isinstance(x, int):

しかし、よりクリーンな方法は単に

sum(z for z in y if isinstance(z, int))
42
Jakob Bowyer

TLDR:

  • 理由がない限り、if isinstance(x, int):を使用してください。
  • 正確な型の等価性だけが必要な場合は、if type(x) is int:を使用します。
  • ターゲットタイプへの変換に問題がない場合は、try: ix = int(x)を使用します。

Pythonでの型チェックには、非常に大きな「依存」があります。タイプを処理するには多くの方法があり、すべて長所と短所があります。 Python3では、さらにいくつかが登場しました。

明示的な型の等価性

タイプはファーストクラスのオブジェクトであり、他の値と同様に扱うことができます。したがって、何かのタイプをintに等しくしたい場合は、それをテストします。

_if type(x) is int:
_

これは最も限定的なタイプのテストです。exactタイプの等価性が必要です。多くの場合、これはあなたが望むものではありません:

  • 代替タイプは除外されます。floatは、多くの目的でintのように動作しますが、有効ではありません。
  • サブクラスと抽象型は除外されます。論理的に整数であっても、かなり出力されるintサブクラスまたはenumは拒否されます。
    • これは移植性を厳しく制限します:Python2文字列はstrまたはunicodeのいずれかであり、整数はどちらかintまたはlong

明示的な型の等価性は、低レベルの操作に使用することに注意してください。

  • sliceなどの一部のタイプはサブクラス化できません。ここでは、明示的なチェックがより明示的です。
  • シリアル化やC-APIなどの一部の低レベル操作では、特定のタイプが必要です。

バリアント

___class___属性に対して比較を実行することもできます。

_if x.__class__ is int:
_

クラスが___class___プロパティを定義する場合、これはtype(x)と同じではないことに注意してください。

チェックするクラスがいくつかある場合は、dictを使用してアクションをディスパッチする方が拡張性が高く、明示的なチェックよりも高速(5〜10タイプ)になります。これは、変換とシリアル化に特に役立ちます。

_dispatch_dict = {float: round, str: int, int: lambda x: x}
def convert(x):
    converter = self.dispatch_dict[type(x)]  # lookup callable based on type
    return converter(x)
_

明示的な型のインスタンスチェック

慣用型テストではisinstancebuiltin を使用します:

_if isinstance(x, int):
_

このチェックは正確かつ高性能です。これは、ほとんどの場合、タイプをチェックするために欲しいものです:

  • サブタイプを適切に処理します。 pretty-printingのintサブクラスはこのテストに合格します。
  • 一度に複数のタイプをチェックできます。 Python2では、isinstance(x, (int, long))を実行すると、すべての組み込み整数が得られます。

最も重要なのは、マイナス面がほとんどの場合無視できることです。

  • 変な動作をするファンキーなサブクラスも受け入れます。 anythingは奇妙な方法で動作させることができるので、これを防ぐのは無駄です。
  • それは簡単にtoo制限される可能性があります:多くの人は、任意のシーケンス(たとえばTuple)またはさらにはisinstance(x, list)をチェックしますiterable(例えばgenerator)も同様です。これは、スクリプトやアプリケーションよりも、汎用ライブラリの方が重要です。

バリアント

タイプがすでにある場合、issubclassは同じように動作します。

_if issubclass(x_type, int):
_

抽象型のインスタンスチェック

Pythonには 抽象基本クラス の概念があります。大まかに言えば、これらは型の意味ではなく、型の意味を表しています。

_if isinstance(x, numbers.Real):  # accept anything you can sum up like a number
_

つまり、type(x)は必ずしも_numbers.Real_からinheritとは限りませんが、behaveいいね。それでも、これは非常に複雑で難しい概念です。

  • 基本的なタイプを探している場合、多くの場合、やり過ぎです。ほとんどの場合、整数は単にintです。
  • 他の言語から来た人々はしばしばその概念を混乱させます。
    • それを例えばから区別するC++では、abstract基本クラスではなく、abstract baseクラスが強調されます。
    • ABCはJavaインターフェースのように使用できますが、まだ具体的な機能を持っている可能性があります。

ただし、汎用ライブラリや抽象化には非常に役立ちます。

  • 多くの関数/アルゴリズムは、明示的な型を必要とせず、その動作のみを必要とします。
    • キーで検索するだけの場合、dictは特定のメモリ内タイプに制限します。対照的に、_collections.abc.Mapping_には、データベースラッパー、大容量のディスクバックアップ辞書、レイジーコンテナーなども含まれます-およびdict
  • 部分的な型制約を表すことができます。
    • 反復を実装する厳密な基本型はありません。しかし、オブジェクトを_collections.abc.Iterable_に対してチェックすると、それらはすべてforループで機能します。
  • 同じ抽象型として表示される、最適化された個別の実装を作成できます。

通常、使い捨てのスクリプトには必要ありませんが、数個のpythonリリースを超えて存在するものすべてに使用することを強くお勧めします。

仮変換

型を処理する慣用的な方法は、型をテストすることではなく、互換性があると想定することです。入力に誤った型がすでにあると予想される場合は、互換性のないものはすべてスキップしてください。

_try:
    ix = int(x)
except (ValueError, TypeError):
    continue  # not compatible with int, try the next one
else:
    a.append(ix)
_

これは実際には型チェックではありませんが、通常同じ目的を果たします。

  • それは保証あなたの出力に期待されるタイプがあることです。
  • 間違った型を変換する際には、ある程度の余裕があります。 floatintに特化しています。
  • どの型がintに準拠しているかを知らなくても機能します。

主な欠点は、それが明示的な変換であることです。

  • 「間違った」値を黙って受け入れることができます。リテラルを含むstrを変換します。
  • それは不必要に、十分に良いタイプでさえ変換します。 floatからintは、数値だけが必要な場合に使用します。

変換は、いくつかの特定のユースケースに効果的なツールです。入力が何であるかを大まかに知っていて、出力について保証しなければならない場合に最適です。

関数のディスパッチ

型チェックの目的は、適切な関数を選択することだけである場合があります。この場合、 _functools.singledispatch_ などの関数ディスパッチにより、特定のタイプの関数実装を特殊化できます。

_@singledispatch
def append_int(value, sequence):
    return

@append_int.register
def _(value: int, sequence):
    sequence.append(value)
_

これはisinstancedictディスパッチの組み合わせです。これは、より大きなアプリケーションに最も役立ちます。

  • ディスパッチされたタイプの数に関係なく、使用のサイトを小さく保ちます。
  • 他のモジュールでも、後で追加の型の特殊化を登録できます。

それでも、それには欠点がないわけではありません。

  • 多くのPython=プログラマーは、関数型で強く型付けされた言語を起源としており、単一または複数のディスパッチに慣れていません。
  • ディスパッチは個別の機能を必要とするため、使用場所での定義には適していません。
    • 関数を作成してディスパッチキャッシュを「ウォームアップ」すると、実行時に著しいオーバーヘッドがかかります。ディスパッチ関数は一度定義して、頻繁に再利用する必要があります。
    • ウォームアップされたディスパッチテーブルでさえ、手書きのif/elseまたはdictルックアップよりも遅くなります。

入力の制御

最善の策は、そもそもタイプをチェックする必要がないようにすることです。ユースケースに強く依存するため、これは少しメタトピックです。

ここでは、somelistのソースに非数値を入れるべきではありません。

14
MisterMiyagi

int型の変数xを宣言しましょう

x = 2
if type(x) == type(1) or isinstance(x, int):  
    # do something

どちらも正常に動作します。

0
Naga Sreyas