使用对象变量作为Python类中的递归方法参数

时间:2012-01-03 02:01:48

标签: python recursion

我正在尝试在类中编写递归函数,但在使用对象var作为方法参数时遇到一些麻烦:

class nonsense(object):
  def __init__(self, val):
    self.val = val
  def factorial(self, n=self.val):
    if n<=1: return 1
    return n*self.factorial(n=n-1)

上面的代码会产生以下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in nonsense
NameError: name 'self' is not defined

但是如果我没有引用self.val,那么错误就会消失,尽管必须指定n是多余的:

class nonsense(object):
  def __init__(self, val):
    self.val = val
  def factorial(self, n):
    if n<=1: return 1
    return n*self.factorial(n=n-1)

这样做的正确方法是什么?

4 个答案:

答案 0 :(得分:6)

定义方法时会评估默认参数。因此,使用__init__中定义的成员值基本上“为时已晚”。您应该做的是将默认值设置为None并在函数体中对此进行测试:

class nonsense(object):
    def __init__(self, val):
        self.val = val
    def factorial(self, n=None):
        if n is None:
            n = self.val
        elif n <= 1:
            return 1

        return n*self.factorial(n-1)

答案 1 :(得分:3)

正如您所发现的那样,标题中不能有self.xxx - 而是拥有无,然后在正文中更正:

def factorial(self, n=None):
    if n is None: n = self.val
    if n<=1: return 1
    return n*self.factorial(n=n-1)

原因是当创建类对象时没有self;除了globals()之外,Python到达factorial时定义的唯一名称是__module____init__

作为向自己证明这一点的实验,试试这个:

class TestClassCreation(object):
    print("Started creating class")
    print("names so far: %s" % vars())

    def __init__(self):
        pass
    print("now we have %s" % vars())

    def noop(self, default=None):
        print("this gets run when noop is called")
    print("and now have %s" % vars())
    print()

    print("and now we'll fail...")
    def failure(self, some_arg=self.noop):
        pass
    print("we never get here...")

答案 2 :(得分:1)

奇怪行为的原因是def语句仅在定义函数时执行一次。因此,只有在没有self引用时才会创建初始化值一次。

作为替代方案,试试这个:

class nonsense(object):
  def __init__(self, val):
    self.val = val
  def factorial(self, n=None):
    return self.factorial_aux(n if n is not None else self.val)
  def factorial_aux(self, n):
    if n <= 1:
        return 1
    return n * self.factorial(n-1)

如果n参数具有默认值(None),上述解决方案仅测试一次,之后,它返回调用factorial_aux的结果(执行实际工作)用适当的论点。

答案 3 :(得分:0)

为什么不写这么简单呢?

class fact1():  
    def fact2(self, num):
        if num==1:
            return 1
        ss=num*self.fact2(num-1)
        return ss

exx=fact1()
print exx.fact2(5)

输出120