2009-03-26 2 views
0

Вот проблема, которую я пытаюсь решить (я упростил актуальную проблему, но это должно дать вам всю необходимую информацию). У меня есть иерархия, как так:Hierarchy/Flyweight/Instancing Problem in Python

1.A 
1.B 
1.C 
2.A 
3.D 
4.B 
5.F 

(Это трудно для иллюстрации - каждое число является родителем, каждая буква является ребенок).

  1. Создание экземпляра объектов «letter» дорого (IO, стоимость базы данных и т. Д.), Поэтому это должно выполняться только один раз.

  2. Иерархия должна быть легко ориентирована.

  3. Дети в иерархии должны иметь только одного родителя.

  4. Изменение содержимого объектов букв должно быть возможным непосредственно из объектов в иерархии.

  5. Должен быть центральный магазин, содержащий все объекты «письма» (и только те, что находятся в иерархии).

  6. Объекты «письмо» и «номер» должны быть доступны для создания из конструктора (например, Letter (** kwargs)).

  7. Совершенно приемлемо ожидать, что при изменении буквы из иерархии все остальные буквы будут соблюдать одно и то же изменение.

Надеюсь, что это не слишком абстрактно, чтобы проиллюстрировать проблему.

Какой был бы лучший способ решить это? (Тогда я вывешу мое решение)

Вот пример сценария:

one = Number('one') 
a = Letter('a') 
one.addChild(a) 
two = Number('two') 
a = Letter('a') 
two.addChild(a) 

for child in one: 
    child.method1() 
for child in two: 
    print '%s' % child.method2() 
+0

Как это иерархия? Это похоже на простую связь между «числом» и «буквой». –

+0

Снова я просто пытаюсь показать вам подмножество проблемы (это на самом деле иерархия типа 1.ABCD), потому что фактические данные намного сложнее, чем это, специфичные для приложения, и потребуют много работы для объясните, поэтому я пытаюсь представить эту абстрагированную от нерелевантных сложностей. – Dan

+0

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

ответ

0

Основной подход будет использовать встроенные типы данных. Если я получаю ваш дрейф, то объект Letter должен быть создан на заводе с кешем dict, чтобы сохранить ранее созданные объекты Letter. Завод будет создавать только один объект Letter для каждого ключа.

Number объект может быть подклассом list, который будет держать Letter объекты, так что append() может быть использован для добавления ребенка. A list легко ориентироваться.

Неочищенный контур кэширования завода:

>>> class Letters(object): 
...  def __init__(self): 
...   self.cache = {} 
...  def create(self, v): 
...   l = self.cache.get(v, None) 
...   if l: 
...    return l 
...   l = self.cache[v] = Letter(v) 
...   return l 
>>> factory=Letters() 
>>> factory.cache 
{} 
>>> factory.create('a') 
<__main__.Letter object at 0x00EF2950> 
>>> factory.create('a') 
<__main__.Letter object at 0x00EF2950> 
>>> 

чтобы выполнить требование 6 (конструктор), вот более надуманный пример, используя __new__, конструктора кэширования. Это похоже на Recipe 413717: Caching object creation.

class Letter(object): 
    cache = {} 

    def __new__(cls, v): 
     o = cls.cache.get(v, None) 
     if o: 
      return o 
     else: 
      o = cls.cache[v] = object.__new__(cls) 
      return o 

    def __init__(self, v): 
     self.v = v 
     self.refcount = 0 

    def addAsChild(self, chain): 
     if self.refcount > 0: 
      return False 
     self.refcount += 1 
     chain.append(self) 
     return True 

Тестирование функциональности кэша

>>> l1 = Letter('a') 
>>> l2 = Letter('a') 
>>> l1 is l2 
True 
>>> 

Для соблюдения одного родителя, вам нужен метод на Letter объектов (не Number) - с эталонным счетчиком. Когда вызывается для выполнения добавления, он отказывается от добавления, если счетчик больше нуля.

l1.addAsChild(num4) 
+0

Это хорошее начало, но оно не удовлетворяет 3 или 6. – Dan

+0

для 6, вы можете с легкостью скрыть завод позади любого вызываемого. Вы уверены в требовании конструктора? – gimel

+0

Прохладный, это больше похоже на то, как я закончил его реализацию, так что кажется, что я на правильных строках. Одна вещь, которую я нашел, - __init__ всегда выполняется после __new__ (независимо от того, возвращает ли он существующий объект), что хорошо в этом случае, но что, если __init__ делает намного больше? – Dan

0

Создание экземпляра объектов «письмо» дорого (IO затраты базы данных и т.д.), так что должно быть сделано только один раз.

Здесь я начну. Кажется, что было бы легко уйти с пути и дать вам гораздо больше свободы для реализации последних 6.

Возможно, вы могли бы рассмотреть решение, подобное memcached?

0

Интересно, слишком ли вы сделали эту проблему слишком абстрактной, чтобы люди могли дать полезные ответы. Мне кажется, что вы можете что-то делать с генетическими кодами, и если это так, вы должны посмотреть на BioPython. Мало того, что он поставляется с библиотеками для управления генетическими последовательностями и доступа к репозиториям генных данных, но есть также сообщество людей, использующих биологию, которые могут посоветовать конкретные конкретные практики, зная используемые данные и манипуляции, которые люди хотят делать ,