Дескриптор данных

Необходимо описать класс-дескриптор, который хранит в себе произвольные значения. Этот класс должен содержать метод null(), который будет "обнулять" все ранее сохраненные значения. Загвоздка в том, как мне получить ссылки на все объекты-владельцы этого дескриптора.

class Nuller(object):
 
    def __set__(self, instance, value):
        self.value = value
 
    def __get__(self, instance, owner):
        return self.value
 
    def __delete__(self, value):
        del self.value
 
    def null():
        print('reset')
 
 
class Team:
    score = Nuller()
 
team1 = Team()
team2 = Team()
team1.score = 5   #5
team2.score = 28   #28
Nuller.null()
print(team1, team2)  #0 0

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

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

Добавляем в класс Nuller множество, в котором будем хранить объекты и названия полей, которые нужно обнулить. При записи чего-то в поле (вызов метода __set__) добавляем объект и имя поля в это множество. При вызове метода null проходим это множество и обнуляем значения записанных полей в записанных объектах.

Также обратите внимание, что запись/получение данных идет через instance (в данном случае это будут объекта класса Team), а не через self (объект класса Nuller), т.к. объект Nuller создается один раз при создании поля класса, в итоге будет один объект Nuller на все объекты Team (в вашем примере из вопроса после team1.score = 5 все объекты класса Team будут в score показывать 5, а после team2.score = 28 - будут показывать 28).

class Nuller(object):
    instances_and_attributes = set()
    
    def __set_name__(self, owner, name):
        # Значения фактически будут записываться в поле с добавлением подчеркивания
        self.private_name = '_' + name

    def __set__(self, instance, value):
        # Добавляем объект и приватное имя поля в список обнуления
        # (если обнулять по публичному имени поля, то вызов метода __set__ зациклится)
        self.instances_and_attributes.add((instance, self.private_name))
        setattr(instance, self.private_name, value)
 
    def __get__(self, instance, owner):
        return getattr(instance, self.private_name)
    
    def __delete__(self, instance):
        delattr(instance, self.private_name)

    def null():
        print('reset')
        for instance, name in Nuller.instances_and_attributes:
            setattr(instance, name, 0)


class Team:
    score = Nuller()


team1 = Team()
team2 = Team()

team1.score = 5
team2.score = 28

print(team1.score, team2.score)  # 5 28
Nuller.null()
print(team1.score, team2.score)  # 0 0
→ Ссылка
Автор решения: Алексей Белкин

Если вопрос с доступом к атрибутам класса, то можете использовать магический метод __dict__:

class E():
    def __init__(self):
        self.rod = 10

class Er(E):
    def __init__(self, val1, val2):
        super(Er, self).__init__()
        self.val1 = val1
        self.val2 = val2

    def x2_val1(self):
        self.val1 = self.val1 * 2

    def null(self):
        for key in self.__dict__:
            self.__dict__[key] = 0

obj = Er(4, 5)

obj.null()
print(obj.val1)  # выведет 0
print(obj.rod)   # выведет 0
→ Ссылка