如何根据数据类型在 python 中设置条件?
Posted
技术标签:
【中文标题】如何根据数据类型在 python 中设置条件?【英文标题】:How do you set a conditional in python based on datatypes? 【发布时间】:2012-12-16 07:07:42 【问题描述】:这个问题看似简单得令人难以置信,但我想不通。我知道您可以在 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 行,我该如何设置这样的条件?
【问题讨论】:
为什么你的列表中有整数和非整数元素?这是关于什么的? @TokenMacGuy - 没有什么要求列表中的所有元素都是同一类型。 @Paul McGuire:不,该语言当然不会对特定列表的成员强制执行任何特定功能,但另一方面,将类型混合和匹配到一个公共集合中可能表明这些对象并不像将它们放入相同的列表结构所暗示的那样密切相关。有没有比单个列表更好的方法来对这些相关元素进行分组? 【参考方案1】:怎么样,
if isinstance(x, int):
但更清洁的方法就是
sum(z for z in y if isinstance(z, int))
【讨论】:
进一步阅读:Differences between isinstance() and type() in python 是的,非常适合他想做的事情。但是,可能值得指出他的问题的答案是if type(x) == int
,但为什么这是个坏主意。【参考方案2】:
TLDR:
除非您有理由不这样做,否则请使用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 字符串可以是任一str
或unicode
,整数可以是任一int
或long
。李>
请注意,显式类型相等可用于低级操作:
某些类型不能被子类化,例如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
builtin:
if isinstance(x, int):
此检查既准确又高效。这通常是人们想要检查类型的:
它可以正确处理子类型。一个打印漂亮的int
子类仍然可以通过这个测试。
它允许一次检查多种类型。在 Python2 中,执行 isinstance(x, (int, long))
可以获得所有内置整数。
最重要的是,大多数时候缺点可以忽略不计:
它仍然接受行为怪异的时髦子类。由于任何东西都可以以奇怪的方式表现,因此防范是徒劳的。 它很容易过于限制:当任何序列(例如tuple
)甚至可迭代(例如generator
)都可以时,许多人检查isinstance(x, list)
。与脚本或应用程序相比,通用库更需要关注这一点。
变体
如果您已经有一个类型,issubclass
的行为相同:
if issubclass(x_type, int):
抽象类型的实例检查
Python 有一个abstract base classes 的概念。粗略地说,这些表达了类型的含义,而不是它们的层次结构:
if isinstance(x, numbers.Real): # accept anything you can sum up like a number
换句话说,type(x) 不一定继承来自numbers.Real
,但必须表现喜欢它。
不过,这是一个非常复杂和困难的概念:
int
。
来自其他语言的人经常混淆它的概念。
将其与例如C++,重点是 abstract base 类而不是 abstract 基类。
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
。
它甚至会不必要地转换足够好的类型,例如float
到 int
当您只需要数字时。
转换是一些特定用例的有效工具。如果您大致了解您的输入是什么,并且必须对您的输出做出保证,则效果最好。
函数调度
有时类型检查的目标只是选择一个合适的函数。在这种情况下,functools.singledispatch
之类的函数调度允许针对特定类型专门化函数实现:
@singledispatch
def append_int(value, sequence):
return
@append_int.register
def _(value: int, sequence):
sequence.append(value)
这是isinstance
和dict
调度的组合。它对大型应用程序最有用:
不过,它并非没有缺点:
源于函数式和强类型语言,许多 Python 程序员不熟悉单调度甚至多调度。 调度需要单独的函数,因此不适合在使用现场定义。 创建函数和“预热”调度缓存需要显着的运行时开销。调度函数应该定义一次并经常重复使用。 即使是预热的调度表也比手写的 if/else 或dict
查找要慢。
控制输入
最好的做法是确保您从一开始就不必检查类型。这有点像元主题,因为它在很大程度上取决于用例。
这里,somelist
的来源不应该将非数字放入其中。
【讨论】:
【参考方案3】:让我声明 int 类型的变量 x
x = 2
if type(x) == type(1) or isinstance(x, int):
# do something
两者都可以正常工作。
【讨论】:
【参考方案4】:你可以像这样简单地使用类型和相等运算符
if (type(x) == int):
【讨论】:
【参考方案5】:易于使用的类型。
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(u"testing") == type("testing")
,即使它们都是字符串。
哇——你能解释一下这是为什么吗?我对你的逻辑有点困惑。这不是一段生产代码,只是一个如何使用库的示例。
比较类型不会处理子类,甚至不会处理自定义类的实例,或者如示例所示,unicode vs string 类型,也会使情况复杂化
这纯粹是出于好奇,而不是争论 - 但是如果您只是在搜索整数而不是比较类型,您会检查 types.IntType (或其他一些集合类型)吗?出于对效率的渴望,我很想这样做。想看看你有什么建议。
@JakobBowyer:type(u"") != type("")
。您应该在提出此类声明之前进行检查。【参考方案6】:
您可以在运算符的两侧使用类型函数。像这样:
if type(x) == type(1):
【讨论】:
不!这是一个非常糟糕的主意,例如type(u"testing") == type("testing")
,即使它们都是字符串。以上是关于如何根据数据类型在 python 中设置条件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 css 或 js 根据 vue.js 中的条件在打印页面中设置不显示?