|
4 | 4 | <qhelp>
|
5 | 5 |
|
6 | 6 | <overview>
|
7 |
| -<p>Python, unlike statically typed languages such as Java, allows complete freedom when calling methods during object destruction. |
8 |
| -However, standard object-oriented principles apply to Python classes using deep inheritance hierarchies. |
9 |
| -Therefore the developer has responsibility for ensuring that objects are properly cleaned up when |
10 |
| -there are multiple <code>__del__</code> methods that need to be called. |
| 7 | +<p> |
| 8 | +Python, unlike some other object-oriented languages such as Java, allows the developer complete freedom in |
| 9 | +when and how superclass finalizers are called during object finalization. |
| 10 | +However, the developer has responsibility for ensuring that objects are properly cleaned up. |
11 | 11 | </p>
|
12 | 12 |
|
13 | 13 | <p>
|
14 |
| -Calling a <code>__del__</code> method more than once during object destruction risks resources being released multiple |
15 |
| -times. The relevant <code>__del__</code> method may not be designed to be called more than once. |
| 14 | +Objects with a <code>__del__</code> method (a finalizer) often hold resources such as file handles that need to be cleaned up. |
| 15 | +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 |
| 16 | +cleaned up properly as expected. |
16 | 17 | </p>
|
17 | 18 |
|
18 | 19 | <p>There are a number of ways that a <code>__del__</code> method may be be called more than once.</p>
|
19 | 20 | <ul>
|
20 | 21 | <li>There may be more than one explicit call to the method in the hierarchy of <code>__del__</code> methods.</li>
|
21 |
| - <li>A class using multiple inheritance directly calls the <code>__del__</code> methods of its base types. |
22 |
| - One or more of those base types uses <code>super()</code> to pass down the inheritance chain.</li> |
| 22 | + <li>In situations involving multiple inheritance, an finalization method may call the finalizers of each of its base types, |
| 23 | + which themselves both call the finalizer of a shared base type. (This is an example of the Diamond Inheritance problem)</li> |
| 24 | + <li>Another situation involving multiple inheritance arises when a subclass calls the <code>__del__</code> methods of each of its base classes, |
| 25 | + one of which calls <code>super().__del__</code>. This super call resolves to the next class in the Method Resolution Order (MRO) of the subclass, |
| 26 | + which may be another base class that already has its initializer explicitly called.</li> |
23 | 27 | </ul>
|
24 | 28 |
|
25 | 29 |
|
26 | 30 | </overview>
|
27 | 31 | <recommendation>
|
28 |
| -<p>Either be careful not to explicitly call a <code>__del__</code> method more than once, or |
29 |
| -use <code>super()</code> throughout the inheritance hierarchy.</p> |
30 |
| - |
31 |
| -<p>Alternatively refactor one or more of the classes to use composition rather than inheritance.</p> |
| 32 | +<p>Ensure that each finalizer method is called exactly once during finalization. |
| 33 | +This can be ensured by calling <code>super().__del__</code> for each finalizer methid in the inheritance chain. |
| 34 | +</p> |
32 | 35 |
|
33 | 36 | </recommendation>
|
34 | 37 | <example>
|
35 |
| -<p>In the first example, explicit calls to <code>__del__</code> are used, but <code>SportsCar</code> erroneously calls |
36 |
| -both <code>Vehicle.__del__</code> and <code>Car.__del__</code>. |
37 |
| -This can be fixed by removing the call to <code>Vehicle.__del__</code>, as shown in <code>FixedSportsCar</code>. |
38 |
| -</p> |
39 | 38 |
|
40 |
| -<sample src="SuperclassDelCalledMultipleTimes.py" /> |
41 |
| - |
42 |
| -<p>In the second example, there is a mixture of explicit calls to <code>__del__</code> and calls using <code>super()</code>. |
43 |
| -To fix this example, <code>super()</code> should be used throughout. |
| 39 | +<p>In the following example, there is a mixture of explicit calls to <code>__del__</code> and calls using <code>super()</code>, resulting in <code>Vehicle.__del__</code> |
| 40 | +being called twice. |
| 41 | +<code>FixedSportsCar.__del__</code> fixes this by using <code>super()</code> consistently with the other delete methods. |
44 | 42 | </p>
|
45 | 43 |
|
46 | 44 | <sample src="SuperclassInitCalledMultipleTimes2.py" />
|
47 | 45 |
|
48 | 46 | </example>
|
49 | 47 | <references>
|
50 |
| - |
51 |
| - <li>Python Tutorial: <a href="https://docs.python.org/2/tutorial/classes.html">Classes</a>.</li> |
52 |
| - <li>Python Standard Library: <a href="https://docs.python.org/2/library/functions.html#super">super</a>.</li> |
53 |
| - <li>Artima Developer: <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=236275">Things to Know About Python Super</a>.</li> |
54 |
| - <li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Composition_over_inheritance">Composition over inheritance</a>.</li> |
55 |
| - |
| 48 | + |
| 49 | + <li>Python Reference: <a href="https://docs.python.org/3/reference/datamodel.html#object.__del__">__del__</a>.</li> |
| 50 | + <li>Python Standard Library: <a href="https://docs.python.org/3/library/functions.html#super">super</a>.</li> |
| 51 | + <li>Python Glossary: <a href="https://docs.python.org/3/glossary.html#term-method-resolution-order">Method resolution order</a>.</li> |
| 52 | + <li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem">The Diamond Problem</a>.</li> |
56 | 53 |
|
57 | 54 | </references>
|
58 | 55 | </qhelp>
|
0 commit comments