Декоратор класса Python "self" кажется неправильным
Я пытаюсь понять, как я могу изменить функциональность __setattr__
класса с использованием декоратора в классе, но я сталкиваюсь с проблемой при попытке доступа self
внутри функции, которая заменяет __setattr__
, Если я изменю проблемную строку, чтобы не получить доступ self
например, заменить его на val = str(val)
Я получаю ожидаемое поведение.
Я вижу подобные проблемы в других вопросах здесь, но они используют другой подход, где класс используется в качестве декоратора. Мой подход ниже выглядит менее сложным, поэтому я хотел бы сохранить его таким, если это возможно.
Почему может a
не определяться на self
/foo
где я ожидаю, что это будет?
# Define the function to be used as decorator
# The decorator function accepts the relevant fieldname as argument
# and returns the function that wraps the class
def field_proxied(field_name):
# wrapped accepts the class (type) and modifies the functionality of
# __setattr__ before returning the modified class (type)
def wrapped(wrapped_class):
super_setattr = wrapped_class.__setattr__
# The new __setattr__ implementation makes sure that given an int,
# the fieldname becomes a string of that int plus the int in the
# `a` attribute
def setattr(self, attrname, val):
if attrname == field_name and isinstance(val, int):
val = str(self.a + val) # <-- Crash. No attribute `a`
super_setattr(self, attrname, val)
wrapped_class.__setattr__ = setattr
return wrapped_class
return wrapped
@field_proxied("b")
class Foo(object):
def __init__(self):
self.a = 2
self.b = None
foo = Foo()
# <-- At this point, `foo` has no attribute `a`
foo.b = 4
assert foo.b == "6" # Became a string
1 ответ
Проблема проста, вам просто нужно изменить одну строку.
def setattr(self, attrname, val):
if attrname == field_name and isinstance(val, int):
val = str(self.a + val)
super_setattr(self, attrname, val) # changed line
Причина в том, что в исходном методе вы будете вызывать только super_setattr
когда attrname == field_name
, Так self.a = 2
в __init__
не работает вообще, как "a" != "b"
,