Best way to distinguish scalar, list, and dict arguments in Python?

I want a function that usually takes an argument of type X, where X is either a scalar, or a list, or a dict, and returns a list X with the same key values ​​based on other information.

def foo(info, k):
   return [bar(item,k) for item in processInfo(info)]

def bar(item, keydata):
   # pseudocode follows.
   # What we want to do is return an output of parallel type to the input key k,
   # using the key data to lookup information from the input item.
   if keydata is a scalar:
      return item[keydata]
   elif keydata is a list:
      return [item[k] for k in keydata]
   elif keydata is a dict:
      return dict((k,item[v]) for (k,v) in keydata.iteritems())
   else:
      raise ValueError('bar expects a scalar, list, or dict')

My question is: how can I send between the three types?


edit: The string should be interpreted as a scalar, not a list / iterable. Tuples must be interpreted as iterable.

edit 2: I want the duck to print, not strict typing.

+5
source share
7 answers

, . isinstance , (I.e., no duck-typing). , . , .

:

if isinstance(keydata, basestring):
    # special case to avoid considering strings as containers
    # for python 3.x use str instead of basestring
    return item[keydata]
try:
    return dict((k,item[v]) for (k,v) in keydata.iteritems())
except AttributeError:
    # it not a dict-like
    pass
try:
    return [item[k] for k in keydata]
except TypeError:
    # it not iterable
return item[keydata]

, , . , ?

+3

- , str dict .

from collections import Iterable, Mapping  # in Python 3 use from collections.abc

def bar(item, keydata):
    if isinstance(keydata, Mapping):
        return {k: item[v] for (k,v) in keydata.iteritems()}
    elif isinstance(keydata, Iterable) and not isinstance(keydata, str):
        return [item[k] for k in keydata]
    return item[keydata]
+5

:)

>>> isinstance([], collections.Sequence)
True
>>> isinstance({}, collections.Mapping)
True

types

+2
if isinstance(keydata,(int,float,str)): #scalar

elif isinstance(keydata,(list,tuple)):#iterable

elif isinstance(keydata,dict):#dictionary

?? (Im, , )...

0

, isinstance http://docs.python.org/2/library/functions.html#type

if type(asd) in (int, str):
    print 'asd is int or str'
0

!

, keydata :

def asKVlists(keydata):
    # return a tuple (keys, values, isScalar)
    # where keys and values are iterable
    if not isinstance(keydata, basestring):
        # check for dict behavior:
        try:
            return zip(*keydata.iteritems()) + [False]
        except AttributeError:
            pass

        # otherwise check for list behavior
        # make sure we can iterate over it
        try:
            iter(keydata)
            return (None, keydata, False)
        except TypeError:
            pass
    return (None, (keydata,), True)
0
def is_scalar(x):
    return hasattr(x, 'lower') or not hasattr(x, '__iter__')

isinstance - , - - .

0

All Articles