[Python-Dev] operator.is*Type

Michael Foord fuzzyman at voidspace.org.uk
Wed Feb 22 22:00:57 CET 2006


Raymond Hettinger wrote:
> [Ian Bicking]
>> They seem terribly pointless to me.
>
> FWIW, here is the script that had I used while updating and improving 
> the two functions (can't remember whether it was for Py2.3 or Py2.4).  
> It lists comparative results for many different types of inputs.  
> Since perfection was not possible, the goal was to have no false 
> negatives and mostly accurate positives.  IMO, they do a pretty good 
> job and are able to access information in not otherwise visable to 
> pure Python code.  With respect to user defined instances, I don't 
> care that they can't draw a distinction where none exists in the first 
> place -- at some point you have to either fallback on duck-typing or 
> be in control of what kind of arguments you submit to your functions. 
> Practicality beats purity -- especially when a pure solution doesn't 
> exist (i.e. given a user defined class that defines just __getitem__, 
> both mapping or sequence behavior is a possibility).
>
But given :

True True Instance w getitem <type 'instance'>
True True NewStyle Instance w getitem <class '__main__.cng'>
True True [] <class UserList.UserList at 0x00F11B70>
True True {} <type 'instance'>

(Last one is UserDict)

I can't conceive of circumstances where this is useful without duck 
typing *as well*.

The tests seem roughly analogous to :

def isMappingType(obj):
    return isinstance(obj, dict) or hasattr(obj, '__getitem__')

def isSequenceType(obj):
    return isinstance(obj, (basestring, list, tuple, collections.deque)) 
or hasattr(obj, '__getitem__')

If you want to allow sequence access you could either just use the 
isinstance or you *have* to trap an exception in the case of a mapping 
object being passed in.

Redefining (effectively) as :

def isMappingType(obj):
    return isinstance(obj, dict) or (hasattr(obj, '__getitem__') and 
hasattr(obj, 'keys'))

def isSequenceType(obj):
    return isinstance(obj, (basestring, list, tuple, collections.deque)) 
or (hasattr(obj, '__getitem__')
        and not hasattr(obj, 'keys'))

Makes the test useful where you want to know you can safely treat an 
object as a mapping (or sequence) *and* where you want to tell the 
difference.

The only code that would break is use of mapping objects that don't 
define ``keys`` and sequences that do. I imagine these must be very rare 
and *would* be interested in seeing real code that does break. 
Especially if that code cannot be trivially rewritten to use the first 
example.

All the best,

Michael Foord
>
> ---- Analysis Script ----
>
> from collections import deque
> from UserList import UserList
> from UserDict import UserDict
> from operator import *
> types = (set,
>         int, float, complex, long, bool,
>         str, unicode,
>         list, UserList, tuple, deque,
> )
>
> for t in types:
>    print isMappingType(t()), isSequenceType(t()), repr(t()), repr(t)
>
> class c:
>    def __repr__(self):
>        return 'Instance w/o getitem'
>
> class cn(object):
>    def __repr__(self):
>        return 'NewStyle Instance w/o getitem'
>
> class cg:
>    def __repr__(self):
>        return 'Instance w getitem'
>    def __getitem__(self):
>        return 10
>
> class cng(object):
>    def __repr__(self):
>        return 'NewStyle Instance w getitem'
>    def __getitem__(self):
>        return 10
>
> def f():
>    return 1
>
> def g():
>    yield 1
>
> for i in (None, NotImplemented, g(), c(), cn()):
>    print isMappingType(i), isSequenceType(i), repr(i), type(i)
>
> for i in (cg(), cng(), dict(), UserDict()):
>    print isMappingType(i), isSequenceType(i), repr(i), type(i)
>
>
>
> ---- Output ----
>
> False False set([]) <type 'set'>
> False False 0 <type 'int'>
> False False 0.0 <type 'float'>
> False False 0j <type 'complex'>
> False False 0L <type 'long'>
> False False False <type 'bool'>
> False True '' <type 'str'>
> False True u'' <type 'unicode'>
> False True [] <type 'list'>
> True True [] <class UserList.UserList at 0x00F11B70>
> False True () <type 'tuple'>
> False True deque([]) <type 'collections.deque'>
> False False None <type 'NoneType'>
> False False NotImplemented <type 'NotImplementedType'>
> False False <generator object at 0x00F230A8> <type 'generator'>
> False False Instance w/o getitem <type 'instance'>
> False False NewStyle Instance w/o getitem <class '__main__.cn'>
> True True Instance w getitem <type 'instance'>
> True True NewStyle Instance w getitem <class '__main__.cng'>
> True False {} <type 'dict'>
> True True {} <type 'instance'>
>
>



More information about the Python-Dev mailing list