【问题标题】:Return the result instead of printing in a function返回结果而不是在函数中打印
【发布时间】:2013-12-23 15:05:17
【问题描述】:

我有一个关于 Python 的问题。

我有一个递归函数:

def func(num, k):

    if k == 0:
        print(num, end = '')
        return

    for item in num:
        if item == '1':
            func('123', k-1)
        elif item == '2':
            func('321', k-1)
        elif item == '3':
            func('1', k-1)

运行此代码func('2', 3) 打印: 12313211231233211

但是,实际上我不希望该函数打印结果。我想把它退回来。所以,如果我以a = func('2', 3) 运行程序,那么程序什么也不会打印。现在我可以在函数外使用a,例如打印它print(a),得到12313211231233211。

我应该如何更改返回结果而不打印的代码?

谢谢!

【问题讨论】:

    标签: python python-3.x return-value output


    【解决方案1】:

    这是一种无需更改函数代码的方法。相反,我们将创建一个函数装饰器,它会静默捕获所有打印输出,并将其保存以供以后使用。

    import sys
    from io import StringIO
    
    def returnStdout(fn):
        silent_stdout = StringIO()
        def silentFn(*args, depth=0, **kargs):
            nonlocal silent_stdout
    
            #only replace stdout if it hasn't been replaced already.
            #this may be important if we decorate a recursive function.
            if sys.stdout != silent_stdout:
                old_stdout = sys.stdout
                sys.stdout = silent_stdout
                fn(*args, **kargs)
                sys.stdout = old_stdout
                result = silent_stdout.getvalue()
    
                #clear silent_stdout so the next call to the decorated function doesn't contain the values of previous calls
                silent_stdout = StringIO()
    
                return result
            else:
                fn(*args, **kargs)
        return silentFn
    
    @returnStdout
    def func(num, k):
    
        if k == 0:
            print(num, end = '')
            return
    
        for item in num:
            if item == '1':
                func('123', k-1)
            elif item == '2':
                func('321', k-1)
            elif item == '3':
                func('1', k-1)
    
    
    result = func("2", 3)
    print("got result. Result is:")
    print(result)
    

    结果:

    got result. Result is:
    12313211231233211
    

    【讨论】:

      【解决方案2】:
      def func(num, k, result=None):
          if result is None:
              result = []
          if k == 0:
              result.append(num)
          else:
              for item in num:
                  if item == '1':
                      func('123', k-1, result)
                  elif item == '2':
                      func('321', k-1, result)
                  elif item == '3':
                      func('1', k-1, result)
          return "".join(result)
      

      我添加了result 参数,但只是为了保存解决方案,您不需要提供任何列表来运行此版本。就像你发布的那样运行它:

      print func('2', 3)
      

      【讨论】:

      • 我试过这个,func("2", 3) 返回123。我认为这是不对的。
      • @Kevin 是的,我现在得到了相同的答案123。但是,是的,这是不正确的。
      • 不要使用空列表作为默认参数,下次调用函数时它不会被“清除”。例如,print(func('2', 3)); print(func('2', 3)) 在第二个电话中给出了错误的答案。您可以使用None 作为默认值并在函数顶部对其进行测试。
      【解决方案3】:

      这是另一种方法。

      def func(num, k, m={'1':'123','2':'321','3':'1'}):
          def recurs(s, c, r=''):
              return s if c == 0 else ''.join([recurs(m.get(i,''), c-1) for i in s])
          return recurs(num, k)
      
      >>> func('2', 3)
      '12313211231233211'
      

      【讨论】:

        【解决方案4】:

        在 Python 3.3 中:

        def iter_func(num, k):
            if k == 0:
                yield num
            else:
                for item in num:
                    if item == '1':
                        yield from iter_func('123', k-1)
                    elif item == '2':
                        yield from iter_func('321', k-1)
                    else:
                        yield from iter_func('1', k-1)
        
        def func(num, k):
            return ''.join(iter_func(num, k))
        

        在早期的 Python 版本中没有yield from,但您可以通过以下方式实现相同的目的:

        for x in whatever:
            yield x
        

        顺便说一句,你也可以通过重组来简化一点,特别是如果你不使用 3.3,因此在每种情况下都需要额外的代码:

        subvalues = {'1' : '123', '2': '321'}
        
        ...
        
        for item in num:
            yield from iter_func(subvalues.get(item, '1'), k-1)
        

        同样的事情的另一种说法:

        import itertools
        
        subvalues = {'1' : '123', '2': '321'}
        def iter_func(num, k):
            if k == 0:
                return (num,)
            return itertools.chain.from_iterable(
                iter_func(subvalues.get(item, '1'), k-1)
                for item in num
            )
        

        【讨论】:

        • 谢谢!由于我是 Python 的初学者,我需要搜索有关 yield 的更多信息。我没想到会这么多地更改我的代码。不过还是谢谢。
        • @user3129888:嗯,还有其他方法可以做到这一点,所以你不必有查找yield,但我建议你这样做:-) 例如您可以在该位置周围传递一个列表,并将一个值附加到您当前打印的位置的该列表中。不过,您仍然需要在最后将 join 全部放在一起,而 yield 在任何情况下都是自然的(我敢说“Pythonic”)用于生成一系列值。
        猜你喜欢
        • 2016-07-13
        • 2013-10-10
        • 1970-01-01
        • 2021-06-08
        • 1970-01-01
        • 2015-11-14
        • 2018-10-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多