Ответ 1
К сожалению, нет способа "переопределить, после init" специальные методы python; как побочный эффект того, как работает этот поиск. Суть проблемы в том, что python фактически не смотрит на экземпляр; кроме того, чтобы получить свой класс; прежде чем он начнет искать специальный метод; поэтому нет способа заставить состояние объекта влиять на то, какой метод просматривается.
Если вам не нравится специальное поведение в __init__
, вы можете реорганизовать свой код, чтобы вместо этого добавить специальные знания в __setattr__
. Что-то вроде:
class Foo(object):
__initialized = False
def __init__(self, a, b):
try:
self.a = a
self.b = b
# ...
finally:
self.__initialized = True
def __setattr__(self, attr, value):
if self.__initialzed:
print(self.b)
super(Foo, self).__setattr__(attr, value)
Изменить: На самом деле есть способ изменить, какой специальный метод просматривается, если вы измените его класс после его инициализации. Этот подход пошлет вас далеко в сорняки метаклассов, поэтому без дальнейших объяснений, вот как это выглядит:
class AssignableSetattr(type):
def __new__(mcls, name, bases, attrs):
def __setattr__(self, attr, value):
object.__setattr__(self, attr, value)
init_attrs = dict(attrs)
init_attrs['__setattr__'] = __setattr__
init_cls = super(AssignableSetattr, mcls).__new__(mcls, name, bases, init_attrs)
real_cls = super(AssignableSetattr, mcls).__new__(mcls, name, (init_cls,), attrs)
init_cls.__real_cls = real_cls
return init_cls
def __call__(cls, *args, **kwargs):
self = super(AssignableSetattr, cls).__call__(*args, **kwargs)
print "Created", self
real_cls = cls.__real_cls
self.__class__ = real_cls
return self
class Foo(object):
__metaclass__ = AssignableSetattr
def __init__(self, a, b):
self.a = a
self.b = b
for key, value in process(a).items():
setattr(self, key, value)
def __setattr__(self, attr, value):
frob(self.b)
super(Foo, self).__setattr__(attr, value)
def process(a):
print "processing"
return {'c': 3 * a}
def frob(x):
print "frobbing", x
myfoo = Foo(1, 2)
myfoo.d = myfoo.c + 1