Python 优雅地处理不同的参数类型
我有一个函数,在最简单的情况下,它对一系列的项进行操作Python 优雅地处理不同的参数类型,python,Python,我有一个函数,在最简单的情况下,它对一系列的项进行操作 def foo(items): for item in items: # do stuff 有时,我不想直接向它传递iterable of items,而是希望传递一个提供获取iterable的方法的对象: def foo(obj): for item in obj.iteritems(): # do same stuff as above import collections isins
def foo(items):
for item in items:
# do stuff
有时,我不想直接向它传递iterable of items,而是希望传递一个提供获取iterable的方法的对象:
def foo(obj):
for item in obj.iteritems():
# do same stuff as above
import collections
isinstance(obj, collections.Iterable)
我可以这样合并这两个案例:
def foo(obj):
try:
items = obj.iteritems()
except ValueError:
items = obj
for item in items:
# do stuff
def foo(objs):
for item in itertools.chain.from_iterable(obj.iteritems() for obj in objs):
# do same stuff again
这个很好用。现在我得到了第三个用例,如下所示:
def foo(obj):
try:
items = obj.iteritems()
except ValueError:
items = obj
for item in items:
# do stuff
def foo(objs):
for item in itertools.chain.from_iterable(obj.iteritems() for obj in objs):
# do same stuff again
我仍然可以使用
try-except
方法,因为接口不兼容。但是,嵌套的try-catch将开始变得非常丑陋。当我想添加第四个用例时,情况就更糟了。有没有办法在不嵌套try
-块的情况下解决此问题?要检查对象是否可编辑:
def foo(obj):
for item in obj.iteritems():
# do same stuff as above
import collections
isinstance(obj, collections.Iterable)
这会帮你解决一些问题
此外,处理此类问题的一种方法是使用递归性(但不知道它是否适用):
目前,您可能至少应该在这里使用两种方法,第三种方法只是使用
itertools.chain.from\u iterable
结果调用第一种方法。您还可能使用*args;这取决于你的具体情况(提供一个真实的例子是有帮助的)。还可以使用简单的helper函数返回正确类型的迭代器
也许这可以解决:
def _foo_iter(obj):
try:
return obj.iteritems()
except AttributeError:
return obj
def foo(*objs):
for obj in objs:
for item in _foo_iter(obj):
hasattr(对象、名称)
如果hasattr(对象,'.'uuuu iter'):
返回[o代表obj中的o]
埃利夫·哈斯塔特(obj,“iteritems”):
返回[o代表对象中的o.iteritems()]
elif isinstance(对象,列表)或isinstance(对象,元组):
返回[o.iteritems()表示对象中的o[o表示对象中的o]]
其他:
提高打字错误
分类栏(列表):
定义iteritems(自我):
返回自我
打印foo([1,2,3])
打印foo(Bar([1,2,3]))
打印foo([[1,2,3],[1,2,3]]
印刷字体(1)
[1, 2, 3]
[1, 2, 3]
[[1, 2, 3], [1, 2, 3]]
回溯(最近一次呼叫最后一次):
文件“test.py”,第20行,在
印刷字体(1)
文件“test.py”,第11行,在foo中
提高打字错误
打字错误
必须同意克里斯的观点:魔法理解一切输入都会反过来咬你。如果您将一个对象的iterable和一个iterable的iterable传递给它,那么如何指定在什么级别开始实际处理数据
最好坚持使用“列表或生成器”作为输入,然后预处理对函数的调用。啊,我真希望Python中有适当的函数重载@André:几乎总是在Python中,如果您想要那种函数/方法重载,那么您的做法是错误的。但是显式发送iterable有什么问题?太冗长了?是的。所有的用例都是同样频繁的,其中有些只是太冗长了。@Chris:是的,差不多了。我几乎总能找到更好的选择;-)我见过太多Python类使用
addfoo()
、addbar()
和addmeh()
方法来避免在单个add()
方法中进行运行时类型检查!我提供的代码与真实代码非常接近,只是名称发生了更改。@Space\u C0wb0y:但您没有解释您使用它的准确程度和用途。对于某些事情,可能有一种更好的方法没有出现在您身上(这种情况经常发生,例如,在一个问题中,我使用了一个自定义函数,而x in y
也可以,但由于某种原因,我没有想到)该函数是一个生成器,用于计算每个项目的特定属性。@Space\u C0wb0y:仔细考虑,我认为这实际上正是您所需要的,除非您真的想要foo([a,b,c])
,而不是foo(a,b,c)
,用于您的链案例。通过使用*args,它被放入一个列表中,因此您可以在objs中为obj使用。不管它是否正是您想要的-帮助函数应该是您所需要的,以使代码不那么混乱。@Chris:我也这么认为。感谢您的建议。hasattr
本质上只是一个try
roundgetattr
@chris No,它不强制嵌套异常,例如它更具可读性。这就是问题所在。