Найти - Пользователи
Полная версия: Как код улучшить?
Начало » Python для новичков » Как код улучшить?
1 2 3
Isem
Ну питон - это не си++, и разбиение кода на более мелкие элементарные части в обход конструкциям питона только увеличивает время исполнения (зачастую). Конечно, нельзя утверждать, что последний вариант однозначно быстрее любого предложенного другого, пока не измеришь (к тому же это ничего не стоит), но уже интуитивно видно, что скорее всего это так.
Андрей Светлов
Isem, мне интересны подобные задачки. Спецы начинают изобретать, как лучше.
Было бы хорошо еще и таки измерять скорость - если об этом речь.
Насколько быстрее?
Стоит скорость того?
К месту или нет?

Может, задачка вообще не предполагает гонку за микросекундами?

К слову, в С++ часто код выполняется дольше, чем в аналогичном С для конкретного случая. И, тем не менее, я люблю мудреные плюсы с перегруженной частичной типизацией шаблонов - особенно если применяется к месту.
Ed
Вообще эта задача близка к достаточно общей задаче list partitioning. В Эрланге, например, есть lists:partition: http://www.erlang.org/doc/man/lists.html#partition-2, в Хаскеле тоже: http://zvon.org/other/haskell/Outputlist/partition_f.html
К сожалению исторически так сложилось, что более развитый аппарат работы со списками присущ функциональным языкам более, чем таким, как Питон.
На мой взгляд наиболее правильным было бы решение с использованием аналога partitioning, что нибудь типа такого:
result = [], res
for v in val:
result[bool_func(v)].append(v)
vals, res = result
А всякие трюки, которые мы здесь предлагали - это чисто для поиграться. В реальном коде наличие таких ‘перлов’ обычно только усложняет читабельность.
Isem
Тем не менее, отличие самого медленного от самого быстрого составляет 2 раза. Для “тяжелой” bool_func, отличие будет конечно более заметно.
import time
import random

def bool_func( v ):
return bool(v & 1)

def func1( vals, res ):
res += [v for v in vals if bool_func(v)]
vals = [v for v in vals if not bool_func(v)]
return vals

def func2( vals, res ):
tmp = [(v, bool_func(v)) for v in vals]
res += [v[0] for v in tmp if v[1]]
vals = [v[0] for v in tmp if not v[1]]
return vals

def func3( vals, res ):
tmp = []
for v in vals:
if bool_func(v):
res.append(v)
else:
tmp.append(v)
vals = tmp
return vals

def func4( vals, res ):
vals = [v for v in vals if (res.append(v) if bool_func(v) else True)]
return vals

def func5( vals, res ):
vals = [v for v in vals if not bool_func(v) or res.append(v)]
return vals

def func6( vals, res ):
result = [], res
for v in vals:
result[bool_func(v)].append(v)
return result[0]

vals = list(range(100000))
random.shuffle( vals )

for func in [func1, func2, func3, func4, func5, func6]:
start = time.clock()
for i in range(20):
res = []
func( vals, res )
print( "Time for {} = {}".format( func.__name__, (time.clock() - start)/20 ) )
Time for func1 = 0.0963765587239
Time for func2 = 0.0977442872617
Time for func3 = 0.0598561109443
Time for func4 = 0.05586766467
Time for func5 = 0.0559596650385
Time for func6 = 0.062651857113

Python 3.1
Ed
Только потому, что самый медленный вариант - двухпроходный.
Отличие хакерского варианта 5 и варианта ‘в лоб’ 3 несущественно, на мой взгляд.
Isem
Но если “легкую” функцию bool_func сделать inline, то есть явно переписать ее содержимое в цикле вместо вызова, то скорость еще удвоится. Так что опять приходим к тяжелой для питона ноше - вызову функций.
То есть в нашем тестовом случае это:
vals = [v for v in vals if not (v&1) or res.append(v)]
В большинстве случаев оптимизация не нужна, но иногда без нее ни как не обойтись.
В этом смысле, я не вижу каких либо трудностей сделать в интерпретаторе питона поддержку inline функций, конечно, с явным указанием этого. Хотя Гвидо ван Россум наверняка будет против.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB