原函数删除后函数名递归失效,如何用类似this/self引用自身?
如何在Python中让递归函数不依赖外部函数名引用自身?
你遇到的问题很典型:当递归函数依赖全局函数名来调用自身时,如果这个函数名被删除或者重新赋值,内部的递归调用就会因为找不到名称而失败。核心原因是count_down只是一个指向函数对象的变量,当你del count_down后,函数内部的count_down()调用就找不到对应的变量了。
下面几种方法可以让函数内部直接引用自身,不再依赖外部变量名:
方法1:通过参数传递自身引用
最简单的方式是给函数加一个可选参数,第一次调用时自动把函数对象赋值给这个参数,后续递归调用时传递这个参数:
def count_down(cur_count, self=None): # 第一次调用时初始化self为当前函数对象 if self is None: self = count_down print(cur_count) cur_count -= 1 if cur_count > 0: # 使用self而不是函数名进行递归 self(cur_count, self) else: print('Ignition!')
测试验证:
count_down(3) # 输出:3 2 1 Ignition! zaehle_runter = count_down del count_down zaehle_runter(2) # 输出:2 1 Ignition! (不会再抛出NameError)
这种方法的优点是无需额外依赖,代码改动小;缺点是函数签名多了一个参数(不过设置了默认值,不影响正常调用)。
方法2:用类的__call__方法模拟函数
把递归逻辑放到类的__call__方法中,这样就可以用self来引用自身(这里的self是类实例,而实例的__call__方法就是我们的递归逻辑):
class CountDown: def __call__(self, cur_count): print(cur_count) cur_count -= 1 if cur_count > 0: # 用self直接调用自身的__call__方法 self(cur_count) else: print('Ignition!') # 创建实例,调用方式和普通函数一样 count_down = CountDown() count_down(3) zaehle_runter = count_down del count_down zaehle_runter(2) # 正常执行
这种方法的优点是调用方式和普通函数完全一致,符合面向对象的封装思路;缺点是需要额外定义一个类,稍微有点繁琐。
方法3:用装饰器注入自身引用
通过装饰器把函数自身作为参数注入进去,既能保持函数签名简洁,又能实现无依赖的递归:
import functools def self_referential(func): @functools.wraps(func) def wrapper(*args, **kwargs): # 把wrapper(即函数对象本身)作为第一个参数传给原函数 return func(wrapper, *args, **kwargs) return wrapper @self_referential def count_down(self, cur_count): print(cur_count) cur_count -= 1 if cur_count > 0: self(cur_count) else: print('Ignition!')
测试验证:
count_down(3) zaehle_runter = count_down del count_down zaehle_runter(2) # 正常执行
这种方法的优点是函数调用时不需要额外传参,代码更干净;缺点是需要理解装饰器的工作原理,对新手稍微有点门槛。
核心思路总结
不管用哪种方法,核心都是让函数内部引用的是函数对象本身,而不是指向函数对象的外部变量名。这样即使外部变量被删除或重新赋值,函数内部依然能找到正确的递归目标。
内容的提问来源于stack exchange,提问作者Min-Soo Pipefeet
相关产品推荐
相关产品推荐

