在Python中区分标量,列表和字典参数的最佳方法是什么?

时间:2013-04-24 20:49:02

标签: python types python-2.7 polymorphism

我想要一个通常接受X类型参数的函数,其中X是标量,列表或dict,并根据其他信息返回具有相同键值的X列表。

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')

我的问题是,如何在三种类型之间进行调度?


编辑:字符串将被解释为标量,而不是列表/可迭代。元组将被解释为可迭代的。

编辑2:我想要打字,而不是严格打字。

7 个答案:

答案 0 :(得分:5)

您需要按正确的顺序执行操作,因为strdict类型是可迭代的。

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]

答案 1 :(得分:3)

这取决于您希望对输入的严格程度。 isinstance方法强制您指定要接受的类型(即,没有鸭子类型)。只要您的用户只传递这些类的类或子类,它就可以工作。您还可以尝试通过它们支持的方法区分参数。这方面的一个例子是

修改:添加字符串的特殊情况

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]

控制流的选择取决于您希望的灵活程度,以及您希望如何处理模棱两可的案例。例如,字符串是一系列字符还是标量?

答案 2 :(得分:2)

使用新的花哨的东西:)导入集合

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

您还应该考虑查看types模块

答案 3 :(得分:0)

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

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

elif isinstance(keydata,dict):#dictionary

也许?? (我可能错过了几种类型)......

答案 4 :(得分:0)

或者您可以使用类型,但根据http://docs.python.org/2/library/functions.html#type

建议使用isinstance
if type(asd) in (int, str):
    print 'asd is int or str'

答案 5 :(得分: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)

答案 6 :(得分:0)

def is_scalar(x):
    return hasattr(x, 'lower') or not hasattr(x, '__iter__')

然后你永远不必担心isinstance失败,因为有人实现了一个可疑的迭代子类。