检查给定对象是否属于给定类型的最佳方法是什么?如何检查对象是否继承给定类型?
假设我有一个对象o
.我如何检查它是否是一个str
?
要检查是否o
是实例str
或任何子类str
,请使用isinstance(这将是"规范"方式):
if isinstance(o, str):
要检查类型o
是否完全str
(排除子类):
if type(o) is str:
以下也适用,在某些情况下可能有用:
if issubclass(type(o), str):
有关相关信息,请参阅Python Library Reference中的内置函数.
还有一点需要注意:在这种情况下,如果你使用的是python 2,你可能真的想要使用:
if isinstance(o, basestring):
因为这也将赶上Unicode字符串(unicode
不是的子类str
,这两个str
和unicode
是的子类basestring
).请注意,basestring
python 3中不再存在,其中严格分离 strings(str
)和二进制数据(bytes
).
或者,isinstance
接受一个类的元组.如果x是任何(str,unicode)的任何子类的实例,则返回True:
if isinstance(o, (str, unicode)):
检查对象类型的最 Pythonic方法是......不检查它.
由于Python鼓励Duck Typing,你应该只想try...except
按照你想要的方式使用对象的方法.因此,如果您的函数正在寻找可写文件对象,请不要检查它是否是它的子类file
,只是尝试使用它的.write()
方法!
当然,有时候这些漂亮的抽象会破坏,isinstance(obj, cls)
这就是你所需要的.但要谨慎使用.
isinstance(o, str)
True
如果o
是str
或是继承自的类型,则返回str
.
type(o) is str
将返回True
当且仅当o
是str.False
如果o
是继承自的类型,它将返回str
.
在询问问题并回答之后,将类型提示添加到Python中.Python中的类型提示允许检查类型,但与静态类型语言的方式完全不同.在Python类型提示的预期类型的参数与功能与功能相关联的运行获得的数据关联起来,这使得为被检查的类型.类型提示语法示例:
def foo(i: int): return i foo(5) foo('oops')
在这种情况下,我们希望触发错误,foo('oops')
因为参数的注释类型是int
.添加的类型提示不会导致脚本正常运行时发生错误.但是,它会向函数添加属性,以描述其他程序可以查询并用于检查类型错误的预期类型.
可用于查找类型错误的其他程序之一是mypy
:
mypy script.py script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(您可能需要mypy
从您的软件包管理器安装.我不认为它与CPython一起提供,但似乎有一定程度的"官方".)
以这种方式检查类型与静态类型编译语言中的类型检查不同.因为类型在Python中是动态的,所以类型检查必须在运行时完成,这会产生成本 - 即使是在正确的程序上 - 如果我们坚持认为它是偶然发生的.显式类型检查也可能比需要更严格,并导致不必要的错误(例如,参数真的需要是完全list
类型还是任何可迭代的东西?).
显式类型检查的优点是它可以更早地捕获错误并提供比duck typing更清晰的错误消息.鸭子类型的确切要求只能用外部文档表示(希望它是彻底和准确的),不兼容类型的错误可能远离它们的起源.
Python的类型提示旨在提供一种折衷方案,可以指定和检查类型,但在通常的代码执行期间不需要额外的成本.
该typing
包提供了类型变量,可以在类型提示中使用它来表达所需的行为,而不需要特定的类型.例如,它包含变量,例如Iterable
和Callable
提示,以指定对具有这些行为的任何类型的需求.
虽然类型提示是检查类型的最Pythonic方式,但通常更不用Pythonic来检查类型并依赖于duck typing.类型提示相对较新,当他们是最恐怖的解决方案时,陪审团仍在继续.一个相对无争议但非常一般的比较:类型提示提供了一种可以强制执行的文档形式,允许代码生成更早且更容易理解的错误,可以捕获鸭子不能输入的错误,并且可以静态检查(在不寻常的情况下)感觉但它仍然在运行时之外).另一方面,鸭子打字长期以来一直是Pythonic方式,不会强加静态打字的认知开销,不那么冗长,并且会接受所有可行的类型然后一些.
这里有一个例子,为什么鸭子打字是邪恶的,而不知道它何时是危险的.例如:这是Python代码(可能省略了正确的缩进),请注意,通过处理isinstance和issubclassof函数可以避免这种情况,以确保当你真的需要一个鸭子时,你不会得到炸弹.
class Bomb: def __init__(self): "" def talk(self): self.explode() def explode(self): print "BOOM!, The bomb explodes." class Duck: def __init__(self): "" def talk(self): print "I am a duck, I will not blow up if you ask me to talk." class Kid: kids_duck = None def __init__(self): print "Kid comes around a corner and asks you for money so he could buy a duck." def takeDuck(self, duck): self.kids_duck = duck print "The kid accepts the duck, and happily skips along" def doYourThing(self): print "The kid tries to get the duck to talk" self.kids_duck.talk() myKid = Kid() myBomb = Bomb() myKid.takeDuck(myBomb) myKid.doYourThing()
isinstance(o, str)
链接到文档
我认为使用像Python这样的动态语言很酷,你真的不应该检查这样的东西.
我只是在你的对象上调用所需的方法并捕获一个AttributeError
.稍后,这将允许您使用其他(看似无关的)对象调用您的方法来完成不同的任务,例如模拟对象进行测试.
在从Web上获取数据时,我已经使用了很多东西,urllib2.urlopen()
它返回了像 object 这样的文件.这可以反过来传递给几乎任何从文件读取的方法,因为它实现了与read()
真实文件相同的方法.
但我确定有时间和地点使用isinstance()
,否则它可能不会在那里:)
前往雨果:
您可能list
不是意思而是array
,但这指向类型检查的整个问题-您不想知道所讨论的对象是否是列表,您想知道它是某种序列还是单个对象。因此,请尝试像序列一样使用它。
假设您要将对象添加到现有序列中,或者如果它是对象序列,则将它们全部添加
try: my_sequence.extend(o) except TypeError: my_sequence.append(o)
一个技巧是,如果您正在处理字符串和/或字符串序列-这很棘手,因为字符串通常被认为是单个对象,但是它也是一个字符序列。更糟糕的是,它实际上是一个单长度字符串序列。
我通常选择设计API,使其只接受一个值或一个序列-这样会使事情变得更容易。[ ]
如果需要,在传递单个值时并不难。
(尽管这可能会导致字符串错误,因为它们看起来确实像是序列)。