在Python中检查types的规范方法是什么?
检查给定对象是否为给定types的最佳方法是什么? 如何检查对象是否从给定typesinheritance?
假设我有一个对象o
。 我如何检查它是否是一个str
?
要检查o
的types是不是str
:
type(o) is str
检查是否是str
或str
任何子类的实例(这将是“规范”的方式):
isinstance(o, str)
以下内容也适用,在某些情况下可能有用:
issubclass(type(o), str) type(o) in ([str] + str.__subclasses__())
请参阅Python库参考中的内置函数以获取相关信息。
还有一点需要注意:在这种情况下,你可能真的想要使用:
isinstance(o, basestring)
因为这也会捕获Unicodestring( unicode
不是str
的子类; str
和unicode
都是basestring
子类)。
或者, isinstance
接受一个类的元组。 如果x是(str,unicode)中任何一个子类的实例,这将返回True:
isinstance(o, (str, unicode))
检查对象types的最 Pythonic方法是…不检查它。
由于Python鼓励Duck Typing ,所以你应该尽量按照你想要的方式使用对象的方法。 所以,如果你的函数正在寻找一个可写的文件对象, 不要检查它是file
的子类,只要使用它的.write()
方法!
当然,有时候这些好的抽象概念会被打破,而isinstance(obj, cls)
就是你所需要的。 但谨慎使用。
如果o
是一个str
或者是一个从str
inheritance的types, isinstance(o, str)
将返回true
。
type(o) == str
将返回true
当且仅当o
是一个str。 如果o
是从str
inheritance的types,它将返回false
。
自从问题被提出并回答之后,types注释已被添加到Python中。 在Python中input注释不会导致types被静态强制执行,但它们允许检查types。 types注释语法的示例:
def foo(i: int): return i foo(5) foo('oops')
在这种情况下,我们希望为foo('oops')
触发一个错误,因为参数的注释types是int
。 当脚本正常运行时,添加的注释不会导致错误发生,但会将types注释数据与其他程序可用于检查types错误的函数相关联。
其中一个可以用来查找types错误的程序是mypy
:
mypy script.py script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(你可能需要从你的软件包pipe理器安装mypy
,我不认为它是用CPython自带的,但似乎有一定程度的“官方性”)。
这种types检查与静态types编译语言中的types检查不同。 因为types在Python中是dynamic的,所以types检查必须在运行时完成,如果我们坚持每次都发生这种情况,那么即使在正确的程序上也会产生成本。 显式types检查也可能比所需要的限制更多,并导致不必要的错误(例如,参数是否真的需要精确的list
types或任何足够的迭代?)。
显式types检查的好处在于它可以提前发现错误并给出比鸭子打字更清晰的错误信息。 鸭子的确切要求只能用外部文件来expression(希望它是彻底和准确的),而不兼容的types的错误可能远离它们的起源。
Python的types注释旨在提供一个折衷的地方,可以指定和检查types,但在通常的代码执行过程中没有额外的成本。
typing
包提供了typesvariables,可以在types注释中使用,以表示需要的行为,而不需要特定的types。 例如,它包含用于注释的Iterable
和Callable
等variables,以指定需要这些行为的任何types。
isinstance(o, str)
链接
这是一个例子,为什么鸭子打字是邪恶的,不知道什么时候是危险的。 例如:下面是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()
我认为使用像Python这样的dynamic语言很酷的事情是你真的不应该检查这样的东西。
我只是在你的对象上调用所需的方法,并捕获一个AttributeError
。 稍后,您可以使用其他(看起来不相关的)对象调用您的方法来完成不同的任务,例如嘲笑testing对象。
当使用urllib2.urlopen()
从网上获取数据时,我已经使用了这个function, urllib2.urlopen()
会返回类似于对象的文件 。 这可以反过来传递给几乎所有从文件中读取的方法,因为它实现与真实文件相同的read()
方法。
但我确定有一个使用isinstance()
的时间和地点,否则它可能不会在那里:)
给雨果:
你可能是指list
而不是array
,但是这指出了types检查的整个问题 – 你不想知道有问题的对象是否是一个列表,你想知道它是某种序列还是单个目的。 所以试着像序列一样使用它。
假设你想把这个对象添加到一个已经存在的序列中,或者如果它是一个对象序列,那么把它们全部join
try: my_sequence.extend(o) except TypeError: my_sequence.append(o)
与此有关的一个技巧是如果你正在处理string和/或string序列 – 这是棘手的,因为string通常被认为是一个单一的对象,但它也是一个字符序列。 更糟糕的是,这实际上是一串单一string。
我通常selectdevise我的API,以便它只接受一个单一的值或序列 – 它使事情变得更容易。 如果需要的话,在你传入一个值的时候并不难。
(虽然这可能会导致string错误,因为它们看起来像序列)。
您可以检查下面的行来检查给定值是哪个字符types:
def chr_type(chrx): if chrx.isalpha()==True: return 'alpha' elif chrx.isdigit()==True: return 'numeric' else: return 'nothing' chr_type("12)