简体   繁体   English

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

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

This question seems mind-boggling simple, yet I can't figure it out.这个问题看起来很简单,但我想不通。 I know you can check datatypes in python, but how can you set a conditional based on the datatype?我知道您可以在 python 中检查数据类型,但是如何根据数据类型设置条件? For instance, if I have to write a code that sorts through a dictionary/list and adds up all the integers, how do I isolate the search to look for only integers?例如,如果我必须编写一个对字典/列表进行排序并将所有整数相加的代码,我如何隔离搜索以仅查找整数?

I guess a quick example would look something like this:我想一个简单的例子看起来像这样:

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

So for line 3, how would I set such a conditional?那么对于第 3 行,我将如何设置这样的条件?

How about,怎么样,

if isinstance(x, int):

but a cleaner way would simply be但更清洁的方法就是

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

TLDR:域名注册地址:

  • Use if isinstance(x, int): unless you have a reason not to.使用if isinstance(x, int):除非你有理由不这样做。
  • Use if type(x) is int: if you need exact type equality and nothing else. if type(x) is int:如果您需要精确的类型相等而不是其他任何东西。
  • Use try: ix = int(x) if you are fine with converting to the target type.如果您可以转换为目标类型,请使用try: ix = int(x)

There is a really big "it depends" to type-checking in Python.在 Python 中进行类型检查有一个非常大的“取决于”。 There are many ways to deal with types, and all have their pros and cons.处理类型的方法有很多种,各有优缺点。 With Python3, several more have emerged.在 Python3 中,出现了更多。

Explicit type equality显式类型相等

Types are first-class objects, and you can treat them like any other value.类型是一流的对象,您可以像对待任何其他值一样对待它们。 So if you want the type of something to be equal to int , just test for it:因此,如果您希望某事物的类型等于int ,只需对其进行测试:

if type(x) is int:

This is the most restrictive type of testing: it requires exact type equality.这是最严格的测试类型:它需要精确的类型相等。 Often, this is not what you want:通常,这不是您想要的:

  • It rules out substitute types: a float would not be valid, even though it behaves like an int for many purposes.它排除了替代类型: float是无效的,即使它在许多用途上表现得像一个int
  • It rules out subclasses and abstract types: a pretty-printing int subclass or enum would be rejected, even though they are logically Integers.它排除了子类和抽象类型:即使它们在逻辑上是整数,也会拒绝打印漂亮的int子类或enum
    • This severely limits portability: Python2 Strings can be either str or unicode , and Integers can be either int or long .这严重限制了便携性:Python2字符串可以strunicode ,并且整数可以intlong

Note that explicit type equality has its uses for low-level operations:需要注意的是显式类型的平等其低级别操作的用途:

  • Some types cannot be subclassed, such as slice .某些类型不能被子类化,例如slice An explicit check is, well, more explicit here.明确的检查在这里更明确。
  • Some low-level operations, such as serialisation or C-APIs, require specific types.一些低级操作,例如序列化或 C-API,需要特定类型。

Variants变体

A comparison can also be performed against the __class__ attribute:也可以对__class__属性进行比较:

if x.__class__ is int:

Note if a class defines a __class__ property, this is not the same as type(x) .请注意,如果类定义了__class__属性,则这与type(x)

When there are several classes to check for, using a dict to dispatch actions is more extensible and can be faster (≥5-10 types) than explicit checks.当有多个类要检查时,使用dict来分派动作比显式检查更具可扩展性并且可以更快(≥5-10 类型)。 This is especially useful for conversions and serialisation:这对于转换和序列化特别有用:

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)

Instance check on explicit types显式类型的实例检查

The idiomatic type test uses the isinstance builtin :惯用类型测试使用isinstance内置

if isinstance(x, int):

This check is both exact and performant.这种检查既准确又高效。 This is most often what people want for checking types:这通常是人们想要检查类型的内容:

  • It handles subtypes properly.它正确处理子类型。 A pretty-printing int subclass would still pass this test.打印漂亮的int子类仍将通过此测试。
  • It allows checking multiple types at once.它允许一次检查多种类型。 In Python2, doing isinstance(x, (int, long)) gets you all builtin integers.在 Python2 中,执行isinstance(x, (int, long))可以获得所有内置整数。

Most importantly, the downsides are negligible most of the time:最重要的是,在大多数情况下,缺点可以忽略不计:

  • It still accepts funky subclasses that behave in weird ways.它仍然接受行为怪异的时髦子类。 Since anything can be made to behave in weird ways, this is futile to guard against.由于任何事物都可能以奇怪的方式运行,因此无法防范。
  • It can easily be too restrictive: many people check for isinstance(x, list) when any sequence (eg tuple ) or even iterable (eg a generator ) would do as well.它很容易变得过于严格:许多人在任何序列(例如tuple )甚至可迭代(例如generator )也可以这样做时检查isinstance(x, list) This is more of a concern for general purpose libraries than scripts or applications.对于通用库而言,这比脚本或应用程序更值得关注。

Variant变体

If you already have a type, issubclass behaves the same:如果您已经有一个类型,则issubclass行为相同:

if issubclass(x_type, int):

Instance check on abstract type抽象类型的实例检查

Python has a concept of abstract base classes . Python 有一个抽象基类的概念。 Loosely speaking, these express the meaning of types, not their hierarchy:粗略地说,这些表达了类型的含义,而不是它们的层次结构:

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

In other words, type(x) does not necessarily inherit from numbers.Real but must behave like it.换句话说, type(x) 不一定从numbers.Real继承,但必须表现得像它。 Still, this is a very complex and difficult concept:尽管如此,这是一个非常复杂和困难的概念:

  • It is often overkill if you are looking for basic types.如果您正在寻找基本类型,这通常是矫枉过正。 An Integer is simply an int most of the time.大多数情况下,Integer 只是一个int
  • People coming from other languages often confuse its concepts.来自其他语言的人经常混淆它的概念。
    • Distinguishing it from eg C++, the emphasis is abstract base class as opposed to abstract base class.将其与例如 C++ 区分开来,重点是抽象基类而不是抽象基类。
    • ABCs can be used like Java interfaces, but may still have concrete functionality. ABC 可以像 Java 接口一样使用,但可能仍然具有具体的功能。

However, it is incredibly useful for generic libraries and abstractions.但是,它对于通用库和抽象非常有用。

  • Many functions/algorithms do not need explicit types, just their behaviour.许多函数/算法不需要显式类型,只需要它们的行为。
    • If you just need to look up things by key, dict restricts you to a specific in-memory type.如果您只需要按键查找内容, dict您限制为特定的内存类型。 By contrast, collections.abc.Mapping also includes database wrappers, large disk-backed dictionaries, lazy containers, ... - and dict .相比之下, collections.abc.Mapping还包括数据库包装器、大型磁盘支持的字典、惰性容器、... - 和dict
  • It allows expressing partial type constraints.它允许表达部分类型约束。
    • There is no strict base type implementing iteration.没有严格的基本类型实现迭代。 But if you check objects against collections.abc.Iterable , they all work in a for loop.但是如果你根据collections.abc.Iterable检查对象,它们都在for循环中工作。
  • It allows creating separate, optimised implementations that appear as the same abstract type.它允许创建单独的、优化的实现,这些实现显示为相同的抽象类型。

While it is usually not needed for throwaway scripts, I would highly recommend using this for anything that lives beyond a few python releases.虽然一次性脚本通常不需要它,但我强烈建议将它用于除几个 Python 版本之外的任何内容。

Tentative conversion暂定转换

The idiomatic way of handling types is not to test them, but to assume they are compatible.处理类型的惯用方式不是测试它们,而是假设它们是兼容的。 If you already expect some wrong types in your input, simply skip everything that is not compatible:如果您已经预料到输入中有一些错误的类型,只需跳过所有不兼容的内容:

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

This is not actually a type check, but usually serves the same intention.这实际上不是类型检查,但通常用于相同的目的。

  • It guarantees you have the expected type in your output.保证您在输出中具有预期的类型。
  • It has some limited leeway in converting wrong types, eg specialising float to int .它在转换错误类型方面有一些有限的回旋余地,例如将float专门化为int
  • It works without you knowing which types conform to int .它可以在您不知道哪些类型符合int

The major downside is that it is an explicit transformation.主要的缺点是它是一个显式转换。

  • You can silently accept "wrong" values, eg converting a str containing a literal.您可以默默地接受“错误”值,例如转换包含文字的str
  • It needlessly converts even types that would be good enough, eg float to int when you just need numbers.它不必要地转换甚至足够好的类型,例如,当您只需要数字时,将floatint

Conversion is an effective tool for some specific use cases.转换是某些特定用例的有效工具。 It works best if you know roughly what your input is, and must make guarantees about your output.如果您粗略地知道您的输入是什么,并且必须保证您的输出,则效果最佳。

Function dispatch函数调度

Sometimes the goal of type checking is just to select an appropriate function.有时类型检查的目标只是选择一个合适的函数。 In this case, function dispatch such as functools.singledispatch allows specialising function implementations for specific types:在这种情况下,诸如functools.singledispatch函数调度允许对特定类型进行专门的函数实现:

@singledispatch
def append_int(value, sequence):
    return

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

This is a combination of isinstance and dict dispatch.这是isinstancedict调度的组合。 It is most useful for larger applications:它对于较大的应用程序最有用:

  • It keeps the site of usage small, regardless of the number of dispatched types.无论调度类型的数量如何,它都会使使用站点保持较小。
  • It allows registering specialisations for additional types later, even in other modules.它允许稍后为其他类型注册特化,甚至在其他模块中。

Still, it doesn't come without its downsides:尽管如此,它也并非没有缺点:

  • Originating in functional and strongly typed languages, many Python programmers are not familiar with single- or even multiple-dispatch.许多 Python 程序员起源于函数式和强类型语言,并不熟悉单分派甚至多分派。
  • Dispatches require separate functions, and are therefore not suitable to be defined at the site of usage.调度需要单独的功能,因此不适合在使用地点定义。
    • Creating the functions and "warming up" the dispatch cache takes notable runtime overhead.创建函数和“预热”调度缓存需要显着的运行时开销。 Dispatch functions should be defined once and re-used often.调度函数应该定义一次并经常重复使用。
    • Even a warmed up dispatch table is slower than a hand-written if/else or dict lookup.即使是预热的调度表也比手写的 if/else 或dict查找慢。

Controlling the input控制输入

The best course of action is to ensure you never have to check for type in the first place.最好的做法是确保您永远不必首先检查类型。 This is a bit of a meta-topic, as it depends strongly on the use case.这有点像元主题,因为它在很大程度上取决于用例。

Here, the source of somelist should never have put non-numbers into it.在这里, somelist的来源somelist应该将非数字放入其中。

let me declare variable x of type int让我声明 int 类型的变量 x

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

Both works fine.两者都工作正常。

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

if (type(x) == int):

Easy - use types.易于使用的类型。

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

Here's a quick dir(types):这是一个快速目录(类型):

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

You can use the type function on both sides of the operator.您可以在运算符的两侧使用 type 函数。 Like this:像这样:

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

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

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