Задача с дескрипторами, доработать согласно замечанию

nord_wind

Новичок
Пользователь
Дек 31, 2021
2
0
1
Задача: сразу все эти числа обратить в 0 одной командой (числа могут храниться в разных объекта). Представим, что у нас есть класс, который описывает спортивную команду, и в объекте этого класса хранится текущее количество очков в игре. Когда мы начинаем новую игру, у всех команд количество очков должно стать нулём. Написать дескриптор данных, к которому будут предъявляться следующие требования:
инициализация дескриптора внутри класса выглядит так: class Team: score = Nuller(), при присвоении нового значения в поле-дескриптор score объекта team = Team() это значение сохраняется внутри объекта team, при получении значения из поля-дескриптора score объекта team = Team() это значение берется из объекта team, класс Nuller содержит метод класса null, который присваивает 0 во все поля-дескрипторы объектов-владельцев. Для этого проще всего внутри класса Nuller хранить ссылки на все объекты-владельцы этого дескриптора, при удалении значения из объекта-владельца (с помощью оператора del) удаляется и ссылка из класса Nuller на этот объект.
Код:
Код:
class Nuller:
    owners_of_nullers = {}

    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value=0):
        instance.__dict__[self.name] = value
        Nuller.owners_of_nullers[instance] = self.name

    def __delete__(self, instance):
        del Nuller.owners_of_nullers[instance]
        del instance.__dict__[self.name]

    @classmethod
    def null(cls):
        for instance, name in Nuller.owners_of_nullers.items():
            instance.__dict__[name] = 0

Пример исполнения:
Код:
class Team:
    score = Nuller()

team1 = Team()
team2 = Team()
team1.score = 5
print(team1.score) 
# 5

team2.score = 28
print(team2.score) 
# 28

Nuller.null()
print(team1.score, team2.score)
#0 0

team1.score = 10
del team2.score
Nuller.null()
print(team1.score)
#0

Нужно учесть случай, что в классе создается больше одного Nuller.
Ошибка в строке del Nuller.owners_of_nullers[instance]. Скорее всего в тесте один Nuller из объекта удалили и соответственно сам объект из списка owners_of_nullers. А при удалении второго Nuller объекта в списке owners_of_nullers уже нет, и возникает исключение.

Как это сделать? Подскажите, мозг кипит.
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Нужно учесть случай, что в классе создается больше одного Nuller.
У вас в коде для каждого экземпляра класса Team создается одна пара ключ-значение в словаре owners_of_nullers, где ключ это экземпляр объекта Team поэтому если добавить в класс Team второй Nuller он заменит значение первого Nuller`a в словаре owners_of_nullers и код не будет обнулять значение из первого объекта Nuller.
Python:
# класс Nuller из вашего кода

class Team:
    score = Nuller()
    score2 = Nuller()


team1 = Team()
team2 = Team()
team1.score = 5
team1.score2 = 6
print(team1.score, team1.score2)  # 5 6


team2.score = 28
team2.score2 = 286
print(team2.score, team2.score2)  # 28 286

Nuller.null()
print(team1.score, team1.score2, team2.score, team2.score2)  # 5 0 28 0
# значения team1.score и team2.score не обнулились, так как в словаре owners_of_nullers
# для экземпляров team1 и team2 указаны значения score2
Чтобы исправить можно добавлять экземпляры в словарь по составному ключу (например, (instance, self.name)):
Python:
class Nuller:
    owners_of_nullers = {}

    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value=0):
        instance.__dict__[self.name] = value
        # добавляем экземпляр в словарь по составному ключу
        Nuller.owners_of_nullers[(instance, self.name)] = self.name

    def __delete__(self, instance):
        # удаляем экземпляр из словаря по составному ключу
        del Nuller.owners_of_nullers[(instance, self.name)]
        del instance.__dict__[self.name]

    @classmethod
    def null(cls):
        # проходим в цикле всем элементам словаря
        for (instance, n), name in Nuller.owners_of_nullers.items():
            instance.__dict__[name] = 0

            
class Team:
    score = Nuller()
    score2 = Nuller()


team1 = Team()
team2 = Team()
team1.score = 5
team1.score2 = 6
print(team1.score, team1.score2)  # 5 6


team2.score = 28
team2.score2 = 286
print(team2.score, team2.score2)  # 28 286

Nuller.null()
print(team1.score, team1.score2, team2.score, team2.score2)  # 0 0 0 0
# теперь все значения обнуляются
Ошибка в строке del Nuller.owners_of_nullers[instance]
Получить данную ошибку не смог, но она возникает по той же причине что и проблема выше (1 ключ в словаре на 1 экземпляр класса Team).
 

nord_wind

Новичок
Пользователь
Дек 31, 2021
2
0
1
Благодарю stud_55, теперь понятно.
 

Форум IT Специалистов