41

这个问题看起来很简单,但我想不通。我知道您可以在 python 中检查数据类型,但是如何根据数据类型设置条件?例如,如果我必须编写一个对字典/列表进行排序并将所有整数相加的代码,我如何隔离搜索以仅查找整数?

我想一个简单的例子看起来像这样:

y = []
for x in somelist:
    if type(x) == <type 'int'>:  ### <--- psuedo-code line
    y.append(x)
print sum(int(z) for z in y)

那么对于第 3 行,我将如何设置这样的条件?

4

6 回答 6

72

怎么样,

if isinstance(x, int):

但更清洁的方法就是

sum(z for z in y if isinstance(z, int))
于 2013-01-01T18:46:08.317 回答
33

TLDR:

  • if isinstance(x, int):除非您有理由不使用,否则请使用。
  • 如果if type(x) is int:您需要精确的类型相等而不需要其他任何东西,请使用。
  • 如果try: ix = int(x)您可以转换为目标类型,请使用。

Python 中的类型检查有一个很大的“取决于”。处理类型的方法有很多种,各有利弊。随着 Python3,出现了更多。

显式类型相等

类型是一流的对象,您可以像对待任何其他值一样对待它们。因此,如果您希望某物的类​​型等于int,只需对其进行测试:

if type(x) is int:

这是最严格的测试类型:它需要精确的类型相等。通常,这不是您想要的:

  • 它排除了替代类型:afloat是无效的,即使它int在许多方面表现得像 an。
  • 它排除了子类和抽象类型:打印漂亮的int子类或enum将被拒绝,即使它们在逻辑上是整数。
    • 这严重限制了可移植性:Python2 字符串可以 stror unicode,而整数可以 intor long

请注意,显式类型相等用于低级操作:

  • 某些类型不能被子类化,例如slice. 一个明确的检查在这里更明确。
  • 一些低级操作,例如序列化或 C-API,需要特定类型。

变体

也可以对__class__属性进行比较:

if x.__class__ is int:

请注意,如果一个类定义了一个__class__属性,这与type(x).

当有多个类要检查时,使用 adict来调度动作比显式检查更具可扩展性并且可以更快(≥5-10 种类型)。这对于转换和序列化特别有用:

dispatch_dict = {float: round, str: int, int: lambda x: x}
def convert(x):
    converter = self.dispatch_dict[type(x)]  # lookup callable based on type
    return converter(x)

显式类型的实例检查

惯用类型测试使用isinstance 内置

if isinstance(x, int):

此检查既准确又高效。这通常是人们想要检查类型的内容:

  • 它正确处理子类型。一个漂亮的打印int子类仍然可以通过这个测试。
  • 它允许一次检查多种类型。在 Python2 中,doingisinstance(x, (int, long))会为您提供所有内置整数。

最重要的是,大多数时候缺点可以忽略不计:

  • 它仍然接受行为怪异的时髦子类。由于任何东西都可以以奇怪的方式表现,因此防范是徒劳的。
  • 它很容易过于严格:许多人检查isinstance(x, list)任何序列(例如tuple)甚至可迭代(例如 a generator)何时也可以。与脚本或应用程序相比,通用库更需要关注这一点。

变体

如果您已经有一个类型,issubclass则行为相同:

if issubclass(x_type, int):

抽象类型的实例检查

Python 有一个抽象基类的概念。粗略地说,这些表达了类型的含义,而不是它们的层次结构:

if isinstance(x, numbers.Real):  # accept anything you can sum up like a number

换句话说, type(x) 不一定继承自它,numbers.Real但必须表现得像它。尽管如此,这是一个非常复杂和困难的概念:

  • 如果您正在寻找基本类型,这通常是矫枉过正。int大多数时候,整数只是一个。
  • 来自其他语言的人经常混淆它的概念。
    • 将它与例如 C++ 区分开来,重点是抽象基类而不是抽象基类。
    • ABC 可以像 Java 接口一样使用,但仍可能具有具体功能。

但是,它对于泛型库和抽象非常有用。

  • 许多函数/算法不需要显式类型,只需要它们的行为。
    • 如果您只需要按键查找内容,则将您dict限制为特定的内存类型。相比之下,collections.abc.Mapping还包括数据库包装器、大型磁盘支持的字典、惰性容器,... - 和dict.
  • 它允许表达部分类型约束。
    • 没有严格的基类型实现迭代。但是如果你检查对象collections.abc.Iterable,它们都在一个for循环中工作。
  • 它允许创建显示为相同抽象类型的单独、优化的实现。

虽然一次性脚本通常不需要它,但我强烈建议将它用于除了几个 python 版本之外的任何东西。

暂定转换

处理类型的惯用方式不是测试它们,而是假设它们是兼容的。如果您已经预料到输入中有一些错误的类型,只需跳过所有不兼容的内容:

try:
    ix = int(x)
except (ValueError, TypeError):
    continue  # not compatible with int, try the next one
else:
    a.append(ix)

这实际上不是类型检查,但通常具有相同的目的。

  • 保证您的输出中有预期的类型。
  • 它在转换错误类型方面有一些有限的回旋余地,例如专门转换floatint.
  • 它可以在您不知道哪些类型符合int.

主要的缺点是它是一个显式的转换。

  • 您可以默默地接受“错误”值,例如转换str包含文字的 a。
  • 它不必要地转换甚至足够好的类型,例如当你只float需要int数字时。

转换是某些特定用例的有效工具。如果您大致了解您的输入是什么,并且必须对您的输出做出保证,则效果最好。

函数调度

有时类型检查的目标只是选择一个合适的函数。在这种情况下,函数调度例如functools.singledispatch允许针对特定类型专门化函数实现:

@singledispatch
def append_int(value, sequence):
    return

@append_int.register
def _(value: int, sequence):
    sequence.append(value)

这是isinstancedict调度的结合。它对于大型应用程序最有用:

  • 无论分派类型的数量如何,它都会使使用站点保持较小。
  • 它允许以后注册其他类型的特化,即使在其他模块中也是如此。

尽管如此,它并非没有缺点:

  • 许多 Python 程序员起源于函数式和强类型语言,不熟悉单调度甚至多调度。
  • 调度需要单独的功能,因此不适合在使用现场定义。
    • 创建函数和“预热”调度缓存需要显着的运行时开销。调度函数应该定义一次并经常重复使用。
    • 即使是预热的调度表也比手写的 if/else 或dict查找要慢。

控制输入

最好的做法是确保您一开始就不必检查类型。这是一个元主题,因为它在很大程度上取决于用例。

在这里,来源不somelist应该将非数字放入其中。

于 2018-03-02T10:31:16.367 回答
1

您可以像这样简单地使用类型和相等运算符

if (type(x) == int):
于 2020-12-02T05:52:55.617 回答
0

让我声明 int 类型的变量 x

x = 2
if type(x) == type(1) or isinstance(x, int):  
    # do something

两者都工作正常。

于 2018-12-10T09:34:21.817 回答
-1

易于使用的类型。

import types
k = 5
if(type(k)==types.IntType):
   print "int"

这是一个快速目录(类型):

['BooleanType', 'BufferType', 'BuiltinFunctionType', 'BuiltinMethodType', 'ClassType', 'CodeType', 'ComplexType', 'DictProxyType', 'DictType', 'DictionaryType', 'EllipsisType', 'FileType', 'FloatType', 'FrameType', 'FunctionType', 'GeneratorType', 'GetSetDescriptorType', 'InstanceType', 'IntType', 'LambdaType', 'ListType', 'LongType', 'MemberDescriptorType', 'MethodType', 'ModuleType', 'NoneType', 'NotImplementedType', 'ObjectType', 'SliceType', 'StringType', 'StringTypes', 'TracebackType', 'TupleType', 'TypeType', 'UnboundMethodType', 'UnicodeType', 'XRangeType', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
于 2013-01-01T19:39:03.747 回答
-1

您可以在运算符的两侧使用 type 函数。像这样:

if type(x) == type(1):
于 2013-01-01T19:49:11.560 回答