我想要一个通常接受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:我想要打字,而不是严格打字。
答案 0 :(得分:5)
您需要按正确的顺序执行操作,因为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]
答案 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
建议使用isinstanceif 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
失败,因为有人实现了一个可疑的迭代子类。