python — Как создать новый экземпляр класса с новыми рандомными данными?
Вопрос задан
Изменён 1 год 4 месяца назад
Просмотрен 722 раза
Условно есть такой код:
import random class Test: number: str = random.randint(100, 500) test1 = Test() test2 = Test() assert test1.number == test2.number
Создаются 2 разных объекта, но значение number у них будет всегда одинаковое.
Как создать несколько экземпляров класса, в которых будут каждый раз генерироваться случайные значения number
(и чтобы вручную не передавать туда number=...
)? Чтобы выполнялось такое условие:
test1 = Test() test2 = Test() assert test1.number != test2. number
- python
- классы
- pydantic
В обычном случае, вам подойдёт вариант, предложенный @strawdog:
class Test: number: str def __init__(): self.number = random.randint(100, 500)
Если же вы используете pydantic.BaseModel
, то данные можно передать в super().__init__(**data)
при инициализации:
class Test(pydantic.BaseModel): number: str def __init__(self, number=None, **data): super().__init__( number=random.randint(100, 500) if number is None else number, **data )2
А вы не пробовали записывать класс в каноническом виде, с функцией инициализации экземпляров? в противном случае рандомизация у вас происходит один раз для родительского объекта.
import random class Test: def __init__(self): self.number = random. randint(100, 500) test1 = Test() test2 = Test() test1.number==test2.number #False3
Определение поля в классе в pydantic — это значение по умолчанию для всех экземпляров, для которых такое значение не задано. По-этому, то, что вы наблюдаете — это нормальное ожидаемое поведение.
Если вам нужно создать экземпляры со случайными значениями, то делайте это в конструкторе:
class Test(pydantic.BaseModel): number: str def __init__(self, **data): if 'number' not in data: data['number'] = random.randint(100, 500) super().__init__(**data)
Ну и еще есть factoryboy как раз для генерации тестовых данных.
1Всем спасибо за ответы, они действительно правильные. Но мне кажется более изящным и читабельным следующее решение:
import random from pydantic import BaseModel from pydactory import Factory class Test(BaseModel): number: int class TestFactory(Factory[Test]): number: int = lambda: random.randint(100, 500) test1: Test = TestFactory.build() test2: Test = TestFactory.build() assert test1.number != test2.number # True
Напишите, пожалуйста, в комментариях, что вы думаете по поводу данного решения.
1В pydantic
и dataclasses
можно указать default_factory
(«фабрику» значения по умолчанию) для поля. Обычно это используется для инициализации поля пустым списком (или другим контейнером) например
, но можно передать лямбду, которая вызывает random.randint(100, 500)
.
Вариант с использованием pydantic
:
from pydantic import BaseModel, Field import random class Test(BaseModel): number: str = Field(default_factory = lambda: random.randint(100, 500)) test1 = Test() test2 = Test() print(repr(test1)) print(repr(test2))
Пример вывода:
Test(number=387) Test(number=487)
Аналогично, на dataclasses
:
from dataclasses import dataclass, field import random @dataclass class Test: number: str = field(default_factory = lambda: random.randint(100, 500)) test1 = Test() test2 = Test() print(test1) print(test2)
Пример вывода:
Test(number=254) Test(number=247)0
Зарегистрируйтесь или войдите
Регистрация через Google Регистрация через Facebook Регистрация через почтуОтправить без регистрации
ПочтаНеобходима, но никому не показывается
Отправить без регистрации
ПочтаНеобходима, но никому не показывается
By clicking “Отправить ответ”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.
python — Создание независимых объектов класса с полем-словарь
Смотрите, есть классы (типы) и есть объекты.
У тех и других есть свойства. Свойства объектов доступны только им, а свойства классов доступны и самим классам, и объектам тех классов.
В этом примере abc
— свойство класса Foo
, а qwerty
— свойство объектов класса, например self
говорит о том, что это принадлежит текущему объекту.
class Foo: abc = 1 def __init__(self): self.qwerty = "qwerty" f1 = Foo() f1.qwerty # свойство объекта f1 f1.abc # свойство класса Foo f2 = Foo() f2.qwerty # свойство объекта f2 f2.abc # свойство класса Foo Foo.abc # свойство класса Foo Foo.qwerty # ошибка, у класса Foo нет свойства qwerty
Это первый момент.
Второй, это то, что есть объекты, а есть ссылки на объекты.
Когда вы написали так:
abc = [1, 2, 3] zxc = abc
То скопировали не объект, а ссылку на него, поэтому обращение к методам объекта, могут его изменить, например zxc. append(4)
добавит в объект новое значение.
А теперь давайте соберем все информацию воедино.
Когда вы написали:
class SearchConfig: test = 0 metro_stations = dict()
То у класса SearchConfig
создали 2 свойства, test
и metro_stations
и когда у SearchConfig
или его объектов изменяли test
, то на самом деле вы переписывали значение свойства для текущей сущности наглядный пример:
print(SearchConfig.test) # 0 config_1 = SearchConfig() config_1.test = 1 print(config_1.test) # 1 print(SearchConfig.test) # 0 SearchConfig.test = 2 print(SearchConfig.test) # 2 print(config_1.test) # 1
Однако, когда вы обращались к metro_stations
, то вы работали с его методами, например «get,
[], которые могли изменить состояние самого объекта, а т.к. тот объект находился в свойстве класса, то обращение любого объекта к
metro_stations` вело к одному и тому же объекту.
Один и тот же объект доступен по metro_stations
:
config_1 = SearchConfig() config_2 = SearchConfig() print(id(SearchConfig.metro_stations)) print(id(config_1.metro_stations)) print(id(config_2.metro_stations))
И изменение свойства меняло объект:
print(SearchConfig.metro_stations) # {} print(config_1.metro_stations) # {} print(config_2.metro_stations) # {} SearchConfig.metro_stations[1] = 1 config_1.metro_stations.update({'abc': 123}) print(SearchConfig.metro_stations) # {1: 1, 'abc': 123} print(config_1.metro_stations) # {1: 1, 'abc': 123} print(config_2.metro_stations) # {1: 1, 'abc': 123}
ИТОГ.
Создавайте свойства для объектов (в
), особенно если свойства содержат изменяемые объекты.
Пример:
# Заглушка, чтобы код работал class MetroLines: stations = ['abc', '12'] class SearchConfig: def __init__(self): self.test = 0 self.rooms = [1, 2, 3] self. metro_stations = { i: [False] * len(x) for i, x in enumerate(MetroLines.stations) } obj1 = SearchConfig() obj2 = SearchConfig() obj2.metro_stations.get(0)[2] = True print(obj1.metro_stations) # {0: [False, False, False], 1: [False, False]} print(obj2.metro_stations) # {0: [False, False, True], 1: [False, False]}
Как создать несколько объектов класса с циклом в python?
спросил
Изменено 1 месяц назад
Просмотрено 169 тысяч раз
Предположим, вам нужно создать 10 объектов класса в python и что-то с ними сделать, например:
obj_1 = MyClass() other_object.add(obj_1) obj_2 = МойКласс() other_object.add(obj_2) . . . obj_10 = МойКласс() other_object.add(obj_10)
Как бы вы сделали это с циклом и присвоили переменную каждому объекту (например, obj_1
), чтобы код был короче? Каждый объект должен быть доступен вне цикла
obj_1. do_sth()
- питон
- класс
- объект
Этот вопрос задают каждый день в той или иной вариации. Ответ таков: держите свои данные подальше от имен переменных, и это обязательная запись в блоге.
В таком случае, почему бы не составить список объектов?
objs = [MyClass() для i в диапазоне (10)] для объекта в объектах: other_object.add(obj) объекты[0].do_sth()2
вы можете использовать список, чтобы определить его.
объекты = список() для я в диапазоне (10): objs.append(МойКласс())3
Создание словаря, как уже упоминалось, но в этом случае каждый ключ имеет имя имени объекта, который вы хотите создать. Затем значение устанавливается как класс, который вы хотите создать, см., например:
класс MyClass: def __init__(я, имя): self.name = имя self.checkme = 'потрясающий {}'. format(self.name) ... instanceNames = ['красный', 'зеленый', 'синий'] # Здесь вы используете словарь держатель = {имя: MyClass (имя = имя) для имени в instanceNames}
Затем вы просто вызываете ключ держателя, и вам будут доступны все свойства и методы вашего класса.
держатель ['красный'].checkme
вывод:
"потрясающий красный"0
Использование словаря для уникальных имен без списка имен:
класс MyClass: def __init__(я, имя): self.name = имя self.pretty_print_name() def pretty_print_name (я): print("Имя этого объекта {}.".format(self.name)) мои_объекты = {} для я в диапазоне (1,11): имя = 'obj_{}'.format(i) my_objects[имя] = my_objects.get(имя, MyClass(имя = имя))
Вывод:
"Имя этого объекта - obj_1." «Имя этого объекта — obj_2». «Имя этого объекта — obj_3». «Имя этого объекта — obj_4». «Имя этого объекта — obj_5». «Имя этого объекта — obj_6». «Имя этого объекта — obj_7». «Имя этого объекта — obj_8». "Имя этого объекта obj_9." «Имя этого объекта — obj_10».
Надеюсь, это то, что вы ищете.
класс Попробуйте: деф делать_что-то (я): напечатать «Привет» если __name__ == '__main__': список_объектов = [] для объекта в диапазоне (10): объект = попробовать () obj_list.append(obj) obj_list[0].do_something()
Вывод:
Привет2
Это решение помогает создать несколько экземпляров класса с помощью для цикла
, а также функция globals()
.
класс Cir: def __init__(я, имя): self.name = имя
Этот код определяет класс с именем Cir
с методом __init__
, который принимает одно имя аргумента и присваивает его атрибуту name
объекта.
для i в диапазоне (5): inst_name = "my_instance_" + str(i) globals()[inst_name] = Cir(inst_name)
Этот цикл создает пять экземпляров Cir
class и присваивает их глобальным переменным с именами, которые зависят от значения переменной цикла i
. Переменная inst_name
создается как строка, которая добавляет константную строку my_instance_
со строковым представлением переменной цикла i
. Затем функция globals()
возвращает словарь глобальной таблицы символов, и доступ к результирующему словарю осуществляется с использованием inst_name
в качестве ключа для добавления новой глобальной переменной с именем, указанным в inst_name
и значение вновь созданного экземпляра класса Cir
с атрибутом name, установленным на inst_name
.
печать (my_instance_3.name)
Эта строка кода выводит атрибут имени my_instance_3
и гарантирует правильность создания экземпляров.
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя электронную почту и парольОпубликовать как гость
Электронная почтаОбязательно, но не отображается
Опубликовать как гость
Электронная почтаТребуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Создание объекта с циклом — Python
plasker 1
Я разрабатываю вариант покера, в который играю я и моя семья, и пытаюсь понять, есть ли способ быстро создавать объекты-карты с переменными именами, на которые интуитивно можно ссылаться при розыгрыше руки. Вот что у меня есть на данный момент:
чисел = [2, 3, 4, 5, 6, 7, 8, 9, 10, «Валет», «Дама», «Король», «Туз»] масти = ['Пики', 'Червы', 'трефы', 'бубны'] Карта класса: def __init__(я, масть, число): костюм = костюм self.number = число if self.suit == 'Пики': костюм_ранг = 1 elif self.suit == 'Сердца': костюм_ранг = 2 elif self.suit == "Булавы": костюм_ранг = 3 elif self. suit == 'Бриллианты': костюм_ранг = 4 self.suit_rank = костюм_ранг защита __repr__(сам): description = "{номер} из {масти}".format(число = self.number, костюм = self.suit) возвращаемое описание Классовая колода: защита __init__(сам): селф.карты = [] для костюма в костюмах: для числа в цифрах: self.cards.append(Карта(масть, число)) деф-шоу (я): для c в self.cards: печать (с)
Проблема в том, что эти карточные объекты нелегко вызвать, не зная индекса того, где они попадают в руку игрока. Я хотел бы, чтобы каждый объект карт был назначен переменной, имя которой было бы таким, чтобы игроки могли ссылаться на них, набрав что-то вроде «двойка червей».
Итак, я думаю, мой вопрос заключается в том, есть ли способ перебирать список чисел и мастей, чтобы одновременно создавать объекты и назначать имя переменной, чтобы объекты вызывались интуитивно? Кажется утомительным проходить и создавать каждую переменную одну за другой.
Надеюсь, мой вопрос имеет смысл!
тгртим 2
Кажется, я припоминаю, что в книге fluent python в начале есть такой пример, который может быть вам полезен, если вы сможете достать копию.
То, что вы описываете, больше похоже на какое-то отображение. Так что, возможно, можно было бы использовать словарь, наследовать от него для вашей новой коллекции или реализовать методы, подобные словарю ( .__getitem__
и подобные см. для справки сопоставление абстрактных типов).
Думаю, это то, что вам нужно, но если нет, то так и скажите.
Перезапись .__getitem__
даст вам больше возможностей (этот метод вызывается, когда вы используете синтаксис нижнего индекса object[subscript]
).
Блейкбросмер32819606