优化Python代码 [英] Optimizing Python Code

查看:73
本文介绍了优化Python代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究InterviewStreet.com上的编码挑战之一,并且遇到了一些效率问题.谁能建议我可以在哪里更改代码以使其更快,更有效?

I've been working on one of the coding challenges on InterviewStreet.com and I've run into a bit of an efficiency problem. Can anyone suggest where I might change the code to make it faster and more efficient?

代码在这里

如果您有兴趣,请在此处提出问题说明

推荐答案

如果您的问题是一般性地优化python代码(我认为应该如此;),那么您可以做各种各样的证明性工作,但是首先:

If your question is about optimising python code generally (which I think it should be ;) then there are all sorts of intesting things you can do, but first:

您可能不应该过分地优化python代码!如果您要使用最快的算法来解决问题,而python的处理速度不够快,则可能应该使用其他语言.

You probably shouldn't be obsessively optimising python code! If you're using the fastest algorithm for the problem you're trying to solve and python doesn't do it fast enough you should probably be using a different language.

也就是说,您可以采用几种方法(因为有时候,您确实确实想使python代码更快):

That said, there are several approaches you can take (because sometimes, you really do want to make python code faster):

有很多分析python代码的方法,但我将提到两种: cProfile(或profile)模块 PyCallGraph .

There are lots of ways of profiling python code, but there are two that I'll mention: cProfile (or profile) module, and PyCallGraph.

这是您应该实际使用的方法,尽管解释结果可能会有些艰巨. 它通过记录何时进入或退出每个功能以及调用的功能是什么(以及跟踪异常)来进行记录.

This is what you should actually use, though interpreting the results can be a bit daunting. It works by recording when each function is entered or exited, and what the calling function was (and tracking exceptions).

您可以像这样在cProfile中运行一个函数:

You can run a function in cProfile like this:

import cProfile
cProfile.run('myFunction()', 'myFunction.profile')

然后查看结果:

import pstats
stats = pstats.Stats('myFunction.profile')
stats.strip_dirs().sort_stats('time').print_stats()

这将向您显示大部分时间都花在哪些功能上.

This will show you in which functions most of the time is spent.

PyCallGraph 提供了最漂亮的,也许是分析python的最简单方法程序-很好地介绍了在程序中花费的时间,但是却增加了大量的执行开销

PyCallGraph provides a prettiest and maybe the easiest way of profiling python programs -- and it's a good introduction to understanding where the time in your program is spent, however it adds significant execution overhead

要运行pycallgraph:

To run pycallgraph:

pycallgraph graphviz ./myprogram.py

简单!您会得到一个png图形图像作为输出(也许过一会儿...)

Simple! You get a png graph image as output (perhaps after a while...)

如果您要尝试在python中执行某个模块已经存在的操作(甚至在标准库中),请改用该模块!

If you're trying to do something in python that a module already exists for (maybe even in the standard library), then use that module instead!

大多数标准库模块都是用C编写的,它们的执行速度比

Most of the standard library modules are written in C, and they will execute hundreds of times faster than equivilent python implementations of, say, bisection search.

解释器将为您做一些事情,例如循环.真的吗?是的!您可以使用mapreducefilter关键字大大加快紧密循环的速度:

The interpreter will do some things for you, like looping. Really? Yes! You can use the map, reduce, and filter keywords to significantly speed up tight loops:

考虑:

for x in xrange(0, 100):
    doSomethingWithX(x)

vs:

map(doSomethingWithX, xrange(0,100))

很显然,这可能更快,因为解释器只需要处理一个语句,而不是两个,但这有点含糊……实际上,这更快是因为两个原因:

Well obviously this could be faster because the interpreter only has to deal with a single statement, rather than two, but that's a bit vague... in fact, this is faster for two reasons:

  • 所有流控制(我们已经完成了循环...)都是在解释器中完成的
  • doSomethingWithX函数名称仅解析一次

在for循环中,每次循环时python必须检查doSomethingWithX函数的确切位置!即使是缓存,这也有些负担.

In the for loop, each time around the loop python has to check exactly where the doSomethingWithX function is! even with cacheing this is a bit of an overhead.

(请注意,本节实际上是关于微小的优化的,您不应该让它们影响您的常规可读编码风格!) 如果您来自使用c或Fortran之类的编译语言进行编程的背景,那么关于不同python语句的性能的某些事情可能会令人惊讶:

(Note that this section really is about tiny tiny optimisations that you shouldn't let affect your normal, readable coding style!) If you come from a background of a programming in a compiled language, like c or Fortran, then some things about the performance of different python statements might be surprising:

如果您有这样的代码:

if somethingcrazy_happened:
     uhOhBetterDoSomething()
else:
     doWhatWeNormallyDo()

如果doWhatWeNormallyDo()发生了一些疯狂的事情,它将引发异常,那么这样安排代码会更快:

And doWhatWeNormallyDo() would throw an exception if something crazy had happened, then it would be faster to arrange your code like this:

try:
    doWhatWeNormallyDo()
except SomethingCrazy:
    uhOhBetterDoSomething()

为什么?口译员可以直接潜入水中,开始做您通常的工作;在第一种情况下,解释器必须在每次执行if语句时进行一次符号查找,因为该名称可能引用自上次执行该语句以来的其他内容! (而且名称查找,尤其是如果somethingcrazy_happenedglobal的情况,可能是不平凡的.)

Why? well the interpreter can dive straight in and start doing what you normally do; in the first case the interpreter has to do a symbol look up each time the if statement is executed, because the name could refer to something different since the last time the statement was executed! (And a name lookup, especially if somethingcrazy_happened is global can be nontrivial).

由于名称查找的开销,将全局值缓存在函数中以及将简单的布尔测试烘烤到这样的函数中也可能更好:

Because of cost of name lookups it can also be better to cache global values within functions, and bake-in simple boolean tests into functions like this:

未优化的功能:

def foo():
    if condition_that_rarely_changes:
         doSomething()
    else:
         doSomethingElse()

优化的方法而不是使用变量,而是利用了解释器始终在函数上进行名称查找的事实!

Optimised approach, instead of using a variable, exploit the fact that the interpreter is doing a name lookup on the function anyway!

条件成立时:

foo = doSomething # now foo() calls doSomething()

条件变为假时:

foo = doSomethingElse # now foo() calls doSomethingElse()

PyPy

PyPy 是用python编写的python实现.当然,这意味着它将无限慢地运行代码吗?好吧,不. PyPy实际上使用即时编译器(JIT)运行python程序.

PyPy

PyPy is a python implementation written in python. Surely that means it will run code infinitely slower? Well, no. PyPy actually uses a Just-In-Time compiler (JIT) to run python programs.

如果您不使用任何外部库(或者您使用的外部库与PyPy 兼容 ),那么(几乎可以肯定)这是一种极其简单的方法,可以加快程序中的重复任务.

If you don't use any external libraries (or the ones you do use are compatible with PyPy), then this is an extremely easy way to (almost certainly) speed up repetitive tasks in your program.

基本上,JIT可以生成可以执行python解释器功能的代码,但是 更快,因为它是针对单个案例生成的,而不必处理每个可能的合法python表达式.

Basically the JIT can generate code that will do what the python interpreter would, but much faster, since it is generated for a single case, rather than having to deal with every possible legal python expression.

当然,您应该首先考虑的是改进算法和数据结构,并考虑诸如缓存之类的事情,或者甚至是否首先需要做很多事情,但是无论如何:

Of course, the first place you should have looked was to improve your algorithms and data structures, and to consider things like caching, or even whether you need to be doing so much in the first place, but anyway:

    python.org Wiki的
  • 此页面如何加快python代码的速度,尽管其中有些过时了.

  • This page of the python.org wiki provides lots of information about how to speed up python code, though some of it is a bit out of date.

这是关于优化循环的 BDFL自己.

Here's the BDFL himself on the subject of optimising loops.

还有很多事情,即使是从我自己有限的经验中我也已经错过了,但是这个答案已经足够长了!

There are quite a few things, even from my own limited experience that I've missed out, but this answer was long enough already!

所有这些都是基于我最近对一些不够快的python代码的经验,我想再次强调一点,我实际上并没有想到任何事情建议实际上是一个好主意,尽管有时,您必须....

This is all based on my own recent experiences with some python code that just wasn't fast enough, and I'd like to stress again that I don't really think any of what I've suggested is actually a good idea, sometimes though, you have to....

这篇关于优化Python代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆