使用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
Aaaand,正如预期的那样,由于循环初始化而NameError: global name 'Test' is not defined
。理想情况下,我应该在管理器中使用create()
方法来处理列表中的元素(而不是__init__()
),但这意味着创建不是在管理器中完成的,而是别处。
到目前为止,我提出的“最佳”解决方案是首先检查get()
方法,如果列表为空,那么调用fill_the_damn_list()
方法,但它似乎非常hackish对我来说。另一种方法是使用dict而不是列表,并在第一个get()
动态创建实例。后者的优点是它不会创建无用的/从不get()
- ed的实例,但总共只有一百个,我不确定它真的重要,这个解决方案的hackish-ness看起来和我一样......
由于我对Python很新(如果不够清楚......),我想知道是否有更好的方法来做到这一点并保持简单。如果需要,我也可以重构,但我还没有找到更好的解决方案......
答案 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
实例。无论如何,我认为以下将会实现这一目标。它使用元类来创建objects
类的Test
属性,将所需的_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)