#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#property4. Для сеттера нормально не возвращать ничего и полагаться исключительно на геттера, чтобы фактически получить значение.
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)
.
Два замечания:
- Уродство необходимо
object.__setattr__(self, name, val)
, чтобы избежать бесконечных циклов, которые вызывают__setattr__
снова и снова - Я добавил подчеркивание к атрибуту
_val
. Это не имеет синтаксического значения в Python, но служит сигналом для ваших пользователей, что_val
это внутренний атрибут, и с ним следует взаимодействовать только с помощью предоставленных методов объекта.
Правка: Позже я понял, что __setattr__
метод выполняет два ключевых поиска: один для определения того, существует ли атрибут, и другой для его установки, если он существует. Это может быть излишне медленным, поэтому примите этот ответ с необходимыми предосторожностями.