2012-04-20 5 views
0

Я хочу получить класс из list, добавить к нему несколько атрибутов экземпляра и сделать его хешируемой. Какой хороший (быстрый и аккуратный) способ сделать это?Создание подкласса списка hashable

UPDATE:

Я удалил пространное объяснение прецедента. Я также перенес связанную, но отдельную проблему в different question.

+0

Трудно сказать, что именно вы спрашиваете. –

+0

Почему вы не можете использовать кортежи? Если речь идет только об именах атрибутов, есть ['namedtuple'] (http://docs.python.org/py3k/library/collections.html#collections.namedtuple). – delnan

+0

Можете ли вы использовать 'hash (tuple (self))'? – WolframH

ответ

1

Этот код в порядке. Вы делаете копию списка, что может быть немного медленным.

def __hash__(self): 
    return hash(tuple(self.list_attribute)) 

У вас есть несколько вариантов, если вы хотите быть быстрее.

  • магазин list_attribute как кортеж, а не список (после того, как он полностью построен)
  • вычисляет хэш один раз в инициализации времени и хранить хэш-значение. Вы можете сделать это, потому что ваш класс неизменен, поэтому хэш никогда не изменится.
  • Напишите свою собственную функцию хеширования. Вот hash function for tuple, сделайте что-нибудь подобное.
+0

Учитывая, что я сейчас укоротил вопрос, чтобы сосредоточиться только на случае подкласса, опция кортежа исчезает (поскольку она не может быть изменена в '__init__').Вычисление на '__init__' - отличная идея - но мне интересно, разве это не хорошая идея * всегда *, а не только в этом случае? Тем не менее, это будет медленнее, чем третий вариант, конечно. – max

+0

Все зависит от того, сколько раз объект будет хэширован. Если общий случай равен 0, то вы не хотите делать это раньше времени. Если общий случай - * много *, то предварительная компиляция лучше. –

+0

Хранение хэша также отнимает память, кстати. –

1

Вы можете обратиться к tupleself:

class State(list): 
    def __hash__(self): 
     return hash((self.some_attribute, tuple(self))) 

tuple -ную self занимает около половины времени всего процесса хеширования:

from timeit import timeit 

setup = "from __main__ import State; s = State(range(1000)); s.some_attribute = 'foo'" 
stmt = "hash(s)" 
print(timeit(stmt=stmt, setup=setup, number=100000)) 

setup = "r = list(range(1000))" 
stmt = "tuple(r)" 
print(timeit(stmt=stmt, setup=setup, number=100000)) 

отпечатки

0.9382011891054844 
0.3911763069244216 
+0

Спасибо. Это не кажется слишком плохим. – max

1

Это скорее комментарий, чем ответ, но слишком долго, чтобы быть комментарием. Так можно получить доступ к атрибутам экземпляра изнутри __new__:

class Data(tuple): 
    def __new__(klass, arg): 
     data_inst = tuple.__new__(klass, arg) 
     data_inst.min = min(data_inst) 
     data_inst.max = max(data_inst) 
     return data_inst 

>>> d = Data([1,2,3,4]) 
>>> d 
(1, 2, 3, 4) 
>>> d.min 
1 
>>> d.max 
4 
>>> d1 = Data([1,2,3,4,5,6]) 
>>> d1.max 
6 
>>> d.max 
4 
+0

Но это были бы атрибуты класса, а не атрибут экземпляра. Попробуйте 'd1 = Data ([1,2,3,4])', а затем вы увидите, что 'd1.min is d.min' оценивается как True. Вы не можете разделить их между экземплярами. – max

+0

Я так не думаю, попробуйте –

+0

А вы правы. Мой плохой, 'is' оценивается только True, потому что это небольшие числа, которые повторно используют один и тот же объект' int'. Ухоженная! Мне нужно будет хранить промежуточные вычисления до тех пор, пока * после * я не буду называть 'tuple .__ new__', но это нормально, я думаю. – max

Смежные вопросы