确定一个对象的types?
有一个简单的方法来确定一个variables是一个列表,字典,或其他? 我得到一个可能是任何types的对象,我需要能够区分。
要获取对象的types,可以使用内置的type()
函数。 传递一个对象作为唯一的参数将返回该对象的types对象:
>>> type([]) is list True >>> type({}) is dict True >>> type('') is str True >>> type(0) is int True >>> type({}) <type 'dict'> >>> type([]) <type 'list'>
这当然也适用于自定义types:
>>> class Test1 (object): pass >>> class Test2 (Test1): pass >>> a = Test1() >>> b = Test2() >>> type(a) is Test1 True >>> type(b) is Test2 True
注意type()
只会返回对象的直接types,但是不能告诉你typesinheritance。
>>> type(b) is Test1 False
为了解决这个问题,你应该使用isinstance
函数。 这当然也适用于内置的types:
>>> isinstance(b, Test1) True >>> isinstance(b, Test2) True >>> isinstance(a, Test1) True >>> isinstance(a, Test2) False >>> isinstance([], list) True >>> isinstance({}, dict) True
isinstance()
通常是确保对象types的首选方法,因为它也会接受派生types。 所以,除非实际需要types对象(无论出于何种原因),否则使用isinstance()
优于type()
。
isinstance()
的第二个参数也接受一个types的元组,所以可以一次检查多个types。 isinstance
将返回true,如果该对象是以下任何types的:
>>> isinstance([], (tuple, list, set)) True
你可以使用type()
来做到这一点:
>>> a = [] >>> type(a) <type 'list'> >>> f = () >>> type(f) <type 'tuple'>
使用try
… except
块可能会更加Pythonic。 那样的话,如果你有一个像名单那样庸医的类,或者像一个字典那样的庸医,那么它将会正确地行事,而不pipe它的types是什么。
为了澄清,variablestypes之间的“区别”的首选方法是使用鸭型打字 :只要variables响应的方法(和返回types)是你的子程序所期望的,就像你期待的那样对待它成为。 例如,如果您有一个用getattr
和setattr
重载括号运算符的类,但是使用了一些有趣的内部scheme,那么如果它正在尝试模拟它,那么将它作为一个字典是合适的。
type(A) is type(B)
的另一个问题type(A) is type(B)
检查是,如果A
是B
的子类,那么当以编程的方式计算它的值时,它的计算结果为false
。 如果一个对象是一个列表的子类,它应该像列表一样工作:检查另一个答案中提供的types将防止这种情况。 (但isinstance
将工作)。
在对象的实例上,你也有:
__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和新风格的类(可selectPython 2.6)类和types已合并,这有时会导致意想不到的结果。 主要是因为这个原因,我最喜欢的testingtypes/类的方式是isinstance内置函数。
确定一个Python对象的types
确定types的对象的type
>>> obj = object() >>> type(obj) <class 'object'>
尽pipe它起作用了,但避免使用__class__
这样的双下划线属性 – 它们在语义上不是公共的,而且在这种情况下可能不是这样,内置函数通常具有更好的行为。
>>> obj.__class__ # avoid this! <class 'object'>
types检查
有一个简单的方法来确定一个variables是一个列表,字典,或其他? 我得到一个可能是任何types的对象,我需要能够区分。
那么这是一个不同的问题,不要使用type – use 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)
这涵盖了你的用户可能通过inheritancestr
来做一些聪明或者合理的事情 – 根据Liskov Substitution的原则,你希望能够在不破坏代码的情况下使用子类实例,并且支持这一点。
使用抽象
更好的是,您可以从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)
或者只是不明确地键入检查
或者,也许最重要的是,使用鸭子打字,而不是明确的types检查你的代码。 鸭子打字支持Liskovreplace更加优雅和较不详细。
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
显式检查实际的子类或注册的抽象。 - 只要避免types检查在哪里是有道理的。
您可以使用type()
或isinstance()
。
>>> type([]) is list True
被警告你可以通过在同名的当前范围中分配一个variables来打开list
或任何其他types。
>>> the_d = {} >>> t = lambda x: "aight" if type(x) is dict else "NOPE" >>> t(the_d) 'aight' >>> dict = "dude." >>> t(the_d) 'NOPE'
上面我们看到dict
被重新分配给一个string,因此testing:
type({}) is dict
…失败。
为了解决这个问题,更谨慎地使用type()
>>> import __builtin__ >>> the_d = {} >>> type({}) is dict True >>> dict ="" >>> type({}) is dict False >>> type({}) is __builtin__.dict True
虽然问题是相当老的,但是我偶然发现了一个正确的方法,我认为它仍然需要澄清, 至less对于Python 2.x (没有检查Python 3,但是由于经典类出现问题这些版本都没有了,可能没关系)。
在这里,我试图回答标题的问题: 我如何确定任意对象的types ? 关于使用或不使用isinstance的其他build议很多评论和答案,但我没有解决这些问题。
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
我认为,这不是大多数人所期望的。
__class__
方法是最接近正确的方法,但在一个关键的情况下不起作用:当传入的对象是旧式类 (不是实例!)时,因为这些对象缺less这种属性。
这是我能想到的最小的代码片段,以一致的方式满足这样一个合法的问题:
#!/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
的存在,其中包含几个抽象基类(ABCs),它们可以补充鸭子的input。
例如,而不是显式检查是否有列表:
isinstance(my_obj, list)
你可以,如果你只想看看你有没有允许获取项目的对象,使用collections.abc.Sequence
:
from collections.abc import Sequence isinstance(my_obj, Sequence)
如果您对允许获取,设置和删除项目(即可变序列)的对象严格感兴趣,则可以selectcollections.abc.MutableSequence
。
在那里定义了许多其他的ABC, Mapping
可以用作映射, Iterable
, Callable
等的对象。 所有这些的完整列表可以在collections.abc
的文档中看到。
小心使用isinstance
isinstance(True, bool) True >>> isinstance(True, int) True
但types
type(True) == bool True >>> type(True) == int False