2

TestPython 3.3 を使用して、クラスを別のクラスにバインドしTestManagerて、マネージャーがインスタンスを作成しTestて保存し、後でそれらにアクセスできるようにしたいと考えています。

一言で言えば(つまり、Pythonシェル...)、これを実行できるようにしたいです(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()ことですが、私には非常にハックに思えます。これを行う別の方法は、リストの代わりに dict を使用し、最初にその場でインスタンスを作成することget()です。後者の利点は、役に立たない/決してget()-ed インスタンスを作成しないことですが、合計で 100 個しかないため、それが本当に重要かどうかはわかりません。また、このソリューションのハック性は、自分...

私は Python にまったく慣れていないので (十分に明確でない場合は...)、それを実行してシンプルに保つためのより良い方法があるかどうか疑問に思います。必要に応じてリファクタリングしても構いませんが、まだより良い解決策が見つかりません...

4

2 に答える 2

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 に答える
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 に答える