【问题标题】:how to implement a function like sum(2)(3)(4)......(n) in python?如何在 python 中实现 sum(2)(3)(4)......(n) 之类的函数?
【发布时间】:2016-03-18 03:19:09
【问题描述】:

如何在python中实现一个会以如下方式sum_numbers(2)(3)(4)......(n)调用的函数?

结果应该是2+3+4+.....+n

我得到的提示是,由于函数是 python 中的对象,因此可以使用嵌套函数来执行这些操作,但我不确定。

def sum_number(x):
    def sum_number_2(y):
        def sum_number_3(z):
        ....................
            def sum_number_n(n)
                return n
            return sum_number_n
        return sum_number_3
    return sum_number_2
  return sum_number

但是,与其编写这么多嵌套函数,我们应该能够在以以下方式调用时在几个嵌套函数中计算 n 个值的总和 sum_numbers(2)(3)(4)......(n)

【问题讨论】:

  • sum([2,3,4,...,n]) 工作正常...
  • sum(i for i in range(2,n+1)) 应该可以工作
  • @user1870400 你的请求的问题是如果sum(x)返回一个函数,你如何得到最终的和?
  • 也许如果您在问题中展示您学到的知识,我们可以帮助您更好地理解。照原样,你写的不能同时返回一个函数和一个值
  • 因为你的函数不知道第n次调用是为了返回最终值

标签: python functional-programming higher-order-functions


【解决方案1】:

使用 Python 的数据模型功能将结果转换为所需的类型。

class sum_number(object):
  def __init__(self, val):
    self.val = val

  def __call__(self, val):
    self.val += val
    return self

  def __float__(self):
    return float(self.val)

  def __int__(self):
    return int(self.val)

print '{}'.format(int(sum_number(2)(3)(8)))
print '{}'.format(float(sum_number(2)(3)(8)))

【讨论】:

    【解决方案2】:

    您可以创建一个可调用的 int 子类:

    class sum_numbers (int):
        def __new__ (cls, *args, **kwargs):
            return super().__new__(cls, *args, **kwargs)
    
        def __call__ (self, val):
            return sum_numbers(self + val)
    

    这样,您就可以完全兼容普通整数(因为该类型的对象普通整数),因此以下示例有效:

    >>> sum_numbers(2)(3)(4)(5)
    14
    >>> isinstance(sum_numbers(2)(3), int)
    True
    >>> sum_numbers(2)(3) + 4
    9
    

    当然,您可能想要覆盖其他方法,例如__add__ 这样添加一个普通整数仍然会返回您类型的对象。否则,您将不得不使用结果调用类型,例如:

    >>> sum_numbers(sum_numbers(2)(3) + 5)(6)
    16
    

    【讨论】:

      【解决方案3】:

      如果您的函数返回另一个函数,您不能只是将调用链接在一起并期望得到人类可读的结果。如果你想要一个没有最终结果的函数,可以做你想做的事,这行得通:

      def sum(x):
          def f(y):
              return sum(x+y)
          return f
      

      如果你可以打印出操作,你可以试试这个:

      def sum(x):
          print(x)
          def f(y):
              return sum(x+y)
          return f
      

      如果您绝对、绝对需要返回值,那么您可以尝试这种肮脏、可怕的技巧:

      def sum(x, v):
          v[0] = x
          def f(y, v):
              return sum(x+y, v)
          return f
      
      v = [0]
      sum(1,v)(2,v)(3,v)
      print(v[0]) # Should return 6
      

      这是另一个使用类的解决方案:

      class sum(object):
          def __init__(self, x=0):
              self.x=x
          def __call__(self, *y):
              if len(y) > 0:
                  self.x += y[0]
                  return self
              return self.x
      
      print(sum(1)(2)(3)()) # Prints 6
      

      【讨论】:

      • 你不能只是return x+y吗?
      • @cricket_007 他们期待一个函数作为回报。
      • 啊。递归。明白了。
      【解决方案4】:

      您所要求的在 Python 中是不可能的,因为您没有提供一种方法来确定调用链的结束,正如 cricket_007 在 cmets 中提到的那样。但是,如果您确实提供了一种方法来指示不再有调用,那么该函数很容易编写代码。指示链结束的一种方法是进行最后一次不带参数的调用。

      我在我的代码中使用rsum(递归和)作为函数的名称,因为sum 是一个内置函数,并且不必要地隐藏Python 内置函数是不是一个好的编码习惯:它使代码可能令人困惑,或者至少更难阅读,因为您必须始终记住该名称并不是您通常期望它所指的名称,并且可能导致细微的错误。

      def rsum(val=None, tot=0):
          if val is None:
              return tot
          tot += val
          return lambda val=None, tot=tot: rsum(val, tot)
      
      print rsum(42)()
      print rsum(1)(2)()
      print rsum(4)(3)(2)(1)()
      print rsum(4100)(310000)(9)(50)()
      

      输出

      42
      3
      10
      314159
      

      【讨论】:

        【解决方案5】:
        class MetaSum(type):
        
            def __repr__(cls):
        
                    sum_str = str(cls.sum)
        
                    cls.sum = 0
        
                    return sum_str
        
            def __call__(cls, *args):
        
                    for arg in args:
        
                            cls.sum += arg
        
                    return cls
        
        
        
        class sum_numbers(object, metaclass = MetaSum):
            sum = 0
        
        print (sum_numbers(2)(3)(4)) # this only works in python 3
        

        【讨论】:

        • “这只适用于 python 3”——然而,你在那里使用的是 Python 2 打印语句?
        • 另请注意,这可能使它看起来像一个数字,但它不是一个:例如,sum_numbers(2) + 4 将失败,因为您无法将类型添加到 int。
        • Poke 说的。 FWIW,要使此代码在 Python 2 中运行,请将 class sum_numbers(object, metaclass = MetaSum) 替换为 class sum_numbers(object):,后跟 __metaclass__ = MetaSum
        猜你喜欢
        • 2017-04-15
        • 2020-06-19
        • 2022-07-07
        • 1970-01-01
        • 1970-01-01
        • 2019-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多