Повторно использовать существующие объекты для неизменных объектов? - PullRequest
11 голосов
/ 02 марта 2011

Как в Python можно повторно использовать существующие одинаковые неизменяемые объекты (как это сделано для str)? Можно ли это сделать, просто определив метод __hash__, или он требует более сложных мер?

Ответы [ 3 ]

13 голосов
/ 02 марта 2011

Если вы хотите создать с помощью конструктора класса и вернуть ему ранее созданный объект, вам нужно будет предоставить метод __new__ (поскольку к моменту достижения __init__ объект уже создан).

Вот простой пример - если значение, использованное для инициализации, было замечено раньше, то возвращается ранее созданный объект, а не созданный новый:

class Cached(object):
    """Simple example of immutable object reuse."""

    def __init__(self, i):
        self.i = i

    def __new__(cls, i, _cache={}):
        try:
            return _cache[i]
        except KeyError:
            # you must call __new__ on the base class
            x = super(Cached, cls).__new__(cls)
            x.__init__(i)
            _cache[i] = x
            return x

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

>>> a = Cached(100)
>>> b = Cached(200)
>>> c = Cached(100)
>>> a is b
False
>>> a is c
True
3 голосов
/ 02 марта 2011

Для этого есть два решения «программной инженерии», которые не требуют каких-либо низкоуровневых знаний Python.Они применяются в следующих сценариях:

Первый сценарий: Объекты вашего класса «равны», если они построены с одинаковыми параметрами конструктора, и равенство не изменится со временем после построения, Решение: Используйте фабрику, которая хэширует параметры конструктора:

class MyClass:
  def __init__(self, someint, someotherint):
    self.a = someint
    self.b = someotherint

cachedict = { }
def construct_myobject(someint, someotherint):
  if (someint, someotherint) not in cachedict:
    cachedict[(someint, someotherint)] = MyClass(someint, someotherint)
  return cachedict[(someint, someotherint)]

Этот подход по существу ограничивает экземпляры вашего класса одним уникальным объектом для каждой отдельной входной пары.Есть и очевидные недостатки: не все типы легко хешируются и т. Д.

Второй сценарий: Объекты вашего класса изменчивы, и их «равенство» может меняться со временем. Решение: определить реестр на уровне класса равных экземпляров:

class MyClass:
  registry = { }

  def __init__(self, someint, someotherint, third):
    MyClass.registry[id(self)] = (someint, someotherint)
    self.someint = someint
    self.someotherint = someotherint
    self.third = third

  def __eq__(self, other):
    return MyClass.registry[id(self)] == MyClass.registry[id(other)]

  def update(self, someint, someotherint):
    MyClass.registry[id(self)] = (someint, someotherint)

В этом примере объекты с одинаковой парой someint, someotherint равны, тогда как третий параметр не учитываетХитрость заключается в том, чтобы синхронизировать параметры в registry.В качестве альтернативы update вы можете вместо этого переопределить getattr и setattr для своего класса;это обеспечит синхронизацию любого назначения foo.someint = y с вашим словарем на уровне класса.Смотрите пример здесь .

3 голосов
/ 02 марта 2011

Полагаю, вам нужно будет сохранить dict {args: object} уже созданных экземпляров, затем переопределить метод класса '__new__, чтобы проверить в этом словаре и вернуть соответствующий объект, если он уже существовал.Обратите внимание, что я не реализовал и не проверил эту идею.Конечно, строки обрабатываются на уровне C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...