class Command_set:
#вариант со словарём
command_id = {"generic_nack" : 0x80000000,
"bind_receiver" : 0x00000001,
"bind_receiver_resp" : 0x80000001,
"bind_transmitter" : 0x00000002,
"bind_transmitter_resp" : 0x80000002,
"query_sm" : 0x00000003,
"query_sm_resp" : 0x80000003}
#вариант со свойствами класса
generic_nack = [0x80, 0x00, 0x00, 0x00 ]
Что быстрее: Dictionary vs. Class Fields?
Для одной поделки пишу класс со справочными структурами. Там просто постоянные для подстановки в функции. Знаю как минимум два варианта хранения таких постоянных: в словаре и в полях класса. Пример:
Код:
Разные типы здесь потому, что в результате своей работы поделка будет возвращать список. Поэтому в переменной класса сразу указан именно он. Это незначительно изменит логику программы (скажем, где-то можно будет обойтись без преобразований), но по идее отсутствие лишнего пересчёта числа в список ускорит работу. Дело не только в этом.
Вопрос, что быстрее работает: поиск в словаре или поиск к полях класса?
Итак, засекаем время выполнения функции:
Код:
import time
def timing(f, n, a):
print f.__name__,
r = range(n)
t1 = time.clock()
for i in r:
f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a)
t2 = time.clock()
print round(t2-t1, 3)
def timing(f, n, a):
print f.__name__,
r = range(n)
t1 = time.clock()
for i in r:
f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a)
t2 = time.clock()
print round(t2-t1, 3)
Создаём тупой тестовый класс:
Код:
class Testobjext:
dct = {"var1": 1, "var2": 2, "var3": 3, "var4": 4, "var5": 5, "var6": 6,
"var7": 7, "var8": 8, "var9": 9, "var10": 10, "var11": 11, "var13": 12,
"var13": 13, "var14": 14, "var15": 15}
var1 = 1
var2 = 2
var3 = 3
# ...и так далее до...
var15 = 15
dct = {"var1": 1, "var2": 2, "var3": 3, "var4": 4, "var5": 5, "var6": 6,
"var7": 7, "var8": 8, "var9": 9, "var10": 10, "var11": 11, "var13": 12,
"var13": 13, "var14": 14, "var15": 15}
var1 = 1
var2 = 2
var3 = 3
# ...и так далее до...
var15 = 15
Для чистоты эксперимента две одинаковые функции, возвращающие список, составленный из элементов словаря…
Код:
def fobj(emptyarg):
result = []
result.append(xobj.dct["var1"])
# и ещё 15 раз случайно взятые значения
return result
result = []
result.append(xobj.dct["var1"])
# и ещё 15 раз случайно взятые значения
return result
Код:
def fprop(emptyarg):
result = []
result.append(xobj.var1)
# тоже ещё 15 раз случайно взятые значения
return result
result = []
result.append(xobj.var1)
# тоже ещё 15 раз случайно взятые значения
return result
Теперь пробуем прогнать стопицот итераций той и другой функции:
Код:
for i in range(10000, 110000, 10000):
print "Attempt on ", i
timing(fprop, i, 1)
timing(fobj, i, 1)
print "Attempt on ", i
timing(fprop, i, 1)
timing(fobj, i, 1)
Результат изрядно в пользу переменных класса:
Код:
Attempt on 10000
fprop 0.099
fobj 0.273
Attempt on 20000
fprop 0.163
fobj 0.551
Attempt on 30000
fprop 0.243
fobj 0.829
Attempt on 40000
fprop 0.318
fobj 1.089
Attempt on 50000
fprop 0.414
fobj 1.365
Attempt on 60000
fprop 0.493
fobj 1.659
Attempt on 70000
fprop 0.57
fobj 1.925
Attempt on 80000
fprop 0.63
fobj 2.188
Attempt on 90000
fprop 0.727
fobj 2.473
Attempt on 100000
fprop 0.807
fobj 2.848
fprop 0.099
fobj 0.273
Attempt on 20000
fprop 0.163
fobj 0.551
Attempt on 30000
fprop 0.243
fobj 0.829
Attempt on 40000
fprop 0.318
fobj 1.089
Attempt on 50000
fprop 0.414
fobj 1.365
Attempt on 60000
fprop 0.493
fobj 1.659
Attempt on 70000
fprop 0.57
fobj 1.925
Attempt on 80000
fprop 0.63
fobj 2.188
Attempt on 90000
fprop 0.727
fobj 2.473
Attempt on 100000
fprop 0.807
fobj 2.848
Число после "Attempt on" следует умножать на 10, поскольку функция timing() последовательно вызывает одну и ту же функцию-аргумент десять раз.
Проще говоря, миллион операций составления 16-элементного списка из переменных класса проходит в 3,5 раза быстрее, чем из элементов словаря, в наилучшем случае разница составляет 2,7 раза в пользу поиска по переменным класса.
Рекомендую ознакомиться с timeit.
Отмечу, что Дэвид Бизли в своей книге про Python пишет, что пользовательские классы и объекты основаны на словарях, поэтому обычно операции поиска изменения или удаления данных в объектах или классах выполняется медленнее, чем непосредственно в словарях.
Тогда получается, что мне лучше вовсе не заводить отдельный класс для хранения справочной информации, а объявить словарь недалеко от того места, где он будет вызываться?
Цитата: Sanila_san
Тогда получается, что мне лучше вовсе не заводить отдельный класс для хранения справочной информации, а объявить словарь недалеко от того места, где он будет вызываться?
Не знаю, зависит от ситуации. Я бы, возможно, вообще тупли применил бы. Типа такого:
Код:
command_id = (
generic_nack,
bind_receiver, bind_receiver_resp, bind_transmitter,
bind_transmitter_resp, query_sm, query_sm_resp) = (
0x80000000,
0x00000001, 0x80000001, 0x00000002,
0x80000002, 0x00000003, 0x80000003)
print command_id[1]
print query_sm_resp
generic_nack,
bind_receiver, bind_receiver_resp, bind_transmitter,
bind_transmitter_resp, query_sm, query_sm_resp) = (
0x80000000,
0x00000001, 0x80000001, 0x00000002,
0x80000002, 0x00000003, 0x80000003)
print command_id[1]
print query_sm_resp
Хотя, это немного на извращение похоже. Ну и раз это константы, то все их бы заглавными буквами написал.
Попробую и это извращение. Хотя по-моему особо усложнять не надо. Тем более что там мне не обязательно хранить такие вот целочисленные константы, вся работа с данными основана на списках, поэтому и константы мне удобнее хранить не целыми числами, а прямо списками. Таким образом я смог бы избежать штук десять ненужных мне преобразований числа в список за раз.