変数がリストなのか、ディクショナリーなのか、それとも他のものなのかを簡単に判断する方法はありますか?どちらのタイプにもなりうるオブジェクトを返しているので、その違いを見分けられるようにしたいのです。
オブジェクトの型を取得するには,組み込みのtype()
関数を使います。唯一のパラメータとしてオブジェクトを渡すと,そのオブジェクトの型オブジェクトが返されます.
>>> type([]) is list
True
>>> type({}) is dict
True
>>> type('') is str
True
>>> type(0) is int
True
>>> type({})
<type 'dict'>
>>> type([])
<type 'list'>
もちろん、これはカスタムタイプにも使えます。
>>> class Test1 (object):
pass
>>> class Test2 (Test1):
pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True
なお、type()
はオブジェクトの直接の型を返すだけで、型の継承についてはわかりません。
>>> type(b) is Test1
False
これをカバーするには、isinstance
関数を使用する必要があります。もちろん、これは組み込み型にも有効です。
>>> isinstance(b, Test1)
True
>>> isinstance(b, Test2)
True
>>> isinstance(a, Test1)
True
>>> isinstance(a, Test2)
False
>>> isinstance([], list)
True
>>> isinstance({}, dict)
True
isinstance()は派生型も受け付けるので、オブジェクトの型を確認するには通常好ましい方法です。したがって、(何らかの理由で)実際に型のオブジェクトが必要でない限り、
type()よりも
isinstance()`の使用が好ましいです。
isinstance()の2番目のパラメータも型のタプルを受け付けるので、一度に複数の型をチェックすることができます。isinstance
は、オブジェクトがこれらのタイプのいずれかであれば、trueを返します。
>>> isinstance([], (tuple, list, set))
True
Try...
except` ブロックを使った方がPythonicかもしれません。そうすれば、リストのように見えるクラスや、ディクストのように見えるクラスがあったとしても、実際の型が何であるかに関わらず、適切に動作します。
つまり、変数が応答するメソッド(および戻り値の型)がサブルーチンが期待するものである限り、その変数を期待通りに扱うことができます。例えば、ブラケット演算子を getattr
と setattr
でオーバーロードするクラスがあったとして、そのクラスがおかしな内部スキームを使っていたとしたら、それをエミュレートしようとしているのであれば、そのクラスは辞書として振る舞うのが適切でしょう。
type(A) is type(B)チェックのもう一つの問題点は、
Aが
Bのサブクラスである場合、プログラム的には
trueであることを期待しているのに、
falseと評価されてしまうことです。オブジェクトがリストのサブクラスである場合、それはリストのように動作するはずです。他の回答で提示されているように型をチェックすると、これを防ぐことができます。(しかし、
isinstance`は動作します)。
objectのインスタンスには
__class__
属性を使用しています。 以下は、Python 3.3 のコンソールから取得したサンプルです。
>>> str = "str"
>>> str.__class__
<class 'str'>
>>> i = 2
>>> i.__class__
<class 'int'>
>>> class Test():
... pass
...
>>> a = Test()
>>> a.__class__
<class '__main__.Test'>
python 3.xやNew-Styleクラス(Python 2.6からオプションで利用可能)では、クラスと型がマージされているため、予期しない結果になることがあるので注意してください。 主にこの理由から、型やクラスをテストする私のお気に入りの方法は isinstance 関数を使うことです。
オブジェクトの型を type
で決定する
>>> obj = object()
>>> type(obj)
<class 'object'>
これは動作しますが、__class__
のようなダブルアンダースコア属性は避けてください。
>>> obj.__class__ # avoid this!
<class 'object'>
>. 変数がリストなのか、辞書なのか、何か他のものなのかを判断する簡単な方法はありますか? 私は、どちらの型でもよいオブジェクトを返してもらっているのですが、その違いを見分けることができないといけません。
それは別の質問ですが、型を使わずに isinstance
を使ってください。
def foo(obj):
"""given a string with items separated by spaces,
or a list or tuple,
do something sensible
"""
if isinstance(obj, str):
obj = str.split()
return _foo_handles_only_lists_or_tuples(obj)
これは、ユーザが str
をサブクラス化することで何か賢いことや賢明なことをしているかもしれない場合をカバーします。
さらに良いのは、collections
や numbers
から特定の抽象基底クラスを探すことです。
from collections import Iterable
from numbers import Number
def bar(obj):
"""does something sensible with an iterable of numbers,
or just one number
"""
if isinstance(obj, Number): # make it a 1-tuple
obj = (obj,)
if not isinstance(obj, Iterable):
raise TypeError('obj must be either a number or iterable of numbers')
return _bar_sensible_with_iterable(obj)
あるいは、何よりも良いのはダックタイピングを使用して、明示的にコードのタイプチェックをしないことです。 ダック型付けは、よりエレガントで冗長性の少ないLiskov Substitutionをサポートしています。
def baz(obj):
"""given an obj, a dict (or anything with an .items method)
do something sensible with each key-value pair
"""
for key, value in obj.items():
_baz_something_sensible(key, value)
type
を使います。isinstance
を使います。type()か
isinstance()`を使うことができます。
>>> type([]) is list
True
現在のスコープに同じ名前の変数を代入することで、list
や他の型をパクることができることに注意してください。
>>> the_d = {}
>>> t = lambda x: "aight" if type(x) is dict else "NOPE"
>>> t(the_d) 'aight'
>>> dict = "dude."
>>> t(the_d) 'NOPE'
上では dict
が文字列に再割り当てされていることがわかります。
type({}) is dict
...に失敗します。
これを回避して type()
をより慎重に使用するには、以下のようにします。
>>> import __builtin__
>>> the_d = {}
>>> type({}) is dict
True
>>> dict =""
>>> type({}) is dict
False
>>> type({}) is __builtin__.dict
True
この質問はかなり古いものですが、私自身が適切な方法を見つけていた時に偶然見つけたもので、少なくともPython 2.x**についてはまだ明確にする必要があると思います。
ここではタイトルの質問に答えようとしています。 **任意のオブジェクトの型を決定するにはどうすればいいですか? isinstanceを使うか使わないかについての他の提案は、多くのコメントや回答の中では問題ありませんが、私はそれらの懸念には対処していません。
type()`アプローチの主な問題点は、古いスタイルのインスタンスでは正しく動作しないということです。
class One:
pass
class Two:
pass
o = One()
t = Two()
o_type = type(o)
t_type = type(t)
print "Are o and t instances of the same class?", o_type is t_type
このスニペットを実行すると、次のようになります。
Are o and t instances of the same class? True
これは、ほとんどの人が期待していることではないと私は主張しています。
classclass`アプローチは最も正しさに近いアプローチですが、ある重要なケースでは機能しません。 それは、渡されたオブジェクトが古いスタイルのclass(インスタンスではありません!)である場合です。
これは、このような正当な疑問を一貫した方法で満たす、私が考えられる最小のコードです。
#!/usr/bin/env python
from types import ClassType
#we adopt the null object pattern in the (unlikely) case
#that __class__ is None for some strange reason
_NO_CLASS=object()
def get_object_type(obj):
obj_type = getattr(obj, "__class__", _NO_CLASS)
if obj_type is not _NO_CLASS:
return obj_type
# AFAIK the only situation where this happens is an old-style class
obj_type = type(obj)
if obj_type is not ClassType:
raise ValueError("Could not determine object '{}' type.".format(obj_type))
return obj_type
前の回答の余談ですが、[collections.abc
][1]には、ダックタイピングを補完するいくつかの抽象基底クラス(ABC)が含まれていることに言及する価値があります。
例えば、何かがリストであるかどうかを明示的にチェックする代わりに、以下のようにします。
isinstance(my_obj, list)
もしあなたが持っているオブジェクトがアイテムを取得できるかどうかだけに興味があるのであれば、[collections.abc.Sequence
][2]を使用してください。
from collections.abc import Sequence
isinstance(my_obj, Sequence)
アイテムの取得、設定、削除ができるオブジェクト(つまりmutableシーケンス)に厳密に興味があるならば、collections.abc.MutableSequence
を選ぶでしょう。
他にも多くのABCが定義されており、マップとして使用できるオブジェクトのための
Mapping、
Iterable、
Callableなどがあります。 これらの全リストは、[collections.abc
のドキュメント][3]で見ることができます。
[1]: https://docs.python.org/3/library/collections.abc.html [2]: https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence [3]: https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes
type()は
isinstance()よりも良い解決策であり、特に
booleanについては、
type()` の方が良いでしょう。
Trueや
Falseは python では
1や
0` を意味するキーワードにすぎません。
そのため、以下のようになります。
isinstance(True, int)
そして
isinstance(False, int)
はどちらも True
を返します。
どちらのブーリアンも整数のインスタンスです。
しかし、type()
の方がより賢い。
type(True) == int
戻り値は False
です。
一般的には、クラス名を持つオブジェクトから文字列を抽出することができます。
str_class = object.__class__.__name__
と比較するために使用しています。
if str_class == 'dict':
# blablabla..
elif str_class == 'customclass':
# blebleble..
多くの実用的なケースでは、type
やisinstance
の代わりに、@functools.singleispatch
を使うこともできます。これは、generic functionsを定義するために使われます(異なる型に対して同じ操作を実装する複数の関数からなる関数)。
つまり、以下のようなコードがあるときに使いたくなります。
def do_something(arg)
if isinstance(arg, int).
...
# 整数の処理に特化したコード
if isinstance(arg, str).
...
# 文字列を処理するためのコード
if isinstance(arg, list)。
...
# リストを処理するためのコード
... # etc.
これがどのように機能するのか、小さな例を挙げてみましょう。
from functools import singledispatch
@singledispatch
def say_type(arg).
raise NotImplementedError(f"I don't work with {type(arg)}")
say_type.register
def _(arg: int).
print(f"{arg}は整数です")
say_type.register
def _(arg: bool).
print(f"{arg} is a boolean")
无 となります。 say_type(0) 0は整数
>. say_type(False) Falseはブール値 となります。 say_type(dict())
長いエラートレースバックで終わります。
NotImplementedError. 私は<class 'dict'>では動作しません。
--- さらに、[抽象クラス](https://docs.python.org/library/collections.abc.html)を使うことで、複数の型を一度にカバーすることができます。
from collections.abc import Sequence
saytype.register def (arg. シーケンス)であることを示しています。 print(f"{arg}はシーケンスです!")
无
となります。
say_type([0, 1, 2])
0, 1, 2]はシーケンスです!
>>>.
say_type((1, 2, 3))
(1, 2, 3)はシーケンスです!(1, 2, 3)はシーケンスです。