| 34 | === Avoid overriding built-ins and wildcard-imports === |
| 35 | |
| 36 | Except where it is deliberate, we should avoid to use the names of built-in functions or types as variable names. |
| 37 | |
| 38 | Overriding a built-in function/type can - depending on scope - have adverse side-effects, which can then be very hard to trace back to a cause. |
| 39 | |
| 40 | Example: |
| 41 | |
| 42 | {{{#!python |
| 43 | # Somewhere at the top of the module |
| 44 | range = lambda x, y: (x, y) |
| 45 | |
| 46 | ... |
| 47 | |
| 48 | # Somewhere further down in the module |
| 49 | class Example(object): |
| 50 | |
| 51 | def __init__(self, maximum): |
| 52 | |
| 53 | self.indexes = [x for x in range(0, maximum)] |
| 54 | |
| 55 | # Doesn't crash, but doesn't behave as expected either: |
| 56 | # my_example.indexes should be [0, 1, 2, 3, 4], but instead it is (0, 5) |
| 57 | my_example = Example(5) |
| 58 | }}} |
| 59 | |
| 60 | The developer of the Example-class will find it difficult to understand why it doesn't work as expected - so we should avoid such situations. |
| 61 | |
| 62 | Python-3 introduces some new built-in names (e.g. "input"), so this needs extra care. A good strategy is to use a static code checker (e.g. pylint) to detect overrides, or to use an editor that highlights built-in names right away. |
| 63 | |
| 64 | A very tricky part of this are '''wildcard-imports''' like {{{from dateutil.rrule import *}}} - these wildcard imports can (unintentionally) override built-ins without that being obvious (dateutil.rrule overrides range, for instance). Therefore, we should avoid all wildcard-imports, except from internal modules (e.g. {{{from s3 import *}}}) where we have control over what they expose and what not. |