Python中计算阶乘的函数

174

我该如何在Python中计算一个整数的阶乘?

10个回答

241

最简单的方法是使用math.factorial(在Python 2.6及以上版本可用):

import math
math.factorial(1000)

如果您想/必须自己编写代码,可以采用迭代方法:

def factorial(n):
    fact = 1
    for num in range(2, n + 1):
        fact *= num
    return fact

或者采用递归的方法:

def factorial(n):
    if n < 2:
        return 1
    else:
        return n * factorial(n-1)

请注意,阶乘函数仅定义为正整数,因此您还应检查n >= 0并且isinstance(n, int)。如果不是,则分别引发一个ValueErrorTypeError异常。math.factorial 将为您处理这些异常。


2
我不理解如何在factorial函数内部使用factorial。你怎么能在当前定义的函数内部使用相同的函数?我是Python新手,所以我只是想理解一下。 - J82
14
这里使用的概念叫做“递归”(http://zh.wikipedia.org/wiki/递归_(计算机科学)),函数调用自身是完全正常且经常有用的。 - schnaader
5
如果你尝试计算factorial(999),那么递归函数将会因为超出998的数字而引发RecursionError,除非你增加Python的递归限制。请注意,递归函数会反复调用自身,直到达到基本情况来停止。 - user3064538
2
提高CPython的递归限制是危险的——你可能会杀死解释器。如果可以避免,就不要在Python中使用递归(正如这个例子所说明的那样)。 - ggorlen
阶乘(999)约等于4.02 × 10^2564,所以你可能不太想计算这么大的数。 - snibbets

120

在 Python 2.6 或更高版本中,可以尝试以下方法:

import math
math.factorial(n)

1
从Python 3.9开始,将float传递给此函数将引发DeprecationWarning。如果您想这样做,您需要显式地将n转换为intmath.factorial(int(n)),这将丢弃小数点后的任何内容,因此您可能需要检查n.is_integer() - user3064538

24

现有解决方案

最短且可能是最快的解决方案如下:

from math import factorial
print factorial(1000)

构建自己的解决方案

您还可以构建自己的解决方案。通常有两种方法可供选择。我最喜欢的一种是:

from itertools import imap
def factorial(x):
    return reduce(long.__mul__, imap(long, xrange(1, x + 1)))

print factorial(1000)

(当数字较大时,它也适用,此时结果变为 long)

实现相同效果的第二种方式是:

def factorial(x):
    result = 1
    for i in xrange(2, x + 1):
        result *= i
    return result

print factorial(1000)

operator.mul 可以代替 long.__mul__,并且在 Python 2Python 3 中都可以使用。 - Cristian Ciupitu

8
def factorial(n):
    if n < 2:
        return 1
    return n * factorial(n - 1)

3
除非你增加Python的递归深度限制,否则factorial(999)(及以上)会引发RuntimeError - user3064538

7
如果你正在使用Python 2.5或更早版本,请尝试:
from operator import mul

def factorial(n):
    return reduce(mul, range(1, n+1))

对于较新版本的Python,math模块中有阶乘函数,如其他答案所示。


2
这是一个仅适用于Python 2的答案,“reduce”已从Python 3中删除。 - user3064538
@Boris,在Python3中,您只需要添加from functools import reduce - John La Rooy
它被删除是有原因的,你不应该使用它 https://www.artima.com/weblogs/viewpost.jsp?thread=98196 - user3064538

7

出于性能方面的考虑,请勿使用递归。这将是灾难性的。

def fact(n, total=1):
    while True:
        if n == 1:
            return total
        n, total = n - 1, total * n

检查运行结果

cProfile.run('fact(126000)')

4 function calls in 5.164 seconds

使用栈很方便(就像递归调用一样),但代价是:存储详细信息可能会占用大量内存。
如果栈很高,这意味着计算机存储了许多有关函数调用的信息。
该方法仅占用常量内存(就像迭代一样)。
或者使用“for”循环。
def fact(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result

检查运行结果

cProfile.run('fact(126000)')

4 function calls in 4.708 seconds

或者使用内置的math函数。
def fact(n):
    return math.factorial(n)

查看运行结果

cProfile.run('fact(126000)')

5 function calls in 0.272 seconds

1
我认为这个 while 循环看起来更加简洁。<!-- language: python --> def fact(n): ret = 1 while n > 1: n, ret = n - 1, ret * n return ret - edilio
1
看起来很不错,大声喊着(使用大字体)递归是灾难性的,但你能证明吗?是的,你需要很多堆栈,但只需要很短的时间。而昨天的“很多”在计算机领域今天可能只是“一点点”。我们编写高级代码是为了不浪费时间,递归有助于实现这一目标。如今,出于性能原因,你不需要经常使用低级代码。 - Roland
这也取决于你在什么上下文中使用阶乘 -- 递归函数具有可缓存的优点,这在计算阶乘时特别有帮助。 - Schalton

6
def fact(n):
    f = 1
    for i in range(1, n + 1):
        f *= i
    return f

3

另一种方法是使用下面的np.prod

def factorial(n):
    if n == 0:
        return 1
    else:
         return np.prod(np.arange(1,n+1))

2

非递归解决方案,无需导入任何模块:

def factorial(x):
    return eval(' * '.join(map(str, range(1, x + 1))))

3
将其与此处提出的其他方法进行比较会很有意思。我猜想它的效率非常低下。 - Mark Ransom

0

如果你喜欢的话,也可以使用递归的方式将其写在一行中。这只是个人选择问题。这里我们在Python中使用内联if else ,它类似于Java中的三元运算符:

Expression1 ? Expression2 : Expression3
  • 一行函数调用方法:

    def factorial(n): return 1 if n == 0 else n * factorial(n-1)
    
  • 一行lambda函数方法:

    (虽然不建议将lambda函数直接赋值给一个名称,因为这被认为是一种不好的做法,可能会给您的代码带来不一致性。了解这一点总是有好处的。请参见PEP8。)

    factorial = lambda n: 1 if n == 0 else n * factorial(n-1)
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接