由用错PYTHON的递归想到的

由用错PYTHON的递归想到的

之前因为原来养成不良编码风格的原因, 初学PYTHON想试试它的递归, 就用最简单的阶乘来试, 结果出了问题, 还以为PYTHON的递归有什么特别的东西, 今天再试了一试, 终于发现为什么错了, 把过程发出来, 让某些有同样经历的人(也许再没人会发生这种情况)引以为JIAN:

首先看PERL里面求阶乘的例子:

[Copy to clipboard] [ - ]
CODE:
sub fact{
  my $n = $_[0];
  if($n>1) {                #可写为:
    $n = $n * fact($n-1) ;  #  $n *= fact($n-1) if $n > 1;
  }else{                    #
    return $n;              #  return $n;
  }                         #但以前受C的影响, 所以那样写了
}

print fact(50);

这样成功了, 在IF中不用返回, 因为它一定会返回值!

下面用PYTHON依葫芦画瓢来写一个最简单的例子:

[Copy to clipboard] [ - ]
CODE:
-----------------------------------------------------
>>> def fact(n):
...   if n>1:
...     n = n* fact(n-1);
...   else:
...     return n
...
>>> fact(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
  File "<stdin>", line 3, in fact
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
-----------------------------------------------------

HOHO!出错了, 说fact是NONE类型的, 不能返回给INT类型
WA-KAO! 我明明是返回了值的呀, 怎么会说是NONE型呢?
于是我脑子一转: 莫非是每个逻辑路都要有返回值? 于是修改:

[Copy to clipboard] [ - ]
CODE:
-----------------------------------------------------
>>> def fact(n):
...   if n>1:
...     n = n* fact(n-1);
...     return n
...   else:
...     return n
...
>>> fact(5)
120
-----------------------------------------------------

OK! 成功了, 于是猜想PYTHON是编译时就检查它每条逻辑路的返回值,
如果发现某条逻辑分支没返回, 而最后也没返回的话, 就是NONE型.
到底是不是呢? 为了证实, 我再改进一下, 不在分支返回,
而在最后返回, 试试看:

[Copy to clipboard] [ - ]
CODE:
-----------------------------------------------------
>>> def fact(n):
...   if n>1:
...     n = n * fact(n-1)
...   return n
...
>>> fact(5)
120
-----------------------------------------------------

YAHOO! 明白了, 真的是PYTHON在编译时会看是不是绝
对有返回, 如果出现意外会不能返回的话就说你是NONE型.
看来MUTI-RETURN(多个RETURN分支)的编程风格真的不好!
JAVA里反对MUTI-RETURN, 现在PYTHON也不喜欢MUTI-RETURN!
那以后写程序最好还是在最后返回算了!
你这样一个分支里面不return东西,c里面也不能通过的阿。只能说perl的bug而已
哈哈,五分钟前我也有你这样的问题
我的代码是:
def fib(n):
        if n > 1:
                print n * fib(n - 1)#这里的print 应该是return
        else:
                print 'End of line'
                return 1
然后就出现一大堆报错,后来才找到原因,怪不得在书里一直强调某代码的返回的是什么~
这是不同语言的设计风格,python讲究明显比隐晦要好,所以许多东西需要显示的处理。
你的程序本来就写的有问题,这种分支结构拿到C语言里也不是没有返回值吗?起码不会返回正确的值!
楼主, 0 的阶乘是多少啊

LZ的程序,0的阶乘返回还是0。。


QUOTE:
原帖由 libin1983 于 2008-3-9 21:45 发表
楼主, 0 的阶乘是多少啊

很严谨,学习了!


QUOTE:
原帖由 wannachan 于 2006-12-28 07:29 发表
之前因为原来养成不良编码风格的原因, 初学PYTHON想试试它的递归, 就用最简单的阶乘来试, 结果出了问题, 还以为PYTHON的递归有什么特别的东西, 今天再试了一试, 终于发现为什么错了, 把过程发出来, 让某些有同样 ...

如果没有return,perl会返回最后一个expression的值,就是if里面的n*fact(n-1),因此是对的;python不会。
nodelocation={};
lines=[];
nodes=[];
layernodes=[];
for i in range(0,10):
    lines.append([]);

def recursive_construction(n,label='',label_remain_char=[],location={},diameter=0):
    loc={};
    if len(label_remain_char) > 3 :
        for i in range(0,len(label_remain_char)):
            sinx=math.sin(i*2*math.pi/n);
            cosx=math.cos(i*2*math.pi/n);
            if sinx>1 or sinx < -1 or (sinx < 1e-10 and sinx > -1e-10):
                sinx=0;
            if cosx>1 or cosx < -1 or (cosx < 1e-10 and cosx > -1e-10):
                cosx=0;
            loc['x']=location['x']+diameter*cosx;loc['y']=location['y']+diameter*sinx;
            label_remain=label_remain_char[:];
            popitem=label_remain.pop(i);
            recursive_construction(n-1,popitem+label,label_remain,loc,diameter/3);

        #deal with the lines of the current layer
    elif len(label_remain_char) == 3 :
        #deal with the hex-circle
        diameter=2;
        hexlabel=''.join('%s'%j for j in label_remain_char);
        for i in range(0,6):
            sinx=math.sin(i*2*math.pi/6);
            cosx=math.cos(i*2*math.pi/6);
            if sinx>1 or sinx < -1 or (sinx < 1e-10 and sinx > -1e-10):
                sinx=0;
            if cosx>1 or cosx < -1 or (cosx < 1e-10 and cosx > -1e-10):
                cosx=0;
            x=location['x']+diameter*cosx;y=location['y']+diameter*sinx;
            nodelocation['%s'%(hexlabel+label)]={'x','y':y};
            nodes.append('%s'%(hexlabel+label));
            hexlabelold=hexlabel;
            if i%2==0 :
                hexlabel=''.join(j for j in hexlabel[-2:-4:-1])+'%s'%hexlabel[-1];
            else:
                hexlabel=''.join(j for j in hexlabel[-1:-4:-1]);
            lines[0].append((hexlabelold+label,hexlabel+label));