How to perform different actions depending on parameter type
在使用Java静态绑定的语言中,可以定义具有相同名称但不同参数的多个函数。学习python之前,我认为缺乏这一点主要是"安全问题"(比如
现在我发现了一种情况,缺乏静态绑定是非常不方便的。请考虑这个图佩尔:
1 | var = ((1,"foo"), (2,"bar"), (3,"potato")) |
要从带有静态绑定的
1 2 3 4 5 6 7 | def del_item(int i): # search item with (x == i, *) # remove this item def del_item(String s): # search item with (*, x == s) # remove this item |
我觉得这很方便,因为不需要任何条件来选择要执行的正确操作。此外,此代码使重载更容易,因为您可以决定只重载其中一个函数或两者。
尝试在Python中处理这样的情况,我只发现一些不方便的解决方案,比如检查类型的if子句。
有更好的方法吗?
python没有方法重载,所以您必须检查参数的类型抱歉。
1 2 3 4 5 6 7 8 9 | def del_item(item): if type(item) is int: # search item with (x == item, *) # remove this item elif type(item) is str: # search item with (*, x == s) # remove this item else: # Maybe raise an exception? |
您的问题可以通过使用通用方法/函数来解决。这些不是内置于Python中的,但可以由第三方库或您自己编写一个库来连接。
几年前,我一直在和Peak规则一起愉快地工作,但尽管它仍然可以工作,但它似乎有点失宠了。
新的PEP443(单参数调度)伴随着外部实现single dispatch。https://pypi.python.org/pypi/singledispatch/3.4.0.3
有了这个,你的问题就可以这样解决了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | from functools import partial from singledispatch import singledispatch var = ((1,"foo"), (2,"bar"), (3,"potato")) @singledispatch def del_predicate(value): pass @del_predicate.register(int) def _(v, candidate): return v == candidate[0] @del_predicate.register(str) def _(v, candidate): return v == candidate[1] def neg(f): def _f(*args): return not f(*args) return _f print filter(neg(partial(del_predicate,"foo")), var) print filter(neg(partial(del_predicate, 2)), var) |
看看这个问题:Python中isInstance()和type()的区别
如果您最终采用了建议的if-type方法,那么您可能需要考虑duck类型或isinstance替代方法。
您给出的特定情况似乎是无论如何都不需要重载的情况。
1 2 | def del_item(id): return tuple(item for item in var if not id in item) |
另一种选择是使用可选的关键字参数
1 2 3 4 | def del_item(string_id=None, number_id=None): if string_id is not None: return tuple(item for item in var if not item[1] == string_id) return tuple(item for item in var if not item[0] == number_id) |
前面有很多关于Python重载的问题,这是一个可能有助于理解为什么不将其视为问题的答案。