如何在初始化时创建和存储类的实例?

时间:2012-12-31 15:27:36

标签: python python-3.x

使用Python 3.3,我想将一个类Test绑定到另一个名为TestManager的类,以便管理器创建Test的实例并存储它们以便以后访问它们。

简而言之(我的意思是,Python shell ...),我希望能够做到这一点(假设nameTest的属性):

> t = Test.objects.get(id=3)
> t.name
# Returns 'Name 3'

诀窍是我的对象集合是一个“静态”集合,从某种意义上说它是首先创建的(不是由任何用户创建),然后从不修改或删除,也不删除或编辑它的记录。这是固定的。 所以这是我尝试的代码:

class TestManager:
    def __init__(self, *args, **kwargs):
        self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]

    def get(self, id):
        return self._tests[id]

class Test:
    objects = TestManager()

    def __init__(self, name=''):
        self.name = name

Aaaand,正如预期的那样,由于循环初始化而NameError: global name 'Test' is not defined。理想情况下,我应该在管理器中使用create()方法来处理列表中的元素(而不是__init__()),但这意味着创建不是在管理器中完成的,而是别处。

到目前为止,我提出的“最佳”解决方案是首先检查get()方法,如果列表为空,那么调用fill_the_damn_list()方法,但它似乎非常hackish对我来说。另一种方法是使用dict而不是列表,并在第一个get()动态创建实例。后者的优点是它不会创建无用的/从不get() - ed的实例,但总共只有一百个,我不确定它真的重要,这个解决方案的hackish-ness看起来和我一样......

由于我对Python很新(如果不够清楚......),我想知道是否有更好的方法来做到这一点并保持简单。如果需要,我也可以重构,但我还没有找到更好的解决方案......

2 个答案:

答案 0 :(得分:1)

我完全同意肖恩的评论:你的设计很奇怪,而且我觉得很无用,这甚至在开始使用之前就会引起问题。无论如何,如果你想这样做,你可以使用很多不同的方法。

简单的方法:

class TestManager:
    def __init__(self, *args, **kwargs):
        self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]

    def get(self, id):
        return self._tests[id]

class Test:
    objects = None

    def __init__(self, name=''):
        self.name = name

Test.objects = TestManager()

另一种方法可以使用装饰器:

>>> class TestManager(object):
...     def __init__(self, *args, **kwargs):
...             self._tests = []
...     def init_class(self, cls):
...             self._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
...             cls.objects = self
...             return cls
...     def get(self, id):
...             return self._tests[id]
... 
>>> manager = TestManager()
>>> @manager.init_class
... class Test(object):
...     def __init__(self, name=''):
...             self.name = name
... 
>>> manager.get(5)
<__main__.Test object at 0x7f4319db8110>

如果TestManager是Singleton,上面的配方有效,但如果它不是单身,你只需记得在访问类实例之前调用TestManager.init_class(TheClass),这可以在你的任何地方完成代码。

您也可以使用getter:

>>> class TheGetter(object):
...     def __init__(self, cls):
...             self._cls = cls
...             self._inst = None
...     def __get__(self, inst, owner):
...             if self._inst is None:
...                     self._inst = self._cls()
...             return self._inst
... 
>>> class Test(object):
...     objects = TheGetter(TestManager)
...     def __init__(self, name):
...             self.name = name
... 
>>> Test.objects.get(5)
<__main__.Test object at 0x7f431690c0d0>

答案 1 :(得分:1)

您的设计似乎有点奇怪 - 不清楚为什么Test类需要引用TestManger实例。无论如何,我认为以下将会实现这一目标。它使用元类来创建objectsTest属性,将所需的_tests属性添加到它创建的TestManger实例中 - - 我认为,所有这些都使得这个问题变得非常特别...... ; - )

class TestManager:
    def __init__(self, *args, **kwargs):
        print('creating TestManager')

    def get(self, id):
        return self._tests[id]

class TestMetaClass(type):
    def __new__(mcl, name, bases, classdict):
        # add an "objects" attribute to the class being created
        classdict['objects'] = tm = TestManager()
        cls = type.__new__(mcl, name, bases, classdict)
        # add a "_tests" attribute to the TestManager instance just created
        # (can't use class's name, since it hasn't been returned yet)
        tm._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
        return cls

class Test(metaclass=TestMetaClass):
    def __init__(self, name=''):
        self.name = name

t = Test.objects.get(3)
print(t.name)