Heim >Backend-Entwicklung >Python-Tutorial >Tipps zur Python-Codeoptimierung

Tipps zur Python-Codeoptimierung

高洛峰
高洛峰Original
2016-11-21 16:47:181282Durchsuche

Codeoptimierung Teil 1

Teilen Sie einige Tipps zur Codeoptimierung, die ich kürzlich gesehen habe.

Die Kurzschlusseigenschaft des if-Urteils

Für und sollten diejenigen, die die wenigsten Bedingungen erfüllen, zuerst platziert werden, sodass bei einer großen Anzahl von Urteilen die wenigen erfüllten Bedingungen vorhanden sind führt direkt zu anderen Ausdrücken, die folgen. Es wird nicht berechnet, um Zeit zu sparen (da False und True immer noch False sind).

import timeit

s1 = """
a = range(2000)
[i for i in a if i % 2 ==0 and i > 1900]
"""

s2 = """
a = range(2000)
[i for i in a if  i > 1900 and i % 2 ==0]
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

Die laufenden Ergebnisse sind wie folgt:

➜  python test6.py
0.248532056808
0.195827960968

# 可以看到s2 表达式计算更快, 因为大部分情况都不满足 i>1900, 所以这些情况下, i % 2 == 0 也没有计算,从而节约了时间

In ähnlicher Weise setzen Sie für oder diejenigen an die erste Stelle, die die meisten Bedingungen erfüllen.

import timeit

s1 = """
a = range(2000)
[i for i in a if 10 < i <20 or 1000 < i < 2000]
"""

s2 = """
a = range(2000)
[i for i in a if 1000 < i < 2000 or 10 < i <20]
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

Ausführungsergebnisse:

0.253124952316
0.202992200851

Zusammenführungszeichenfolgen zusammenführen

Zusammenführungszeichenfolgen schneller zusammenführen als in einer Schleife zum Zusammenführen.

import timeit

s1 = """
a = [str(x) for x in range(2000)]
s = &#39;&#39;
for i in a:
    s += i
"""

s2 = """
a = [str(x) for x in range(2000)]
s = &#39;&#39;.join(a)
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

Die laufenden Ergebnisse lauten wie folgt:

python test6.py

0.558945894241
0.422435998917

while 1 und while True

In python2.x sind True und False keine reservierten Schlüsselwörter, sondern a Globale Variablen, was bedeutet, dass Sie dies tun können

>>> True = 0
>>> True
0
>>> if not True:
...   print &#39;1&#39;
...
1

Also die folgenden zwei Situationen:

import timeit

s1 = """
n = 1000000
while 1:
    n -= 1
    if n <= 0: break
"""

s2 = """
n = 1000000
while True:
    n -= 1
    if n <= 0: break
"""

print timeit.timeit(stmt=s1, number=100)
print timeit.timeit(stmt=s2, number=100)

Das laufende Ergebnis ist wie folgt:

➜  python test6.py
5.18007302284
6.84624099731

Denn jedes Mal, wenn Sie beurteilen, ob es wahr ist, müssen Sie zuerst den Wert von Wahr ermitteln.

In python3.x wird True zu einem Schlüsselwortargument, sodass die beiden oben genannten Situationen gleich sind.

cProfile, cStringIO und cPickle

Mit der C-Version geschriebene Erweiterungen sind schneller als die nativen. cPickle vs. pickle ist wie folgt:

import timeit

s1 = """
import cPickle
import pickle
n = range(10000)
cPickle.dumps(n)
"""

s2 = """
import cPickle
import pickle
n = range(10000)
pickle.dumps(n)
"""

print timeit.timeit(stmt=s1, number=100)
print timeit.timeit(stmt=s2, number=100)

Die laufenden Ergebnisse sind wie folgt:

➜ python test6.py
0.182178974152
1.70917797089

Vernünftiger Einsatz von Generatoren

Der Unterschied

Verwenden von () ist Der für ein Generatorobjekt erforderliche Speicherplatz hat nichts mit der Größe der Liste zu tun, sodass die Effizienz höher ist.

import timeit

s1 = """
[i for i in range (100000)]
"""

s2 = """
(i for i in range(100000))
"""

print timeit.timeit(stmt=s1, number=1000)
print timeit.timeit(stmt=s2, number=1000)

Ergebnis:

➜  python test6.py
5.44327497482
0.923446893692

Aber für Situationen, in denen eine Schleifendurchquerung erforderlich ist: Die Verwendung von Iteratoren ist wie folgt nicht effizient:

import timeit

s1 = """
ls = range(1000000)
def yield_func(ls):
    for i in ls:
        yield i+1
for x in yield_func(ls):
    pass
"""

s2 = """
ls = range(1000000)
def not_yield_func(ls):
    return [i+1 for i in ls]
for x in not_yield_func(ls):
    pass
"""

print timeit.timeit(stmt=s1, number=10)
print timeit.timeit(stmt=s2, number=10)

Das Ergebnis ist wie folgt:

➜  python test6.py
1.03186702728
1.01472687721

Die Verwendung eines Generators ist also ein Kompromiss, eine umfassende Berücksichtigung von Speicher und Geschwindigkeit.

xrange

在python2.x里xrange 是纯C实现的生成器,相对于range来说,它不会一次性计算出所有值在内存中。但它的限制是只能和整型一起工作:你不能使用long或者float。

import 语句的开销

import语句有时候为了限制它们的作用范围或者节省初始化时间,被卸载函数内部,虽然python的解释器不会重复import同一个模块不会出错,但重复导入会影响部分性能。有时候为了实现懒加载(即使用的时候再加载一个开销很大的模块),可以这么做:

email = None

def parse_email():
    global email
    if email is None:
        import email
    ...

# 这样一来email模块仅会被引入一次,在parse_email()被第一次调用的时候。


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn