Как создавать и хранить экземпляры класса при инициализации?
Используя 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()
, но для меня это кажется очень хакерским. Другой способ сделать это – использовать dict вместо списка и создавать экземпляры «на лету» сперва get()
. Преимущество последнего состоит в том, что он не создает бесполезных / никогда не get()
экземпляров, но всего лишь сотню из них в целом, я не уверен, что это действительно имеет значение, и хакерство этого решения выглядит вполне то же самое для меня…
Поскольку я довольно новичок в Python (если это недостаточно ясно …), мне интересно, есть ли лучший способ сделать это и сохранить его простым. Я также согласен на рефакторинг, если это необходимо, но я еще не нашел лучшего решения …
- Python – перемещение строки из одного файла в другой
- Расширение Python: обработка массивов numpy
- Pandas Groupby и сумма с двумя переменными –
- Sqlite3 Запрос INSERT ERROR?
- Возможно ли сохранить структуру блока YAML при сбрасывании анализируемого документа?
Ваш дизайн кажется немного странным – непонятно, почему классу Test
требуется ссылка на экземпляр TestManger
. Несмотря на это, я думаю, что следующее произойдет. Он использует метакласс для создания атрибута objects
класса Test
и добавляет атрибут _tests
вы хотите TestManger
экземпляр 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)
Я полностью согласен с комментарием Шона: ваш дизайн странный и, я думаю, совершенно бесполезен, и это вызывает проблемы даже перед тем, как начать использовать его. В любом случае, если вы хотите сделать это, вы можете использовать множество разных методов.
Простой способ:
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)
перед доступом к экземплярам класса, и это можно сделать в любом месте вашего кода.
Вы также можете использовать геттеры для этого:
>>> 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>
- Найти и редактировать SubElement в XML с помощью Python ElementTree
- Python: Итерация по двум спискам и замена элементов в одном списке1 с помощью элемента из списка2
- присоединить одну строку слова в файле
- Тест Python Nose2 не заканчивается при вызове метода класса
- Повторный запрос Redshift + SQLAlchemy
- «QStackedWidget.setCurrentIndex»: он не работает или метка ошибки
- Ошибка при печати случайной строки из текстового файла
- Использование QProcess.finished () в Python 3 и PyQt
- использовать ipython для выполнения REAL-кода в pycharm
- Как создать автономный исполняемый файл из сценария Python 3?
- Python – получить полное расстояние от долготы и широты GPS