Как создать новый экземпляр класса с новыми рандомными данными?

Условно есть такой код:

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

Ответы (5 шт):

Автор решения: strawdog

А вы не пробовали записывать класс в каноническом виде, с функцией инициализации экземпляров? в противном случае рандомизация у вас происходит один раз для родительского объекта.

import random

class Test:
    def __init__(self):
        self.number = random.randint(100, 500)


test1 = Test()
test2 = Test()
test1.number==test2.number  #False
→ Ссылка
Автор решения: Envy

В обычном случае, вам подойдёт вариант, предложенный @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
        )
→ Ссылка
Автор решения: Roman Konoval

Определение поля в классе в 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 как раз для генерации тестовых данных.

→ Ссылка
Автор решения: insolor

Как вариант, можно передавать случайное число при инициализации объекта:

import random
from pydantic import BaseModel


class Test(BaseModel):
    number: int


print(Test(number=random.randint(100, 500)).number)
print(Test(number=random.randint(100, 500)).number)
print(Test(number=random.randint(100, 500)).number)

Пример вывода:

431
448
412
→ Ссылка
Автор решения: Gentleman

Всем спасибо за ответы, они действительно правильные. Но мне кажется более изящным и читабельным следующее решение:

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

Напишите, пожалуйста, в комментариях, что вы думаете по поводу данного решения.

→ Ссылка