2011-12-13 3 views
5

Я пытаюсь подклассифицировать объект set в Python, используя код, подобный приведенному ниже, но я не могу найти разумное определение __repr__.Определение __repr__ при установке подкласса в Python

class Alpha(set): 
    def __init__(self, name, s=()): 
     super(Alpha, self).__init__(s) 
     self.name = name 

Я хотел бы определить __repr__ таким образом, что я могу получить следующий вывод:

>>> Alpha('Salem', (1,2,3)) 
Alpha('Salem', set([1, 2, 3])) 

Однако, если я не отменяю __repr__, выход я получаю игнорирует name значение ...

>>> Alpha('Salem', (1,2,3)) 
Alpha([1, 2, 3]) 

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

Это работает, но создает новый экземпляр набора для __repr__, которые затем будут утилизировать кажется неуклюжим и неэффективным для меня.

Есть ли лучший способ определить __repr__ для такого класса?

Редактировать: Другое решение, которое произошло со мной: я могу хранить набор локально. Это кажется немного опрятным, чем другие варианты (создание и уничтожение чего-то для каждого вызова __repr__ или использование какой-либо формы манипуляции с строкой), но все же кажется менее идеальным для меня.

class Alpha(set): 
    def __init__(self, name, s=()): 
     super(Alpha, self).__init__(s) 
     self.name = name 
     self._set = set(s) 
    def __repr__(self): 
     return "%s(%r, %r)" % (self.__class__.__name__, self.name, self._set) 
+5

способ вызова 'super', вы будете получить бесконечную рекурсию, если подклассы пытаются называть '__init__'. Причина 'super' явно принимает класс в том, что он знает, где продолжить в порядке разрешения метода (MRO). Передайте 'Alpha' (или если это указывает на 3.x, как указано в тегах, просто используйте' super() '- он делает что-то как-то). – delnan

+0

@ delnan: Dang. Спасибо за это. И я подумал, что я умею избегать указания класса явно. –

+0

@ delnan: По какой-то причине Sven Marnach briely отметил этот вопрос как Python 3.x. Я на самом деле использую Python 2.6. –

ответ

7

Я думаю, что у меня есть кое-что, что дает вам то, что вы хотите, в дополнение к показу некоторых тестов. Они почти все эквивалентны, хотя я уверен, что есть разница в использовании памяти.

#!/usr/bin/env python 

import time 

class Alpha(set): 
    def __init__(self, name, s=()): 
      super(Alpha, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      return '%s(%r, set(%r))' % (self.__class__.__name__, 
             self.name, 
             list(self)) 

class Alpha2(set): 
    def __init__(self, name, s=()): 
      super(Alpha2, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      return '%s(%r, set(%r))' % (self.__class__.__name__, 
             self.name, 
             set(self)) 

class Alpha3(set): 
    def __init__(self, name, s=()): 
      super(Alpha3, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      rep = super(Alpha3, self).__repr__() 
      rep = rep.replace(self.__class__.__name__, 'set', 1) 
      return '%s(%r, %s)' % (self.__class__.__name__, 
            self.name, 
            rep) 

def timeit(exp, repeat=10000): 
    results = [] 
    for _ in xrange(repeat): 
     start = time.time() 
     exec(exp) 
     end = time.time()-start 
     results.append(end*1000) 
    return sum(results)/len(results) 

if __name__ == "__main__": 
    print "Alpha(): ", timeit("a = Alpha('test', (1,2,3,4,5))") 
    print "Alpha2(): ", timeit("a = Alpha2('test', (1,2,3,4,5))") 
    print "Alpha3(): ", timeit("a = Alpha3('test', (1,2,3,4,5))") 

Результаты:

Альфа(): +0,0287627220154

Альфа 2(): +0,0286467552185

Alpha3(): +0,0285225152969

+0

Я, я бы выбрал для 'list()', поскольку это кажется самым простым, но, очевидно, это не имеет большого значения. –

+1

Я готов поспорить, по памяти, что первый и второй менее эффективны, так как они создают и отбрасывают объекты. Но это просто предположение, фактически не проверяя память/процессор. Третий пример получает строку и переформатирует ее. – jdi

+0

Возможно. Я предполагаю, что это вопрос, это 'set()' или 'list()' быстрее, чем 2 вызова 'Alpha3' (в тесте можно сказать« да »). –

2

Я не мог найти лучшего способа, чем это сделать. Полагаю, это лучше, чем выбрасывать сет.

(Python 2.x)

>>> class Alpha(set): 
...  def __init__(self, name, s=()): 
...    super(Alpha, self).__init__(s) 
...    self.name = name 
...  def __repr__(self): 
...    return 'Alpha(%r, set(%r))' % (self.name, list(self)) 
... 
>>> Alpha('test', (1, 2)) 
Alpha('test', set([1, 2])) 

Или, если вам не нравится имя жёстко прописанного класса (хотя это на самом деле не имеет значения).

>>> class Alpha(set): 
...  def __init__(self, name, s=()): 
...    super(Alpha, self).__init__(s) 
...    self.name = name 
...  def __repr__(self): 
...    return '%s(%r, set(%r))' % (self.__class__.__name__, self.name, list(self)) 
... 
>>> Alpha('test', (1, 2)) 
Alpha('test', set([1, 2])) 
+1

Я бы не стал hardcode classname и вместо этого использовал 'self .__ class __.__ name__' (например, me_and did) – gecco

+1

@gecco: Личные предпочтения. Я не вижу особого смысла в том, чтобы не жестко кодировать его (если у вас нет классов, которые подклассифицируют его), тем более что некоторые места по-прежнему требуют его (супервызов). Это легко изменить в любом случае. Но я добавил не-hardcoded версию, а также для каждого запроса. –

+1

Я согласен с @JohnDoe. Я не считаю это критичным, когда вам уже нужно явно использовать имя класса для вызовов super(). Но да, это немного более динамично. – jdi

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