Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 6, 2010 11:10:47

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Как код улучшить?

Ну питон - это не си++, и разбиение кода на более мелкие элементарные части в обход конструкциям питона только увеличивает время исполнения (зачастую). Конечно, нельзя утверждать, что последний вариант однозначно быстрее любого предложенного другого, пока не измеришь (к тому же это ничего не стоит), но уже интуитивно видно, что скорее всего это так.



Отредактировано (Дек. 6, 2010 11:15:19)

Офлайн

#2 Дек. 6, 2010 12:32:04

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Как код улучшить?

Isem, мне интересны подобные задачки. Спецы начинают изобретать, как лучше.
Было бы хорошо еще и таки измерять скорость - если об этом речь.
Насколько быстрее?
Стоит скорость того?
К месту или нет?

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

К слову, в С++ часто код выполняется дольше, чем в аналогичном С для конкретного случая. И, тем не менее, я люблю мудреные плюсы с перегруженной частичной типизацией шаблонов - особенно если применяется к месту.



Офлайн

#3 Дек. 6, 2010 12:57:39

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Как код улучшить?

Вообще эта задача близка к достаточно общей задаче 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
А всякие трюки, которые мы здесь предлагали - это чисто для поиграться. В реальном коде наличие таких ‘перлов’ обычно только усложняет читабельность.



Офлайн

#4 Дек. 6, 2010 13:57:26

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Как код улучшить?

Тем не менее, отличие самого медленного от самого быстрого составляет 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



Офлайн

#5 Дек. 6, 2010 17:03:44

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Как код улучшить?

Только потому, что самый медленный вариант - двухпроходный.
Отличие хакерского варианта 5 и варианта ‘в лоб’ 3 несущественно, на мой взгляд.



Офлайн

#6 Дек. 6, 2010 18:43:44

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Как код улучшить?

Но если “легкую” функцию bool_func сделать inline, то есть явно переписать ее содержимое в цикле вместо вызова, то скорость еще удвоится. Так что опять приходим к тяжелой для питона ноше - вызову функций.
То есть в нашем тестовом случае это:

vals = [v for v in vals if not (v&1) or res.append(v)]
В большинстве случаев оптимизация не нужна, но иногда без нее ни как не обойтись.
В этом смысле, я не вижу каких либо трудностей сделать в интерпретаторе питона поддержку inline функций, конечно, с явным указанием этого. Хотя Гвидо ван Россум наверняка будет против.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version