繁体   English   中英

你如何根据数据类型在python中设置条件?

[英]How do you set a conditional in python based on datatypes?

这个问题看起来很简单,但我想不通。 我知道您可以在 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 行,我将如何设置这样的条件?

怎么样,

if isinstance(x, int):

但更清洁的方法就是

sum(z for z in y if isinstance(z, int))

域名注册地址:

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

在 Python 中进行类型检查有一个非常大的“取决于”。 处理类型的方法有很多种,各有优缺点。 在 Python3 中,出现了更多。

显式类型相等

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

if type(x) is int:

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

  • 它排除了替代类型: float是无效的,即使它在许多用途上表现得像一个int
  • 它排除了子类和抽象类型:即使它们在逻辑上是整数,也会拒绝打印漂亮的int子类或enum
    • 这严重限制了便携性:Python2字符串可以strunicode ,并且整数可以intlong

需要注意的是显式类型的平等其低级别操作的用途:

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

变体

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

if x.__class__ is int:

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

当有多个类要检查时,使用dict来分派动作比显式检查更具可扩展性并且可以更快(≥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 中,执行isinstance(x, (int, long))可以获得所有内置整数。

最重要的是,在大多数情况下,缺点可以忽略不计:

  • 它仍然接受行为怪异的时髦子类。 由于任何事物都可能以奇怪的方式运行,因此无法防范。
  • 它很容易变得过于严格:许多人在任何序列(例如tuple )甚至可迭代(例如generator )也可以这样做时检查isinstance(x, list) 对于通用库而言,这比脚本或应用程序更值得关注。

变体

如果您已经有一个类型,则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继承,但必须表现得像它。 尽管如此,这是一个非常复杂和困难的概念:

  • 如果您正在寻找基本类型,这通常是矫枉过正。 大多数情况下,Integer 只是一个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)

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

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

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

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

转换是某些特定用例的有效工具。 如果您粗略地知道您的输入是什么,并且必须保证您的输出,则效果最佳。

函数调度

有时类型检查的目标只是选择一个合适的函数。 在这种情况下,诸如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的来源somelist应该将非数字放入其中。

让我声明 int 类型的变量 x

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

两者都工作正常。

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

if (type(x) == int):

易于使用的类型。

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__']

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

if type(x) == type(1):

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM