QHelp previews: python/ql/src/Classes/CallsToInitDel/MissingCallToDel.qhelpMissing call to superclass__del__ during object destructionPython, unlike some other object-oriented languages such as Java, allows the developer complete freedom in when and how superclass finalizers are called during object finalization. However, the developer has responsibility for ensuring that objects are properly cleaned up, and that all superclass__del__ methods are called. Classes with a__del__ method (a finalizer) typically hold some resource such as a file handle that needs to be cleaned up. If the__del__ method of a superclass is not called during object finalization, it is likely that resources may be leaked. A call to the__init__ method of a superclass during object initialization may be unintentionally skipped: - If a subclass calls the
__del__ method of the wrong class. - If a call to the
__del__ method of one its base classes is omitted. - If a call to
super().__del__ is used, but not all__del__ methods in the Method Resolution Order (MRO) chain themselves callsuper() . This in particular arises more often in cases of multiple inheritance.
RecommendationEnsure that all superclass__del__ methods are properly called. Either each base class's finalize method should be explicitly called, orsuper() calls should be consistently used throughout the inheritance hierarchy. ExampleIn the following example, explicit calls to__del__ are used, butSportsCar erroneously callsVehicle.__del__ . This is fixed inFixedSportsCar by callingCar.__del__ . classVehicle(object):def__del__(self):recycle(self.base_parts)classCar(Vehicle):def__del__(self):recycle(self.car_parts)Vehicle.__del__(self)#BAD: Car.__del__ is not called.classSportsCar(Car,Vehicle):def__del__(self):recycle(self.sports_car_parts)Vehicle.__del__(self)#GOOD: Car.__del__ is called correctly.classFixedSportsCar(Car,Vehicle):def__del__(self):recycle(self.sports_car_parts)Car.__del__(self) Referencespython/ql/src/Classes/CallsToInitDel/MissingCallToInit.qhelpMissing call to superclass__init__ during object initializationPython, unlike some other object-oriented languages such as Java, allows the developer complete freedom in when and how superclass initializers are called during object initialization. However, the developer has responsibility for ensuring that objects are properly initialized, and that all superclass__init__ methods are called. If the__init__ method of a superclass is not called during object initialization, this can lead to errors due to the object not being fully initialized, such as having missing attributes. A call to the__init__ method of a superclass during object initialization may be unintentionally skipped: - If a subclass calls the
__init__ method of the wrong class. - If a call to the
__init__ method of one its base classes is omitted. - If a call to
super().__init__ is used, but not all__init__ methods in the Method Resolution Order (MRO) chain themselves callsuper() . This in particular arises more often in cases of multiple inheritance.
RecommendationEnsure that all superclass__init__ methods are properly called. Either each base class's initialize method should be explicitly called, orsuper() calls should be consistently used throughout the inheritance hierarchy. ExampleIn the following example, explicit calls to__init__ are used, butSportsCar erroneously callsVehicle.__init__ . This is fixed inFixedSportsCar by callingCar.__init__ . classVehicle(object):def__init__(self):self.mobile=TrueclassCar(Vehicle):def__init__(self):Vehicle.__init__(self)self.car_init()# BAD: Car.__init__ is not called.classSportsCar(Car,Vehicle):def__init__(self):Vehicle.__init__(self)self.sports_car_init()# GOOD: Car.__init__ is called correctly.classFixedSportsCar(Car,Vehicle):def__init__(self):Car.__init__(self)self.sports_car_init() Referencespython/ql/src/Classes/CallsToInitDel/SuperclassDelCalledMultipleTimes.qhelpMultiple calls to__del__ during object destructionPython, unlike some other object-oriented languages such as Java, allows the developer complete freedom in when and how superclass finalizers are called during object finalization. However, the developer has responsibility for ensuring that objects are properly cleaned up. Objects with a__del__ method (a finalizer) often hold resources such as file handles that need to be cleaned up. If a superclass finalizer is called multiple times, this may lead to errors such as closing an already closed file, and lead to objects not being cleaned up properly as expected. There are a number of ways that a__del__ method may be be called more than once. - There may be more than one explicit call to the method in the hierarchy of
__del__ methods. - In situations involving multiple inheritance, an finalization method may call the finalizers of each of its base types, which themselves both call the finalizer of a shared base type. (This is an example of the Diamond Inheritance problem)
- Another situation involving multiple inheritance arises when a subclass calls the
__del__ methods of each of its base classes, one of which callssuper().__del__ . This super call resolves to the next class in the Method Resolution Order (MRO) of the subclass, which may be another base class that already has its initializer explicitly called.
RecommendationEnsure that each finalizer method is called exactly once during finalization. This can be ensured by callingsuper().__del__ for each finalizer method in the inheritance chain. ExampleIn the following example, there is a mixture of explicit calls to__del__ and calls usingsuper() , resulting inVehicle.__del__ being called twice.FixedSportsCar.__del__ fixes this by usingsuper() consistently with the other delete methods. #Calling a method multiple times by using explicit calls when a base uses super()classVehicle(object):def__del__(self):recycle(self.base_parts)super(Vehicle,self).__del__()classCar(Vehicle):def__del__(self):recycle(self.car_parts)super(Car,self).__del__()classSportsCar(Car,Vehicle):# BAD: Vehicle.__del__ will get called twicedef__del__(self):recycle(self.sports_car_parts)Car.__del__(self)Vehicle.__del__(self)# GOOD: super() is used ensuring each del method is called once.classFixedSportsCar(Car,Vehicle):def__del__(self):recycle(self.sports_car_parts)super(SportsCar,self).__del__() Referencespython/ql/src/Classes/CallsToInitDel/SuperclassInitCalledMultipleTimes.qhelpMultiple calls to__init__ during object initializationPython, unlike some other object-oriented languages such as Java, allows the developer complete freedom in when and how superclass initializers are called during object initialization. However, the developer has responsibility for ensuring that objects are properly initialized. Calling an__init__ method more than once during object initialization risks the object being incorrectly initialized, as the method and the rest of the inheritance chain may not have been written with the expectation that it could be called multiple times. For example, it may set attributes to a default value in a way that unexpectedly overwrites values setting those attributes in a subclass. There are a number of ways that an__init__ method may be be called more than once. - There may be more than one explicit call to the method in the hierarchy of
__init__ methods. - In situations involving multiple inheritance, an initialization method may call the initializers of each of its base types, which themselves both call the initializer of a shared base type. (This is an example of the Diamond Inheritance problem)
- Another situation involving multiple inheritance arises when a subclass calls the
__init__ methods of each of its base classes, one of which callssuper().__init__ . This super call resolves to the next class in the Method Resolution Order (MRO) of the subclass, which may be another base class that already has its initializer explicitly called.
RecommendationTake care whenever possible not to call an an initializer multiple times. If each__init__ method in the hierarchy callssuper().__init__() , then each initializer will be called exactly once according to the MRO of the subclass. When explicitly calling base class initializers (such as to pass different arguments to different initializers), ensure this is done consistently throughout, rather than usingsuper() calls in the base classes. In some cases, it may not be possible to avoid calling a base initializer multiple times without significant refactoring. In this case, carefully check that the initializer does not interfere with subclass initializers when called multiple times (such as by overwriting attributes), and ensure this behavior is documented. ExampleIn the following (BAD) example, the classD callsB.__init__ andC.__init__ , which each callA.__init__ . This results inself.state being set toNone asA.__init__ is called again afterB.__init__ had finished. This may lead to unexpected results. classA:def__init__(self):self.state=NoneclassB(A):def__init__(self):A.__init__(self)self.state="B"self.b=3classC(A):def__init__(self):A.__init__(self)self.c=2classD(B,C):def__init__(self):B.__init__(self)C.__init__(self)# BAD: This calls A.__init__ a second time, setting self.state to None. In the following (GOOD) example, a call tosuper().__init__ is made in each class in the inheritance hierarchy, ensuring each initializer is called exactly once. classA:def__init__(self):self.state=NoneclassB(A):def__init__(self):super().__init__()self.state="B"self.b=3classC(A):def__init__(self):super().__init__()self.c=2classD(B,C):def__init__(self):# GOOD: Each method calls super, so each init method runs once. self.state will be set to "B".super().__init__()self.d=1 In the following (BAD) example, explicit base class calls are mixed withsuper() calls, andC.__init__ is called twice. classA:def__init__(self):print("A")self.state=NoneclassB(A):def__init__(self):print("B")super().__init__()# When called from D, this calls C.__init__self.state="B"self.b=3classC(A):def__init__(self):print("C")super().__init__()self.c=2classD(B,C):def__init__(self):B.__init__(self)C.__init__(self)# BAD: C.__init__ is called a second time References |
Uh oh!
There was an error while loading.Please reload this page.
Modernizes py/missing-call-to-init, py/missing-call-to-del, py/multiple-calls-to-init,, and py/multiplecalls-to-del.
Uses DataFlowDispatch methods rather than. pointsTo.
Improves precision (to reduce FPs) in resolving relevant calls as precisely as possible using known MRO information, improves descriptiveness of alert messages by including more possible relevant locations, and improves documentation.