太长了;没读:
使用float.__trunc__() 比builtins.int() 快30%
我喜欢长篇大论:
@MartijnPieters 绑定builtins.int 的技巧确实很有趣,它让我想起了An Optimization Anecdote。但是,调用builtins.int 并不是最有效的。
让我们看看这个:
python -m timeit -n10000000 -s "n = 1.345" "int(n)"
10000000 loops, best of 5: 48.5 nsec per loop
python -m timeit -n10000000 -s "n = 1.345" "n.__trunc__()"
10000000 loops, best of 5: 33.1 nsec per loop
这是 30% 的收益!这里发生了什么?
原来builtints.int 所做的只是调用以下method-chains:
- 如果定义了
1.345.__int__,则返回1.345.__int__(),否则:
- 如果定义了
1.345.__index__,则返回1.345.__index__(),否则:
- 如果定义了
1.345.__trunc__,则返回1.345.__trunc__()
1.345.__int__ 未定义 1 - 1.345.__index__ 也未定义。因此,直接调用1.345.__trunc__() 可以让我们跳过所有不必要的方法调用——成本相对较高。
绑定技巧怎么样?那么float.__trunc__ 本质上只是一个实例方法,我们可以将1.345 作为self 参数传递。
python -m timeit -n10000000 -s "n = 1.345; f=int" "f(n)"
10000000 loops, best of 5: 43 nsec per loop
python -m timeit -n10000000 -s "n = 1.345; f=float.__trunc__" "f(n)"
10000000 loops, best of 5: 27.4 nsec per loop
两种方法都得到了预期2的改进,并且它们的比例大致相同!
1 我对此并不完全确定 - 如果有人知道,请纠正我。
2 这让我很惊讶,因为我的印象是float.__trunc__ 在实例创建期间绑定到1.345。如果有人愿意向我解释这一点,那就太好了。
还有一种方法builtins.float.__floor__ 没有在文档中提及——它比builtins.int 快但比buitlins.float.__trunc__ 慢。
python -m timeit -n10000000 -s "n = 1.345; f=float.__floor__" "f(n)"
10000000 loops, best of 5: 32.4 nsec per loop
似乎在负浮点数和正浮点数上产生相同的结果。如果有人能解释这如何适合其他方法,那就太棒了。