【问题标题】:Python - can function call itself without explicitly using name?Python - 可以在不显式使用名称的情况下调用自身吗?
【发布时间】:2015-10-19 02:13:56
【问题描述】:

或者一个更广泛的问题:如何在python中创建一个递归函数,并且在更改其名称时,只需在声明中更改它?

【问题讨论】:

  • 为什么要改函数名?你可以这样做,但很多时候有比动态函数名称更好的方法。
  • 这是一个有趣的想法,但我希望在现实中您使用的是像样的 IDE 或其他工具来安全地重构,而不是像这样的奇怪技巧。
  • 实际上我正在通过 SSH 玩 python 而我正在使用 vim
  • 作为长而描述性的函数名称的粉丝,如果函数是递归的,我总是在内部重复它们,这让我很恼火。它违反了 DRY 原则。我认为这个问题应该在代码级别解决,而不是委托给 IDE。它还可以使coden-ps更易读,因为递归字符直接变得明显(不需要记住函数名)。

标签: python recursion refactoring inspection


【解决方案1】:

我找到了一个简单有效的解决方案。

from functools import wraps

def recfun(f):
    @wraps(f)
    def _f(*a, **kwa): return f(_f, *a, **kwa)
    return _f

@recfun
# it's a decorator, so a separate class+method don't need to be defined
# for each function and the class does not need to be instantiated,
# as with Alex Hall's answer
def fact(self, n):
    if n > 0:
        return n * self(n-1)  # doesn't need to be self(self, n-1),
                              # as with lkraider's answer
    else:
        return 1

print(fact(10))  # works, as opposed to dursk's answer

【讨论】:

    【解决方案2】:

    这是一个(未经测试的)想法:

    class Foo(object):
    
        def __call__(self, *args):
            # do stuff
            self(*other_args)
    

    【讨论】:

      【解决方案3】:

      您可以将函数绑定到自身,因此它接收对自身的引用作为第一个参数,就像绑定方法中的self

      def bind(f):
          """Decorate function `f` to pass a reference to the function
          as the first argument"""
          return f.__get__(f, type(f))
      
      @bind
      def foo(self, x):
          "This is a bound function!"
          print(self, x)
      

      来源:https://stackoverflow.com/a/5063783/324731

      【讨论】:

        【解决方案4】:

        我不知道您为什么要这样做,但尽管如此,您可以使用decorator 来实现此目的。

        def recursive_function(func):
            def decorator(*args, **kwargs):
                return func(*args, my_func=func, **kwargs):
            return decorator
        

        然后你的函数看起来像:

        @recursive_function
        def my_recursive_function(my_func=None):
            ...
        

        【讨论】:

          【解决方案5】:

          免责声明:肮脏的解决方案,但不需要装饰器

          import sys
          
          def factorial(x):
              _f = eval(sys._getframe().f_code.co_name)
              return x if x<3 else x*_f(x-1)
          
          >>> factorial(5)
          120
          

          【讨论】:

            猜你喜欢
            • 2012-12-29
            • 1970-01-01
            • 2021-11-01
            • 2013-05-26
            • 1970-01-01
            • 2018-08-20
            • 2018-09-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多