Movatterモバイル変換


[0]ホーム

URL:


CodeQL documentation
CodeQL resources

Multiple calls to__init__ during object initialization

ID: py/multiple-calls-to-initKind: problemSecurity severity: Severity: warningPrecision: very-highTags:   - quality   - reliability   - correctnessQuery suites:   - python-security-and-quality.qls

Click to see the query in the CodeQL repository

Python, 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.

Recommendation

Take 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.

Example

In 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


[8]ページ先頭

©2009-2025 Movatter.jp