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? 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?


How about,

if isinstance(x, int):

but a cleaner way would simply be

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

There is a really big "it depends" to type-checking in Python. There are many ways to deal with types, and all have their pros and cons. With Python3, several more have emerged.

  • 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:

    if type(x) == 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 many purposes.
  • It rules out subclasses and abstract types: a pretty-printing int subclass or enum would be rejected, even though they are logically Integers.
  • This severely limits portability: Python2 Strings can be either str or unicode , and Integers can be either int or long .
  • Note that explicit type equality has its uses for low-level operations:

  • Some types cannot be subclassed, such as slice . An explicit check is, well, more explicit here.
  • Some low-level operations, such as serialisation or C-APIs, require specific types.
  • Variants

    A comparison is slightly faster when performed with __class__ :

    if x.__class__ == int:
    

    When there are multiple classes to check for, using a dict to dispatch actions is considerably faster than explicit checks. 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:

    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.
  • It allows checking multiple types at once. In Python2, doing isinstance(x, (int, long)) gets you all builtin integers.
  • 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. This is more of a concern for general purpose libraries than scripts or applications.
  • Variants

    If you already have a type, issubclass behaves the same:

    if issubclass(x_type, int):
    
  • Instance check in abstract type
  • Python has a concept of abstract base classes. Loosely speaking, these express the meaning of types, not their hierarchy:

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

    In other words, type(x) does not necessarily inherit from numbers.Real but must behave like it. 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.
  • 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.
  • 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. By contrast, collections.abc.Mapping also includes database wrappers, large disk-backed dictionaries, lazy containers, ..., and 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.
  • 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.

  • 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 .
  • It works without you knowing which types conform to int .
  • The major downside is that it is an explicit transformation.

  • You can silently accept "wrong" values, eg converting a str containing a literal.
  • It needlessly converts even types that would be good enough, eg float to int when you just need numbers.
  • 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.

  • 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.


    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__']
    
    链接地址: http://www.djcxy.com/p/54242.html

    上一篇: 抽象类和接口之间有什么区别?

    下一篇: 你如何在基于数据类型的python中设置条件?