【问题标题】:How can we make a function do different things based on the nature of its input?我们如何让一个函数根据其输入的性质做不同的事情?
【发布时间】:2022-08-24 08:22:03
【问题描述】:

我们有一个名为funky_the_function 的函数。

funky_the_function 应该根据标准测试其输入,然后根据测试结果调用其他函数。

以下是测试谓词的一些示例:

class Predicates: 
    @classmethod
    def is_numeric_string(cls, chs:str) -> bool:
        \"\"\"
        +-----------------+--------+
        |      INPUT      | OUTPUT |
        +-----------------+--------+
        | \"9821\"          | True   |
        | \"3038739984\"    | True   |
        | \"0\"             | True   |
        | \"3.14\"          | False  |
        | \"orange\"        | False  |
        | \"kiwi 5 pear 0\" | False  |
        +-----------------+--------+
        \"\"\"
        return all([ch in string.digits for ch in chs])

    @classmethod
    def is_just_one_thing(cls, thing):
        \"\"\"
        This function returns a boolean (True/False)

        `thing` is defined to just one thing only,
                not many things if str(thing)
                is the same as the concatenation
                of the to-stringed versions
                of all of its elements

                (The whole is the sum of its parts)

        +--------------------------+--------+   
        |          INPUT           | OUTPUT |
        |--------------------------|--------|
        | int(4)                   | True   |
        | str(4)                   | True   |
        | float(9.17)              | True   |
        | str(\"ABCDE\")             | True   |
        | [int(1), str(2), int(3)] | False  |
        | (8, 3)                   | False  |
        | [8]                      | False  |
        | [\"A\", \"B\", \"C\"]          | False  |
        +--------------------------+--------+
        \"\"\"
        if hasattr(thing, \"__iter__\"):
            return str(thing) == \"\".join(str(elem) for elem in thing)
        else:  # thing is not iterable
            return True

我们有几个不同版本的函数,应该调用哪个版本的函数取决于输入的内容。

有一个很长的if-else 块似乎有点难看。

def funky_the_function(*args):   
    if test_one(args): 
        return funky_the_function_one(*args)
    elif test_two(args): 
        return funky_the_function_two(*args)
    elif test_three(args): 
        return funky_the_function_three(*args)
    elif test_three(args): 
        return funky_the_function_four(*args)
    elif test_four(args): 
        return funky_the_function_four(*args)
    else:
        raise ValueError()

python 的functools 库中的@singledispatchmethod 与我们想​​要的类似,但@singledispatchmethod 根据输入数据类型(intfloatstr 等)决定调用哪个函数。 ..)。 @singledispatchmethod 无法根据任意标准决定调用哪个函数,例如isinstance(arg, (list, tuple)) and len(arg) = 2

我们如何重载基于任意谓词的函数?

我们如何在 python 中实现Predicate Dispatching

    标签: python-3.x design-patterns polymorphism operator-overloading dispatch


    【解决方案1】:

    假设有八种不同形式的funky_the_function 函数。

    我们可以:

    • 编写funky_the_function的八个不同实现
    • 编写八个不同的测试谓词
    • 编写八个不同的类。

    之后我们可以编写一个funky_the_function 函数:

    1. 测试其输入。
    2. 根据测试结果,将输入传递给几个不同的类构造函数之一
    3. 使用来自 python 的 functools 库的 @singledispatchmethod 进行调度
      from functools import singledispatch
      
      class ArgsOne:
         pass
      
      class ArgsTwo:
         pass  
      
      def funky_the_function(*args):   
          if test_one(args): 
              obj = ArgsOne(args)
              return _funky_the_function(obj)
          elif test_two(args): 
              obj = ArgsTwo(args)
              return _funky_the_function(obj)
      
      @singledispatch
      def _funky_the_function():
          pass
      
      @_funky_the_function.register
      def _(arg:ArgsOne):
          print("implementation one")
          
      @_funky_the_function.register
      def _(arg:ArgsTwo):
          print("implementation one")
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多