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

2024-11-20 08:44:00
admin
原创
7
摘要:问题描述:如何检查对象是否属于给定类型,或者是否从给定类型继承?如何检查对象是否o属于该类型str?初学者经常错误地认为字符串已经是“数字”——要么期望 Python 3.xinput转换类型,要么期望像这样的字符串同时也是'1'整数。这对于这些问题来说是错误的规范。请仔细阅读问题,然后使用如何检查字符串是否...

问题描述:

如何检查对象是否属于给定类型,或者是否从给定类型继承?

如何检查对象是否o属于该类型str


初学者经常错误地认为字符串已经是“数字”——要么期望 Python 3.xinput转换类型,要么期望像这样的字符串同时也是'1'整数。这对于这些问题来说是错误的规范。请仔细阅读问题,然后使用如何检查字符串是否代表数字(浮点数或整数)?、如何将输入读取为数字?和/或要求用户输入,直到他们给出有效的响应。


解决方案 1:

用于isinstance检查是否o是的实例str或任何子类str

if isinstance(o, str):

要检查 的类型是否o恰好str不包括 的子类str

if type(o) is str:

相关信息请参阅Python 库参考中的内置函数。


检查 Python 2 中的字符串

o对于 Python 2,这是检查是否为字符串的更好方法:

if isinstance(o, basestring):

因为这也将捕获 Unicode 字符串。unicode不是 的子类strstrunicode都是 的子类basestring。在 Python 3 中,basestring不再存在,因为字符串 ( ) 和二进制数据 ( ) 有严格的区分。str`bytes`

或者,接受类的元组。如果是以下任一子类的实例,isinstance则返回:True`o`(str, unicode)

if isinstance(o, (str, unicode)):

解决方案 2:

检查对象类型的最 Python 方式是......不检查它

由于 Python 鼓励使用Duck Typing,因此您应该按照try...except自己想要的方式使用对象的方法。因此,如果您的函数正在寻找可写文件对象,请不要检查它是否是 的子类file,只需尝试使用它的.write()方法!

当然,有时这些漂亮的抽象会失效,而isinstance(obj, cls)这正是你所需要的。但要谨慎使用。

解决方案 3:

isinstance(o, str)`True如果ostr或 是从 继承的类型,则返回str`。

type(o) is str`True当且仅当o是时才会返回。如果是继承自 的类型,str它将返回。Falseostr`

解决方案 4:

在Python 3.10中,你可以|使用isinstance

>>> isinstance(1223, int | str) 
True

>>> isinstance('abcd', int | str) 
True

解决方案 5:

在提出并回答了这个问题之后,类型提示被添加到了 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类型,或者任何可迭代的就足够了?)。

显式类型检查的优点是它可以更早地发现错误,并提供比鸭子类型更清晰的错误消息。鸭子类型的确切要求只能通过外部文档来表达(希望它是全面和准确的),并且不兼容类型的错误可能发生在远离其起源的地方。

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

typing软件包提供了类型变量,可用于类型提示以表达所需行为,而无需特定类型。例如,它包含诸如IterableCallable等变量,用于提示以指定对具有这些行为的任何类型的需求。

虽然类型提示是检查类型最 Pythonic 的方式,但完全不检查类型而依靠鸭子类型往往更 Pythonic。类型提示相对较新,目前尚不清楚它们何时才是最 Pythonic 的解决方案。一个相对没有争议但非常普遍的比较:类型提示提供了一种可以强制执行的文档形式,允许代码更早且更容易理解地生成错误,可以捕获鸭子类型无法捕获的错误,并且可以静态检查(以一种不寻常的方式,但它仍然在运行时之外)。另一方面,鸭子类型长期以来一直是 Pythonic 的方式,不会带来静态类型的认知开销,更简洁,并且会接受所有可行的类型,甚至更多。

解决方案 6:

isinstance(o, str)

链接至文档

解决方案 7:

您可以使用类型的 name 检查变量的类型。

前任:

>>> a = [1,2,3,4]  
>>> b = 1  
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'

解决方案 8:

对于更复杂的类型验证,我喜欢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) 

解决方案 9:

被接受的答案回答了问题,因为它提供了所提问题的答案。

问:检查给定对象是否属于给定类型的最佳方法是什么?如何检查对象是否从给定类型继承?

答:isinstance, issubclass, type根据类型来检查。

然而,正如其他答案和评论很快指出的那样,“类型检查”的概念远不止 Python 中的类型检查。自从添加了 Python 3 和类型提示以来,很多事情也发生了变化。下面,我将介绍类型检查、鸭子类型和异常处理的一些困难。对于那些认为类型检查不是必需的(通常不需要,但我们在这里),我还指出了如何使用类型提示来代替。

类型检查

在 Python 中,类型检查并不总是一件合适的事情。请考虑以下示例:

def sum(nums):
    """Expect an iterable of integers and return the sum."""
    result = 0
    for n in nums:
        result += n
    return result

要检查输入是否是整数的可迭代对象,我们遇到了一个大问题。检查每个元素是否都是整数的唯一方法是循环检查每个元素。但是如果我们循环整个迭代器,那么预期的代码将一无所有。在这种情况下,我们有两种选择。

  1. 循环时进行检查。

  2. 提前检查,但在我们检查后存储所有内容。

选项 1 的缺点是会使我们的代码复杂化,特别是如果我们需要在很多地方执行类似的检查。它迫使我们将类型检查从函数顶部移到代码中使用迭代器的所有地方。

选项 2 的缺点很明显,它破坏了迭代器的整个用途。迭代器的整个用途就是不存储数据,因为我们不需要这样做。

有人可能认为检查所有元素太多了,那么也许我们可以只检查输入本身是否是可迭代类型,但实际上没有任何可迭代基类。任何实现的类型__iter__都是可迭代的。

异常处理和鸭子类型

另一种方法是完全放弃类型检查,转而专注于异常处理和鸭子类型。也就是说,将代码包装在 try-except 块中并捕获发生的任何错误。或者,什么也不做,让异常自然地从代码中出现。

这是捕获异常的一种方法。

def sum(nums):
    """Try to catch exceptions?"""
    try:
        result = 0
        for n in nums:
            result += n
        return result
    except TypeError as e:
        print(e)

与之前的选项相比,这当然更好。我们在运行代码时进行检查。如果有任何TypeError地方,我们都会知道。我们不必在循环输入的每个地方都进行检查。我们也不必在迭代输入时存储输入。

此外,这种方法还支持鸭子类型。我们不再检查specific types,而是检查specific behaviors,并在输入未能按预期运行时查找 (在本例中,循环nums并能够添加n)。

然而,异常处理之所以优秀的原因也可能是其失败的原因。

  1. Afloat不是int,但它满足工作的行为要求。

  2. 用 try-except 块包装整个代码也是不好的做法。

起初这些可能看起来不像是问题,但下面的一些原因可能会改变你的想法。

  1. 用户不再能期望我们的函数int按预期返回。这可能会破坏其他地方的代码。

  2. 由于异常可能来自各种各样的来源,因此在整个代码块上使用 try-except 可能会捕获您不想要的异常。我们只想检查是否nums可迭代且具有整数元素。

  3. 理想情况下,我们希望捕获代码生成器中的异常,并在其位置引发更具信息量的异常。当其他人的代码引发异常而没有任何解释,除了一行你没有写的代码和一些TypeError发生的异常时,这可不是什么好事。

为了修复上述问题的异常处理,我们的代码就会变成这样……令人憎恶。

def sum(nums):
    """
    Try to catch all of our exceptions only.
    Re-raise them with more specific details.
    """
    result = 0

    try:
        iter(nums)
    except TypeError as e:
        raise TypeError("nums must be iterable")

    for n in nums:
        try:
            result += int(n)
        except TypeError as e:
            raise TypeError("stopped mid iteration since a non-integer was found")

    return result

你可以大概知道这是怎么回事。我们越是试图“正确”地检查,我们的代码看起来就越糟糕。与原始代码相比,这根本无法阅读。

我们可以争辩说这也许有点极端。但另一方面,这只是一个非常简单的例子。实际上,你的代码可能比这复杂得多。

类型提示

我们已经看到,当我们尝试修改我们的小示例以“启用类型检查”时会发生什么。类型提示不是专注于尝试强制使用特定类型,而是提供了一种让用户清楚了解类型的方法。

from typing import Iterable

def sum(nums: Iterable[int]) -> int:
    result = 0
    for n in nums:
        result += n
    return result

使用类型提示有一些优点。

  • 代码现在看起来确实不错!

  • 如果您使用类型提示,您的编辑器可能会执行静态类型分析!

  • 它们存储在函数/类中,使它们可动态使用,例如typeguarddataclasses

  • 它们在使用时显示函数help(...)

  • 无需根据描述或更糟糕的缺乏描述来检查您的输入类型是否正确。

  • 您可以根据结构“键入”提示,例如“它有这个属性吗?”而无需用户进行子类化。

类型提示的缺点是什么?

  • 类型提示本身不过是语法和特殊文本而已。它与类型检查不同

换句话说,它实际上并没有回答这个问题,因为它没有提供类型检查。无论如何,如果你来这里是为了进行类型检查,那么你也应该使用类型提示。当然,如果你得出结论,类型检查实际上不是必要的,但你想要一些类似的输入,那么类型提示就适合你。

解决方案 10:

我认为使用像 Python 这样的动态语言的妙处在于你真的不必检查这样的事情。

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

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

但我确信有使用它的时间和地点isinstance(),否则它可能不会在那里:)

解决方案 11:

致 Hugo:

您可能指的是list而不是array,但这指出了类型检查的整个问题 - 您不想知道所讨论的对象是否是列表,您想知道它是某种序列还是单个对象。因此,请尝试像序列一样使用它。

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

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

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

[ ]我通常会选择将 API 设计为只接受单个值或序列 - 这样可以让事情变得简单。如果需要,在传递单个值时将其放在一个位置并不难。

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

解决方案 12:

检查浮点类型

isinstance(x, float)

或者

type(x) is float

如果类型不完全是浮点数,则会返回False,例如 numpy.float32:

import pandas as pd
import numpy as np
x = pd.Series([0.2], dtype=np.float32)[0]

正如该帖子的评论所指出的,numpyissubdtype可用于此目的。

检测浮点类型:

np.issubdtype(type(x), np.floating)
  • 2.0对于、pd.Series([2.0], dtype=np.float32)[0]以及通常任何浮点数、np.float32、np.float64 ... 类型,返回 True

  • 2对于、"2.0"(字符串)、[2.0, 1.2](列表)等,返回 False

检测数字(浮点型和整数型)类型:

np.issubdtype(type(x), np.number)
  • 2对于、2.0pd.Series([2.0], dtype=np.float32)[0]pd.Series([2.0], dtype=np.int32)[0]以及通常任何 float、np.float32、np.float64 ... 类型,返回 True

  • 对于"2"(string)、[2.0, 1.2](list) 等,返回 False

要检测 pd.Index 类类型:

np.issubdtype(type(x), pd.Index)
  • pd.Index对于, pd.Int64Index, pd.Float64Index, ...返回 True

解决方案 13:

str如果您必须检查或的类型,int请使用instanceof。正如其他人已经提到的,解释是还包括子类。在我看来,子类的一个重要示例是数据类型为IntEnum或的枚举StrEnum。这是一种定义相关常量的非常好的方法。但是,如果库不接受这些类型,那就有点烦人了。

例子:

import enum

class MyEnum(str, enum.Enum):
    A = "a"
    B = "b"

print(f"is string: {isinstance(MyEnum.A, str)}")   # True
print(f"is string: {type(MyEnum.A) == str}")       # False!!!
print(f"is string: {type(MyEnum.A.value) == str}") # True

解决方案 14:

在 Python 中,您可以使用内置isinstance()函数来检查对象是否属于给定类型,或者是否从给定类型继承。

要检查对象 o 是否属于 str 类型,可以使用以下代码:

if isinstance(o, str):
# o is of type str

您还可以使用type()函数来检查对象类型。

if type(o) == str:
# o is of type str

您还可以使用函数检查对象是否是特定类的子类issubclass()

if issubclass(type(o),str):
# o is sub class of str

解决方案 15:

要检查对象是否属于给定类型或是否从给定类型继承,可以使用该isinstance()函数。以下是检查对象 o 是否属于 str 类型的方法:

o = "Hello, world!"

if isinstance(o, str):
    print("The object is of type str.")
else:
    print("The object is not of type str.")

解决方案 16:

Python 3.10 引入了一种新方法来检查类型,这种方法通常比match 语句if/instanceof()更简洁。它可以检查多种类型:

float(x) # Is it a floating point?
str(x)   # Is it a string?
int(x)   # Is it an integer?
...

例如,您可以这样处理一些返回多种类型的函数,每个类型都需要以不同的方式处理:

def read_user_input() -> float | str | None:
    ...

# Get user input, rounding floats to 2 decimal places.
def user_input() -> str:
    match read_user_input()
        case float(a_number):
            n = str(round(2, a_number))
        case str(a_string):
            n = return str(round(2, float(a_string.strip())))
        case None:
            n = "(No input given)"

    return n

奖励:当您以这种方式检查类型时,类型检查器可以验证是否match详尽;您已经处理了函数将给您的所有可能类型。

解决方案 17:

如果您还想要整数,则可以使用:

integer = 1
check_integer = integer.isdigit()

isdigit()返回 True 或 False,您可以在中使用它while-loop

解决方案 18:

检查类型的一种简单方法是将其与您知道类型的东西进行比较。

>>> a  = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True

解决方案 19:

我认为最好的方法是正确输入变量。您可以使用“typeing”库来做到这一点。

例子:

from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313`)

请参阅https://docs.python.org/3/library/typing.html

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用