Подтвердить что ты не робот

Метод Python "поймать все" для undefined/нереализованных атрибутов в классах

Мне нравится Python @property украсить систему. Мне нравится, что вы можете запускать собственный код при вызове aClassObect.attribute. Специально для проверки данных при настройке атрибута. Однако одна вещь, которую я хочу, но я не могу найти, - это способ запуска пользовательского кода при попытке установить атрибут, который не существует. Например, скажем, у меня есть следующий класс:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Теперь, если у меня есть myObj, который является экземпляром класса C, и я вызываю myObject.x = 42, он запустит соответствующий наборщик, что отлично подходит для проверки данных. Но это не мешает кому-либо вызвать myOjbect.b = 47, и он с радостью создаст новый атрибут b. Есть ли способ запустить специальный код при настройке нового атрибута? Я мог бы поднять ошибки, чтобы сказать что-то вроде "error, этот атрибут не существует".

4b9b3361

Ответ 1

Чтобы немного рассказать о Elazar, вы хотите переопределить __setattr__ магический метод и проверьте его, чтобы узнать, существует ли атрибут. Если нет, вызовите исключение. Вот что это могло бы выглядеть для вашего класса:

def __setattr__(self, name, value):
    if not hasattr(self, name): # would this create a new attribute?
        raise AttributeError("Creating new attributes is not allowed!")
    super(C, self).__setattr__(name, value)

Также возможно переопределить __getattr__ или __getattribute__, если вы хотите иметь дело с запросами на несуществующие атрибуты, но для конкретной проблемы, о которой вы описали, это, вероятно, не нужно.

Обратите внимание, что метод __setattr__, показанный выше, не будет полностью хорошо воспроизводиться с вашим текущим свойством из-за делетера. Если вы удалите myObj.x, то впоследствии получатель повысит исключение, если попытается получить доступ к x позже. Это означает, что hasattr вернет False при проверке, является ли x существующим атрибутом, и поэтому мой __getattr__ не позволит вам его воссоздать. Если вам действительно нужно иметь возможность удалять (и воссоздавать) определенные атрибуты, вам понадобится более сложная реализация __setattr__ (она может проверять класс для свойства с нужным именем, а не просто полагаться на hasattr).

Ответ 2

переопределить __getattr__ и __setattr__.