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
2

В обычном случае, вам подойдёт вариант, предложенный @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  #False
3

Определение поля в классе в 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 («фабрику» значения по умолчанию) для поля. Обычно это используется для инициализации поля пустым списком (или другим контейнером) например

default_factory=list, но можно передать лямбду, которая вызывает 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}

ИТОГ.

Создавайте свойства для объектов (в

__init__), особенно если свойства содержат изменяемые объекты.

Пример:

# Заглушка, чтобы код работал
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()
 
  • питон
  • класс
  • объект
1

Этот вопрос задают каждый день в той или иной вариации. Ответ таков: держите свои данные подальше от имен переменных, и это обязательная запись в блоге.

В таком случае, почему бы не составить список объектов?

 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 и гарантирует правильность создания экземпляров.

0

Зарегистрируйтесь или войдите в систему

Зарегистрируйтесь с помощью 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