这两个代码片段之间有什么区别?使用
1 2 3 4 5 6 | import types if type(a) is types.DictType: do_something() if type(b) in types.StringTypes: do_something_else() |
使用
1 2 3 4 | if isinstance(a, dict): do_something() if isinstance(b, str) or isinstance(b, unicode): do_something_else() |
要总结其他答案的内容(已经很好了!),
通常,在Python中,您当然希望您的代码支持继承(因为继承非常方便,所以阻止使用您的代码使用它将是非常糟糕的),所以
注意,这并不是说
但是,
1 2 3 4 5 6 | if isinstance(x, basestring) return treatasscalar(x) try: return treatasiter(iter(x)) except TypeError: return treatasscalar(x) |
您可以说
PEP明确指出,虽然abc通常可以替代duck类型,但是通常没有很大的压力来做这件事(请参阅这里)。ABC和最近的Python版本中实现然而提供额外的好处:
有关Python 2.6中提供的ABC支持的底层机制,请参见这里;对于他们的3.1版本,非常相似,请看这里。在这两个版本中,标准库模块集合(即3.1版本—非常相似的2.6版本,请参见这里)提供了几个有用的abc。
为了这个答案,关键要保持对abc (TM DP的更自然放置功能之外,相比经典Python UserDict.DictMixin等替代mixin类)是他们让
下面是一个例子,
1 2 3 4 5 | class Vehicle: pass class Truck(Vehicle): pass |
在本例中,卡车对象是一辆汽车,但您将得到以下信息:
1 2 3 4 | isinstance(Vehicle(), Vehicle) # returns True type(Vehicle()) == Vehicle # returns True isinstance(Truck(), Vehicle) # returns True type(Truck()) == Vehicle # returns False, and this probably won't be what you want. |
换句话说,
另见:如何比较Python中对象的类型?
Differences between isinstance() andtype() in Python?
类型检查和
1 | isinstance(obj, Base) |
允许子类和多个可能的基的实例:
1 | isinstance(obj, (Base1, Base2)) |
而类型检查
1 | type(obj) is Base |
只支持引用的类型。
作为旁注,
1 | type(obj) == Base |
因为类是单例的。
避免类型检查-使用多态性(duck-typing)在Python中,通常您希望允许参数的任何类型,并将其视为预期的类型,如果对象的行为不符合预期,则会引发适当的错误。这称为多态性,也称为duck-typing。
1 2 3 | def function_of_duck(duck): duck.quack() duck.swim() |
如果上面的代码有效,我们可以假设我们的参数是鸭子。因此,我们可以传入其他的东西都是实际的鸭子子类型:
1 | function_of_duck(mallard) |
或者像鸭子一样工作:
1 | function_of_duck(object_that_quacks_and_swims_like_a_duck) |
我们的代码仍然有效。
然而,在某些情况下,显式类型检查是可取的。也许您对不同的对象类型有一些合理的处理。例如,panda Dataframe对象可以由dict或记录构造。在这种情况下,代码需要知道它得到的参数类型,以便能够正确地处理它。
所以,为了回答这个问题:
在Python中请允许我来说明其中的区别:
type
例如,如果函数获得某种参数(构造函数的常见用例),则需要确保某种行为。如果你检查这样的类型:
1 2 3 4 5 | def foo(data): '''accepts a dict to construct something, string support in future''' if type(data) is not dict: # we're only going to test for dicts for now raise ValueError('only dicts are supported for now') |
如果我们试图传递一个dict,它是
1 2 3 | from collections import OrderedDict foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])) |
提出了一个错误!
1 2 3 4 | Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 3, in foo ValueError: argument must be a dict |
isinstance
但是如果我们使用
1 2 3 4 5 6 | def foo(a_dict): if not isinstance(a_dict, dict): raise ValueError('argument must be a dict') return a_dict foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])) |
返回
抽象基类
事实上,我们可以做得更好。
1 2 3 4 5 6 | from collections import Mapping def foo(a_dict): if not isinstance(a_dict, Mapping): raise ValueError('argument must be a dict') return a_dict |
回应置评:
It should be noted that type can be used to check against multiple classes using
type(obj) in (A, B, C)
是的,你可以测试类型是否相等,但是不要使用上面的方法,而是使用控制流的多个基,除非你特别只允许这些类型:
1 | isinstance(obj, (A, B, C)) |
不同之处在于,
不过,更好的方法是反转依赖关系,根本不检查特定类型。
结论因此,由于我们希望支持替换子类,在大多数情况下,我们希望避免使用
后者是首选的,因为它将正确处理子类。事实上,你的例子可以写得更容易,因为
1 2 | if isinstance(b, (str, unicode)): do_something_else() |
或者,使用
1 2 | if isinstance(b, basestring): do_something_else() |
根据python文档,这里有一个声明:
8.15. types — Names for built-in types Starting in Python 2.2, built-in
factory functions such asint() and
str() are also names for the
corresponding types.
因此,
真正的区别在于,我们可以在
但是我们可以得到类似的abc。根据……instancecheck__。
以上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | # file tree # /test/__init__.py # /test/aaa/__init__.py # /test/aaa/aa.py class b(): pass # /test/aaa/a.py import sys sys.path.append('/test') from aaa.aa import b from aa import b as c d = b() print(b, c, d.__class__) for i in [b, c, object]: print(i, '__subclasses__', i.__subclasses__()) print(i, '__mro__', i.__mro__) print(i, '__subclasshook__', i.__subclasshook__(d.__class__)) print(i, '__subclasshook__', i.__subclasshook__(type(d))) print(isinstance(d, b)) print(isinstance(d, c)) <class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'> <class 'aaa.aa.b'> __subclasses__ [] <class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>) <class 'aaa.aa.b'> __subclasshook__ NotImplemented <class 'aaa.aa.b'> __subclasshook__ NotImplemented <class 'aa.b'> __subclasses__ [] <class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>) <class 'aa.b'> __subclasshook__ NotImplemented <class 'aa.b'> __subclasshook__ NotImplemented <class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>] <class 'object'> __mro__ (<class 'object'>,) <class 'object'> __subclasshook__ NotImplemented <class 'object'> __subclasshook__ NotImplemented True False |
我得到了这个结论,
1 2 3 | # according to `abc.__instancecheck__`, they are maybe different! I have not found negative one type(INSTANCE) ~= INSTANCE.__class__ type(CLASS) ~= CLASS.__class__ |
1 2 | # guess from `abc.__instancecheck__` return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)}) |
顺便说一句:最好不要混合使用