Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want a function that normally takes in an argument of type X where X is either a scalar, a list, or a dict, and returns a list of X's 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 dispatch between the three types?


edit: A string is to be interpreted as a scalar, not a list/iterable. Tuples are to be interpreted as iterable.

edit 2: I want duck typing, not strict typing.

like image 526
Jason S Avatar asked Apr 24 '13 20:04

Jason S


People also ask

What is the most significant distinction between a dictionary and a list in Python?

But what's the difference between lists and dictionaries? A list is an ordered sequence of objects, whereas dictionaries are unordered sets. However, the main difference is that items in dictionaries are accessed via keys and not via their position.

Which is the most accurate way to determine the type of a variable Python?

One of the best ways to obtain the variable type is to use the type() function. Every value in Python has a datatype. Everything is an object in Python programming, and data types are classes, and variables are the instance (object) of these classes.

Should I use dict () or {}?

With CPython 2.7, using dict() to create dictionaries takes up to 6 times longer and involves more memory allocation operations than the literal syntax. Use {} to create dictionaries, especially if you are pre-populating them, unless the literal syntax does not work for your case.

When should you use a dictionary rather than a list in Python?

Use a dictionary when you have a set of unique keys that map to values. Use a list if you have an ordered collection of items. Use a set to store an unordered set of items.


3 Answers

You need to do things in the proper order since str and dict types are iterable.

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]
like image 96
Mark Ransom Avatar answered Nov 14 '22 22:11

Mark Ransom


It depends on how strict you want to be with your input. The isinstance approach forces you to specify the types to accept (I.e., no duck-typing). It works as long as your users are only passing in those classes or subtypes of those classes. You can also try to distinguish parameters by the methods they support. An example of this would be

Edit: added the special case for strings

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's not a dict-like
    pass
try:
    return [item[k] for k in keydata]
except TypeError:
    # it's not iterable
return item[keydata]

The choice of control flow depends on how flexible you want to be, and also how you want yo deal with ambiguous cases. Eg, is a string considered a sequence of characters or a scalar?

like image 22
Felipe Avatar answered Nov 14 '22 23:11

Felipe


Use the new fancy stuff :) by import collections

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

You should also consider looking at the types module

like image 40
Meitham Avatar answered Nov 14 '22 22:11

Meitham