首先,为长期解释道歉。
class A(object):
def __init__(self, klass):
print "A::__init__()"
self._klass = klass
def __call__(self):
print "A::__call__()"
return self._klass()
def __del__(self):
print "A::__del__()"
@A
class B(object):
def __init__(self):
print "B::__init__()"
def main():
b = B()
if __name__ == "__main__":
main()
A::__init__()
A::__call__()
B::__init__()
A::__del__()
class A(object):
def __init__(self, klass):
print "A::__init__()"
self._klass = klass
def __call__(self):
print "A::__call__()"
return self._klass()
def __del__(self):
print "A::__del__()"
class Parent1(object):
def __init__(self):
print "Parent1:: __init__()"
super(Parent1, self).__init__()
class Parent2(object):
def __init__(self):
print "Parent2:: __init__()"
super(Parent2, self).__init__()
@A
class B(Parent1, Parent2):
def __init__(self):
print "B::__init__()"
# super(B, self).__init__()
Parent1.__init__(self)
Parent2.__init__(self)
def main():
b = B()
if __name__ == "__main__":
main()
A::__init__()
A::__call__()
B::__init__()
Parent1:: __init__()
Parent2:: __init__()
Parent2:: __init__()
A::__del__()
super()
class A(object):
def __init__(self, klass):
print "A::__init__()"
self._klass = klass
def __call__(self):
print "A::__call__()"
return self._klass()
def __del__(self):
print "A::__del__()"
class Parent1(object):
def __init__(self):
print "Parent1:: __init__()"
super(Parent1, self).__init__()
class Parent2(object):
def __init__(self):
print "Parent2:: __init__()"
super(Parent2, self).__init__()
@A
class B(Parent1, Parent2):
def __init__(self):
print "B::__init__()"
super(B, self).__init__()
def main():
b = B()
if __name__ == "__main__":
main()
A::__init__()
A::__call__()
B::__init__()
Traceback (most recent call last):
File "so.py", line 40, in <module>
main()
File "so.py", line 36, in main
b = B()
File "so.py", line 10, in __call__
return self._klass()
File "so.py", line 32, in __init__
super(B, self).__init__()
TypeError: must be type, not A
A::__del__()
版本#1仅供参考。它解释了我想要做的事情,即捕获creation
对象的deletion
和class B
。
在版本#2中,我尝试使用class B
和Parent1
派生的Parent2
对象,这些对象使用Parent1.__init__(self)
和{{显式初始化1}}按预期工作正常。
但是在版本#3中,我尝试使用Parent2.__init__(self)
方法。但我收到以下错误 - super()
。我认为这是因为TypeError: must be type, not A
链中所有父类的__init__()
方法没有被正确调用 - 为什么?而且,我该如何解决这个问题?
答案 0 :(得分:6)
主要问题是super
的第一个参数需要是实际的类,但在版本3中,在
super(B, self)
B
不是您创建的课程。这是包装类的A
实例。您需要执行类似
class _B(Parent1, Parent2):
def __init__(self):
print "B::__init__()"
super(_B, self).__init__()
B = A(_B)
或者不是在B
实例中包装A
,而是使用装饰器将B
的{{1}}和__init__
方法替换为包装器而不替换整个__del__
课程。
此外,如果您要跟踪B
个实例的删除,B
上的__del__
方法将无法执行此操作。它将跟踪类的删除,而不是单个实例。
这是一个装扮者应该做你想做的事情,没有将课程包装在不属于某个类的东西中的许多问题:
A
其中大约一半是错误处理和复制一些元数据,以使新方法看起来像是由调用者定义的。关键部分是我们定义新的def track_creation_and_deletion(klass):
original_init = klass.__init__
try:
original_del = klass.__del__
except AttributeError:
def original_del(self):
pass
def new_init(self, *args, **kwargs):
print '{}.{}.__init__'.format(klass.__module__, klass.__name__)
return original_init(self, *args, **kwargs)
def new_del(self):
print '{}.{}.__del__'.format(klass.__module__, klass.__name__)
return original_del(self)
# functools.wraps doesn't play nicely with built-in methods,
# so we handle it ourselves
new_init.__name__ = '__init__'
new_init.__doc__ = original_init.__doc__
new_init.__module__ = klass.__module__
new_init.__dict__.update(getattr(original_init, '__dict__', {}))
new_del.__name__ = '__del__'
new_del.__doc__ = original_del.__doc__
new_del.__module__ = klass.__module__
new_del.__dict__.update(getattr(original_del, '__dict__', {}))
klass.__init__ = new_init
klass.__del__ = new_del
return klass
和__init__
方法包装和替换类的旧方法。创建装饰类的实例时,我们给它的__del__
方法将调用我们选择的日志代码。当装饰类的实例被垃圾收集时,我们给它的__init__
方法将调用其他日志代码。由于我们没有替换类对象本身,因此在__del__
调用中按名称引用类将引用它们需要引用的类。
这种方法的一个限制是很难在我们的super
中检查实例本身,因为它可能无法完全构造,即使在包装的__init__
返回之后也是如此。例如,如果我们尝试__init__
实例,我们可能会依赖尚未准备好的子类属性触发子类的print
方法,从而导致AttributeError。
答案 1 :(得分:0)
我花了一些时间来理解为什么难以分别使用__call__
和__del__
方法捕获对象实例化和对象删除。以下是一些有用的参考资料
使用__del__
方法可以使用优秀的黑客攻击,但它们有副作用!例如,@ user2357112给出的答案是一个很好的黑客,但是当我们进行循环引用时它不起作用,因为垃圾收集器无法确定首先调用的循环引用中的哪个__del__
!然而,这可以通过使用弱参考来避免;但它仍然是一个黑客!
其中一个建议是创建一个上下文管理器,它可以创建和删除特定类的对象。
我有以下示例,哪种模拟它。请仔细查看Controller
装饰器。
class Parent1(object):
def __init__(self):
#print "Parent1::__init__()"
super(Parent1, self).__init__()
class Parent2(object):
def __init__(self):
#print "Parent2::__init__()"
super(Parent2, self).__init__()
def Controller(_cls):
class Wrapper(_cls):
def create(self, name):
ret = _cls.create(self, name)
print "Added to Database! :: ", name
# Database add here!
return ret
def remove(self, name):
ret = _cls.remove(self, name)
print "Deleted from Database! :: ", name
# Database delete here!
return ret
return Wrapper
@Controller
class Manager(object):
def __init__(self):
#print "Manager::__init__()"
self._repo = []
def create(self, name):
a = A(name)
print "Object created :: ", name
self._repo.append(a)
def remove(self, name):
for i, item in enumerate(self._repo):
if item._name == name:
del self._repo[i]
print "Object removed :: ", name
def display(self):
for item in self._repo:
print item
class A(Parent1, Parent2):
def __init__(self, name):
#print "A::__init__()"
self._name = name
super(A, self).__init__()
def __repr__(self):
return self._name
def main():
m1 = Manager()
m1.create("apples")
m1.create("oranges")
m1.create("grapes")
#m1.display()
m1.remove("apples")
#m1.display()
if __name__ == "__main__":
main()
执行时,会产生以下结果:
Object created :: apples
Added to Database! :: apples
Object created :: oranges
Added to Database! :: oranges
Object created :: grapes
Added to Database! :: grapes
Object removed :: apples
Deleted from Database! :: apples
这是我能解决问题的最安全的解决方案。建议欢迎!