对象销毁期间多次调用 __del__
¶
ID: py/multiple-calls-to-delete
Kind: problem
Security severity:
Severity: warning
Precision: very-high
Tags:
- efficiency
- correctness
Query suites:
- python-security-and-quality.qls
与 Java 等静态类型语言不同,Python 允许在对象销毁期间调用方法时完全自由。但是,标准的面向对象原则适用于使用深度继承层次结构的 Python 类。因此,开发人员有责任确保在需要调用多个 __del__
方法时,对象能够正确清理。
在对象销毁期间多次调用 __del__
方法会导致资源被释放多次。相关的 __del__
方法可能并非设计为多次调用。
有多种方法会导致 __del__
方法被多次调用。
在
__del__
方法的层次结构中,可能存在对该方法的多次显式调用。使用多重继承的类直接调用其基类型的
__del__
方法。其中一个或多个基类型使用super()
向下传递继承链。
建议¶
要么注意不要显式调用 __del__
方法多次,要么在整个继承层次结构中使用 super()
。
或者将一个或多个类重构为使用组合而不是继承。
示例¶
在第一个示例中,使用了对 __del__
的显式调用,但 SportsCar
错误地调用了 Vehicle.__del__
和 Car.__del__
。这可以通过删除对 Vehicle.__del__
的调用来修复,如 FixedSportsCar
中所示。
#Calling a method multiple times by using explicit calls when a base inherits from other base
class Vehicle(object):
def __del__(self):
recycle(self.base_parts)
class Car(Vehicle):
def __del__(self):
recycle(self.car_parts)
Vehicle.__del__(self)
class SportsCar(Car, Vehicle):
# Vehicle.__del__ will get called twice
def __del__(self):
recycle(self.sports_car_parts)
Car.__del__(self)
Vehicle.__del__(self)
#Fix SportsCar by only calling Car.__del__
class FixedSportsCar(Car, Vehicle):
def __del__(self):
recycle(self.sports_car_parts)
Car.__del__(self)
在第二个示例中,混合使用了对 __del__
的显式调用和使用 super()
的调用。要修复此示例,应在整个继承层次结构中使用 super()
。
#Calling a method multiple times by using explicit calls when a base uses super()
class Vehicle(object):
def __init__(self):
super(Vehicle, self).__init__()
self.mobile = True
class Car(Vehicle):
def __init__(self):
super(Car, self).__init__()
self.car_init()
def car_init(self):
pass
class SportsCar(Car, Vehicle):
# Vehicle.__init__ will get called twice
def __init__(self):
Vehicle.__init__(self)
Car.__init__(self)
self.sports_car_init()
def sports_car_init(self):
pass
#Fix SportsCar by using super()
class FixedSportsCar(Car, Vehicle):
def __init__(self):
super(SportsCar, self).__init__()
self.sports_car_init()
def sports_car_init(self):
pass
参考资料¶
Python 教程: 类。
Python 标准库: super。
Artima 开发者: 关于 Python Super 的一些事项。
维基百科: 组合优于继承。