2

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

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

> 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

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

到目前为止,我想出的“最佳”解决方案是首先在get()方法中检查列表是否为空,然后调用一个fill_the_damn_list()方法,但对我来说这似乎很hackish。另一种方法是使用字典而不是列表,并首先动态创建实例get()。后一个的优点是它不会创建无用/从未创建过get()的实例,但总共只有一百个,我不确定它是否真的重要,而且这个解决方案的 hackish-ness 看起来与我...

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

4

2 回答 2

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,但如果它不是单例,你只需要记住TestManager.init_class(TheClass)在访问类实例之前调用,这可以在你的代码中的任何地方完成。

您也可以为此使用吸气剂:

>>> 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>
于 2012-12-31T15:59:21.560 回答
1

您的设计似乎有点奇怪——不清楚为什么Test类需要引用TestManger实例。无论如何,我认为以下将实现这一点。它使用元类来创建类的属性objects并将您想要的属性添加到它创建的实例中——这一切都使这成为一个相当奇特的答案……我想是合适的。;-)Test_testsTestManger

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)
于 2012-12-31T18:50:44.313 回答