代码之家  ›  专栏  ›  技术社区  ›  Alex KeySmith

在python中检查类型的规范方法是什么?

  •  1016
  • Alex KeySmith  · 技术社区  · 16 年前

    检查给定对象是否为给定类型的最佳方法是什么?检查对象是否继承自给定类型如何?

    假设我有一个物体 o . 我怎么检查它是不是 str ?

    10 回复  |  直到 5 年前
        1
  •  1238
  •   smci    6 年前

    检查是否 o 是的实例 str 或任何子类 STR 使用 isinstance (这是“规范的”方式):

    if isinstance(o, str):
    

    检查 o 正是 STR (不包括子类):

    if type(o) is str:
    

    以下内容也有效,在某些情况下可能有用:

    if issubclass(type(o), str):
    

    Built-in Functions 在python库中参考相关信息。

    另一个注意事项:在本例中,如果您使用的是python 2,那么实际上您可能需要使用:

    if isinstance(o, basestring):
    

    因为这也会捕获Unicode字符串( unicode 不是的子类 STR 两者 STR 统一码 是的子类 basestring )注意 基带 不再存在于python 3中 a strict separation 弦乐( str )和二进制数据( bytes )

    或者, isinstance 接受类的元组。如果x是任何(str,unicode)子类的实例,则返回true:

    if isinstance(o, (str, unicode)):
    
        2
  •  161
  •   smci    6 年前

    这个 检查物体类型的方法是…不用检查。

    因为python鼓励 Duck Typing ,你应该 try...except 以您想要的方式使用对象的方法。因此,如果函数正在查找可写文件对象, 不要 检查它是否是 file ,只需尝试使用它 .write() 方法!

    当然,有时这些美好的抽象会分解 isinstance(obj, cls) 是你需要的。但要谨慎使用。

        3
  •  43
  •   Gray droiddeveloper    6 年前

    isinstance(o, str) 将返回 true 如果 o 是一个 str 或属于继承自的类型 STR .

    type(o) is str 将返回 当且仅当 o 是str。它会返回 false 如果 o 是从继承的类型 STR .

        4
  •  21
  •   Praxeolitic    7 年前

    在问题被问和回答之后, type hints were added to 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"
    

    (您可能需要安装 梅皮 来自您的包管理器。我不认为它与塞顿一起出现,但似乎有某种程度的“官僚主义”。

    这种方式的类型检查不同于静态类型编译语言中的类型检查。因为类型在Python中是动态的,所以必须在运行时进行类型检查,如果我们坚持每次都要进行类型检查,这会带来一定的成本——甚至是对正确的程序也是如此。显式类型检查也可能比需要的更严格,并导致不必要的错误(例如,参数是否确实需要 list 类型或是否有足够的信息?).

    显式类型检查的好处在于,它可以更早地捕获错误,并提供比duck类型更清晰的错误消息。duck类型的准确需求只能用外部文档来表示(希望它是彻底和准确的),不兼容类型的错误可能发生在远离其来源的地方。

    python的类型提示旨在提供一种折衷方案,在这种折衷方案中可以指定和检查类型,但在通常的代码执行过程中不需要额外的成本。

    这个 typing 包提供了类型变量,可以在类型提示中使用这些变量来表示所需的行为,而不需要特定的类型。例如,它包括变量,例如 Iterable Callable 以获取提示,以指定对具有这些行为的任何类型的需要。

    虽然类型提示是检查类型的最蟒蛇式方法,但不检查类型并依赖duck类型通常更为蟒蛇式。类型提示是比较新的,而陪审团仍然在讨论什么时候它们才是最可能的蟒蛇解决方案。一个相对无争议但非常普遍的比较:类型提示提供了一种可以强制执行的文档形式,允许代码提前生成并更容易理解错误,可以捕获duck类型不能捕获的错误,并且可以静态检查(在一个不寻常的意义上,但它仍然在运行时之外)。另一方面,duck打字已经是一种很长一段时间的蟒蛇式的方式,不会强加静态打字的认知开销,不那么冗长,会接受所有可行的类型,然后接受一些。

        5
  •  17
  •   Amelio Vazquez-Reina    11 年前

    这里有一个例子,为什么鸭子打字是邪恶的,而不知道什么时候它是危险的。 例如:这里是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()
    
        6
  •  12
  •   DarkCygnus    6 年前
    isinstance(o, str)
    

    Link to docs

        7
  •  6
  •   Peter Mortensen mkoryak    7 年前

    我认为使用像python这样的动态语言最酷的一点是,你真的不需要检查类似的东西。

    我只需要调用对象上所需的方法并捕获 AttributeError . 稍后,这将允许您使用其他(看起来不相关的)对象调用您的方法来完成不同的任务,例如模拟用于测试的对象。

    我在从网上获取数据时经常使用这个 urllib2.urlopen() 返回一个 类文件 对象。这反过来可以传递给几乎所有从文件中读取的方法,因为它实现了相同的 read() 方法作为实际文件。

    但我相信有时间和地点可以使用 isinstance() 否则它可能不在那里。)

        8
  •  4
  •   Peter Mortensen mkoryak    7 年前

    雨果:

    你可能是说 list 而不是 array ,但这指出了类型检查的整个问题——您不想知道问题对象是否是列表,您想知道它是某种序列还是单个对象。所以试着像序列一样使用它。

    假设要将对象添加到现有序列,或者如果是对象序列,则将它们全部添加。

    try:
       my_sequence.extend(o)
    except TypeError:
      my_sequence.append(o)
    

    其中一个技巧是,如果您使用的是字符串和/或字符串序列-这很棘手,因为字符串通常被认为是单个对象,但它也是一个字符序列。更糟糕的是,它实际上是一个单长度字符串的序列。

    我通常选择设计我的API,这样它只接受一个值或一个序列——这使事情变得更容易。这并不难 [ ] 如果需要的话,在传递单个值的时候。

    (尽管这可能会导致字符串出错,因为它们看起来像(是)序列。)

        9
  •  0
  •   Granitosaurus    5 年前

    对于更复杂的类型验证,我喜欢 typeguard 基于python类型提示注释的验证方法:

    from typeguard import check_type
    from typing import List
    
    try:
        check_type('mylist', [1, 2], List[int])
    except TypeError as e:
        print(e)
    

    您可以以非常干净和可读的方式执行非常复杂的验证。

    check_type('foo', [1, 3.14], List[Union[int, float]])
    # vs
    isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo) 
    
        10
  •  -6
  •   Peter Mortensen mkoryak    7 年前

    您可以使用下面的行检查给定值的字符类型:

    def chr_type(chrx):
        if chrx.isalpha()==True:
            return 'alpha'
        elif chrx.isdigit()==True:
            return 'numeric'
        else:
            return 'nothing'
    
    chr_type("12)