Как сделать одинакову проверку одной и той же переменной класса в разных методах этого класса?
Использую Python 3. Есть класс, в котором есть какая-то переменная, которую обрабатывают несколько методов. Упрощенный пример:
class Foo:
def __init__(self, foobar):
self.foobar = foobar
def bar_1(self):
# some operation with self.foobar
self.foobar = 'Another variable'
def bar_2(self):
# some operation with self.foobar
self.foobar = 'Another variable'
def bar_3(self):
# some operation with self.foobar
self.foobar = 'Another variable'
Я хочу, чтобы в результате вызова этих методов мне возвращался raise или return о том, что в этом вызове метода переменная self.foobar никак не изменилась.
Есть, по-моему, очевидное и простое решение:
class Foo:
def __init__(self, foobar):
self.foobar = foobar
def bar_1(self):
old_foobar = self.foobar
# some operation with self.foobar
self.foobar = 'Another variable'
if old_foobar == self.foobar:
return 'Variable foobar has not changed'
def bar_2(self):
old_foobar = self.foobar
# some operation with self.foobar
self.foobar = 'Another variable'
if old_foobar == self.foobar:
return 'Variable foobar has not changed'
def bar_3(self):
old_foobar = self.foobar
# some operation with self.foobar
self.foobar = 'Another variable'
if old_foobar == self.foobar:
return 'Variable foobar has not changed'
Но оно некрасивое, потому что в нём повторяются одни и те же строки. Как мне кажется, лучше сделать это с помощью декоратора, только я не понимаю как мне для декоратора достать текущее значение переменной в момент выполнения какого-либо метода, чтобы потом сравнить исходное с итоговым. Помогите, пожалуйста, найти оптимальное решение
Ответы (2 шт):
Припишите к первому коду:
@property
def foobar(self):
return self._foobar
@foobar.setter
def foobar(self, v):
try:
if v == self._foobar:
raise ValueError('Variable foobar has not changed')
except AttributeError:
pass
self._foobar = v
Блок try except нужен, чтоб сработала инициализация атрибута
И тогда следующий код приведет к исключению
f = Foo('Another variable')
f.bar_3()
Могу предложить такой вариант, а raise по своему усмотрению встройте.
Через декоратор сохраняем переменные объекта, с которыми потом сравниваем измененные переменные с исходными по ключам в словаре. Дальше при желании можно восстановить исходные значения.
def constants(func):
def wraps(self_, *args, **kwargs):
consts = dict(self_.__dict__)
func(self_, *args, **kwargs)
if all([v == self_.__dict__[c] for c, v in consts.items()]):
print('No changes')
else:
print('Variables are changed')
return wraps
class Foo:
def __init__(self, foobar):
self.foobar = foobar
@constants
def bar_1(self):
# some operation with self.foobar
self.foobar = 'Another variable'
@constants
def bar_2(self):
# some operation with self.foobar
self.foobar = 'Another variable'
@constants
def bar_3(self):
# some operation with self.foobar
self.foobar = 'Another variable'
f = Foo('123')
print(f.foobar) # 123
f.bar_1() # Variables are changed
print(f.foobar) # Another variable
f.bar_2() # No changes
print(f.foobar) # Another variable
f.bar_3() # No changes
print(f.foobar) # Another variable