【问题标题】:How to perform different actions depending on parameter type如何根据参数类型执行不同的操作
【发布时间】:2014-11-23 13:24:20
【问题描述】:

在像 java 这样使用静态绑定的语言中,您可以定义多个具有相同名称但参数不同的函数。学习 Python,直到现在我认为缺少这个主要是“安全问题”(比如 bool_parameter="False" 可能被解释为 True 因为引号)。我想我只是需要更加小心。

现在我发现了一种情况,缺少静态绑定简直不方便。请考虑这个元组:

var = ((1, "foo"), (2, "bar"), (3, "potato"))

要使用静态绑定从var 中删除项目,可以执行以下操作(伪代码:

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 子句。

有没有更好的办法?

【问题讨论】:

  • 你总是可以对一个类进行删除操作,所以你只需要求它删除,它的内部就会负责具体的删除操作。
  • 这是两个不同的删除。第一个查找第一个元素,第二个查找第二个参数。通常这种删除发生在完全不同的情况下,因此 del_on_first_element 和 del_on_second_element 方法比类型重载要清晰得多。

标签: python dynamic-binding static-binding


【解决方案1】:

Python 没有方法重载,因此抱歉,您必须检查参数的类型。

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?

【讨论】:

  • 我喜欢这个答案,因为它指出,我的假设(最初不是有意的)实际上就是这种情况。但是,@deets 显示了一种解决方法,这也很好。我会多想一下我应该接受哪些答案......
【解决方案2】:

看看这个问题:Differences between isinstance() and type() in python

如果您最终采用建议的 if 类型方法,您可能需要考虑使用鸭子类型或 isinstance 替代方法

【讨论】:

    【解决方案3】:

    您的问题可以通过使用通用方法/函数来解决。这些不是 python 内置的,但可以通过 3rd-party 库或您自己编写一个来使用。

    几年前我一直在愉快地使用 PEAK 规则,但虽然它应该仍然有效,但它似乎有点失宠了。

    新的 PEP 443(单参数调度)伴随着外部实现,singledispatch。 https://pypi.python.org/pypi/singledispatch/3.4.0.3

    这样,你的问题可以这样解决:

     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 中存在的问题并不是真的很容易解决。但是,您提供了一个很好的解决方法。我喜欢你的回答和@DanielGibbs 的回答。我会再考虑一下我应该接受哪个答案。
    • 我会根据此类问题发生的频率来做出决定,因此有理由引入一种新的惯用方法来解决它。代码的阅读次数多于编写次数 - 无需进一步的基于类型的分派知识就可以理解 Daniel 的答案。让您对此做出判断。
    • 我还听说python3中将引入某种可选的静态类型。但是,我没有找到关于这一点的真实证据。
    • 这些谣言是错误的——存在的是(可选的)类型注释系统:docs.python.org/3/tutorial/… 优化编译器可以使用它,以及通用函数机制——但我不知道实际使用中。
    【解决方案4】:

    您给出的特殊情况似乎不需要重载。

    def del_item(id):
        return tuple(item for item in var if not id in item)
    

    另一种选择是使用可选的关键字参数

    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 重载的问题,this is one answer 可能有助于理解为什么没有它不会被视为问题。

    【讨论】:

      猜你喜欢
      • 2017-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2021-10-04
      • 2012-07-04
      • 1970-01-01
      相关资源
      最近更新 更多