如何创建一个不会重新创建具有相同输入参数的对象的类

发布于 2024-07-15 06:26:00 字数 1371 浏览 7 评论 0原文

我正在尝试创建一个不会重新创建具有相同输入参数的对象的类。 当我尝试使用与创建已存在对象相同的参数实例化一个类时,我只希望我的新类返回指向已创建(昂贵创建的)对象的指针。 这是我到目前为止所尝试过的:

class myobject0(object):
# At first, I didn't realize that even already-instantiated
# objects had their __init__ called again
instances = {}
def __new__(cls,x):
    if x not in cls.instances.keys():
        cls.instances[x] = object.__new__(cls,x)
    return cls.instances[x]
def __init__(self,x):
    print 'doing something expensive'

class myobject1(object):
    # I tried to override the existing object's __init__
    # but it didnt work.
    instances = {}
    def __new__(cls,x):
        if x not in cls.instances.keys():
            cls.instances[x] = object.__new__(cls,x)
        else:
            cls.instances[x].__init__ = lambda x: None
        return cls.instances[x]
    def __init__(self,x):
        print 'doing something expensive'

class myobject2(object):
    # does what I want but is ugly
    instances = {}
    def __new__(cls,x):
        if x not in cls.instances.keys():
            cls.instances[x] = object.__new__(cls,x)
            cls.instances[x]._is_new = 1
        else:
            cls.instances[x]._is_new = 0
        return cls.instances[x]
    def __init__(self,x):
        if self._is_new:
            print 'doing something expensive'

这是我第一次尝试覆盖 __new__ ,并且我确信我没有以正确的方式处理它。 请让我正视一下。

I am trying to create a class that doesn't re-create an object with the same input parameters. When I try to instantiate a class with the same parameters that were used to create an already-existing object, I just want my new class to return a pointer to the already-created (expensively-created) object. This is what I have tried so far:

class myobject0(object):
# At first, I didn't realize that even already-instantiated
# objects had their __init__ called again
instances = {}
def __new__(cls,x):
    if x not in cls.instances.keys():
        cls.instances[x] = object.__new__(cls,x)
    return cls.instances[x]
def __init__(self,x):
    print 'doing something expensive'

class myobject1(object):
    # I tried to override the existing object's __init__
    # but it didnt work.
    instances = {}
    def __new__(cls,x):
        if x not in cls.instances.keys():
            cls.instances[x] = object.__new__(cls,x)
        else:
            cls.instances[x].__init__ = lambda x: None
        return cls.instances[x]
    def __init__(self,x):
        print 'doing something expensive'

class myobject2(object):
    # does what I want but is ugly
    instances = {}
    def __new__(cls,x):
        if x not in cls.instances.keys():
            cls.instances[x] = object.__new__(cls,x)
            cls.instances[x]._is_new = 1
        else:
            cls.instances[x]._is_new = 0
        return cls.instances[x]
    def __init__(self,x):
        if self._is_new:
            print 'doing something expensive'

This is my first venture into overriding __new__ and I'm convinced I'm not going about it the right way. Set me straight, please.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

原来分手还会想你 2024-07-22 06:26:00

这是一个类装饰器,用于使类成为多类:(

def multiton(cls):
   instances = {}
   def getinstance(id):
      if id not in instances:
         instances[id] = cls(id)
      return instances[id]  
   return getinstance

这是 PEP 318 中单例装饰器的一个轻微变体。)

然后,要使类成为多类,请使用装饰器:

@multiton
class MyObject( object ):
   def __init__( self, arg):
      self.id = arg
      # other expensive stuff

现在,如果您使用相同的 id 实例化 MyObject,你得到相同的实例:

a = MyObject(1)
b = MyObject(2)
c = MyObject(2)

a is b  # False
b is c  # True

Here's a class decorator to make a class a multiton:

def multiton(cls):
   instances = {}
   def getinstance(id):
      if id not in instances:
         instances[id] = cls(id)
      return instances[id]  
   return getinstance

(This is a slight variant of the singleton decorator from PEP 318.)

Then, to make your class a multiton, use the decorator:

@multiton
class MyObject( object ):
   def __init__( self, arg):
      self.id = arg
      # other expensive stuff

Now, if you instantiate MyObject with the same id, you get the same instance:

a = MyObject(1)
b = MyObject(2)
c = MyObject(2)

a is b  # False
b is c  # True
从﹋此江山别 2024-07-22 06:26:00

首先,在 Python 中使用大写的类名。

其次,使用工厂设计模式来解决这个问题。

class MyObject( object ):
    def __init__( self, args ):
        pass # Something Expensive

class MyObjectFactory( object ):
    def __init__( self ):
        self.pool = {}
    def makeMyObject( self, args ):
        if args not in self.pool:
            self.pool[args] = MyObject( args )
        return self.pool[args]

这比使用 new 和类级别的对象池要简单得多。

First, use Upper Case Class Names in Python.

Second, use a Factory design pattern to solve this problem.

class MyObject( object ):
    def __init__( self, args ):
        pass # Something Expensive

class MyObjectFactory( object ):
    def __init__( self ):
        self.pool = {}
    def makeMyObject( self, args ):
        if args not in self.pool:
            self.pool[args] = MyObject( args )
        return self.pool[args]

This is much simpler than fooling around with new and having class level pools of objects.

再可℃爱ぅ一点好了 2024-07-22 06:26:00

这是我对 Jerry 方法的实现,使用数组作为池

def pooled(cls):
    """
    decorator to add to a class, so that when you call YourClass() it actually returns an object from the pool
    """

    pool = []

    def get_instance(*args, **kwargs):
        try:
            instance = pool.pop()
        except IndexError:
            instance = cls(*args, **kwargs)
        returned_instance = yield instance
        pool.append(returned_instance)
        print(len(pool))
        yield

    return get_instance


@pooled
class MyClass():
    def __init__(self, num):
      self.num = num


for i in range(10):
    m_gen =MyClass(i)
    n_gen = MyClass(i + 5)
    m = next(m_gen)
    n = next(n_gen)
    print(f'm num: {m.num}')
    print(f'n num: {n.num}')
    m_gen.send(m)
    n_gen.send(n)

,然后使用元类的另一种方法,以便您可以继承功能。 这个使用weakreaf valuedicts作为池,因此对象可以更好地被垃圾收集

import weakref
  
class PooledMeta(type):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._pool = weakref.WeakValueDictionary()

  def __call__(self, *args):
    if args in self._pool:
      print('got cached')
      return self._pool[args]
    else:
      # print(self._pool.valuerefs())
      instance = super().__call__(*args)
      self._pool[args] = instance
      return instance

class MyPooled(metaclass=PooledMeta):
  def __init__(self, num):
    print(f'crating: {num}')
    self.num = num

class MyPooledChild(MyPooled):
  def __init__(self, num):
    print(f'crating child: {num}')
    self.num = num

p = []
for i in range(10):
  m = MyPooled(i)
  n = MyPooledChild(i)
  p.extend([m,n])

Here is my implementation of Jerry's way, using an array as the pool

def pooled(cls):
    """
    decorator to add to a class, so that when you call YourClass() it actually returns an object from the pool
    """

    pool = []

    def get_instance(*args, **kwargs):
        try:
            instance = pool.pop()
        except IndexError:
            instance = cls(*args, **kwargs)
        returned_instance = yield instance
        pool.append(returned_instance)
        print(len(pool))
        yield

    return get_instance


@pooled
class MyClass():
    def __init__(self, num):
      self.num = num


for i in range(10):
    m_gen =MyClass(i)
    n_gen = MyClass(i + 5)
    m = next(m_gen)
    n = next(n_gen)
    print(f'm num: {m.num}')
    print(f'n num: {n.num}')
    m_gen.send(m)
    n_gen.send(n)

and then another way using metaclasses so you can inherit the functionality. This one uses weakreaf valuedicts as the pool, so the objects get garbage collected better

import weakref
  
class PooledMeta(type):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._pool = weakref.WeakValueDictionary()

  def __call__(self, *args):
    if args in self._pool:
      print('got cached')
      return self._pool[args]
    else:
      # print(self._pool.valuerefs())
      instance = super().__call__(*args)
      self._pool[args] = instance
      return instance

class MyPooled(metaclass=PooledMeta):
  def __init__(self, num):
    print(f'crating: {num}')
    self.num = num

class MyPooledChild(MyPooled):
  def __init__(self, num):
    print(f'crating child: {num}')
    self.num = num

p = []
for i in range(10):
  m = MyPooled(i)
  n = MyPooledChild(i)
  p.extend([m,n])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文