Определите сеттер в классе на Python?

#python #class

Вопрос:

У меня есть класс, который берет большой диктант и инициализирует его. У меня есть геттер, который позволяет мне получать доступ к объектам моего tmp_dict. Я также пытался написать сеттер для изменения значений переменной, но, похоже, он возвращается None . Мой вопрос, если как я могу установить сеттер, чтобы также изменить значения?

 class MyClass:
    def __init__(self, tmp_dict):
        self.vals = tmp_dict
   
    @property
    def get(self, var):
        return self.vals.get(var)

    @get.setter
    def set_val(self, var, new_val):
        self.vals[var] = new_val


tmp_dict = {"val1": 1, "val2": 2, "val3": 1, "val100":1}

obj = MyClass(tmp_dict)
print(obj.get("val1"))
obj.set_val("val1", 100)
print(obj.get("val1"))
TypeError: get() missing 1 required positional argument: 'var'

 

Комментарии:

1. Функции без a return будут выдавать None по умолчанию. Вы можете попробовать не печатать set , а установить в отдельной строке, а затем распечатать get после набора.

2. Сеттер выглядит так, как будто у него все получится. Вы просто ничего из него не возвращаете, поэтому None автоматически возвращаетесь.

3.Лучший способ-использовать класс property docs.python.org/3/library/functions.html#property

4. Для сеттера нормально не возвращать ничего и полагаться исключительно на геттера, чтобы фактически получить значение.

5. Этот сеттер выглядит так, как будто он будет работать, просто, вероятно None , результат вас смущает. Вы можете заставить сеттера вернуться new_val после того, как он преуспеет.

Ответ №1:

Я неправильно понял цель операции. Свойство class хорошо подходит для получения и настройки свойств, сохраняя атрибуты скрытыми для пользователя. Это необходимо для защиты некоторых внутренних переменных или, возможно, для возникновения побочных эффектов при получении или установке значений.

Что я пропустил из поста, так это слово «большой». Если каждый объект инициализирован с помощью большого диктанта, вероятно, лучше оставить его в покое и определить некоторые вспомогательные функции для извлечения и установки ключей.

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

 class MyClass:
    def __init__(self, tmp_dict):
        object.__setattr__(self, '_vals', tmp_dict)
        self.other_attr = 1234
    
    def __getattr__(self, name):
        try:
            return self._vals[name]
        except KeyError:
            raise AttributeError(f"'MyClass' object has no attribute '{name}'")
            
    def __setattr__(self, name, val):
        if hasattr(self, '_vals') and name in self._vals.keys():
            self._vals[name] = val
        else:
            object.__setattr__(self, name, val)
 

Затем вы можете получить доступ к ключу val1 с обычным синтаксисом, а также к другим атрибутам

 >>> tmp_dict = {"val1": 1, "val2": 2, "val3": 1, "val100": 123}
>>> obj = MyClass(tmp_dict)
>>> obj.val1
1
>>> obj.other_attr
1234
 

И вы также можете установить их

 >>> obj.val2 = 90
>>> obj.val2
90
 

Обратите внимание, что теперь вы действительно можете притвориться, что val1 это атрибут, который избавляет вас от этого громоздкого get('val1') или set('val2', 90) .

Два замечания:

  1. Уродство необходимо object.__setattr__(self, name, val) , чтобы избежать бесконечных циклов, которые вызывают __setattr__ снова и снова
  2. Я добавил подчеркивание к атрибуту _val . Это не имеет синтаксического значения в Python, но служит сигналом для ваших пользователей, что _val это внутренний атрибут, и с ним следует взаимодействовать только с помощью предоставленных методов объекта.

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