Star imports trick

Saturday 8 October 2022

Star imports trick

Star-imports (from typing import *) in Python are a handy, but dangerous. They are meant for quick coding, i.e. like on a jupyterlab notebook. However they are bad as they can mask other variables and cause issues down the line. They are ubiquitous online as are guides explaining why they are bad, here I just want to share a handy snippet to iron out star-imports.

Here is an example:

from collections import Counter
from typing import *

counter = Counter(...)

In typing there is a variable Counter, which by virtue of being imported into the namespace second annuls the first import. The module typing can be dangerous for the above, but I'd say I have a good idea what is there. PyRosetta is a very large and the exmaple code is full of naughty star imports, which really out to not be mimicked to avoid namespace pollution, but does not really cause odd clashes.

Note: herein obviously the word module means a namespace as per standard Python, not a base class for a ANN model, which is inexplicably named so.

There are four solution to the problem:
  • gain omniscience of the star-imported module: bad choice
  • use star imports within the scope of a function: repetitive
  • import the module as itself or a shorthand: makes the code look clunky, but a must for big modules like pd, np tf and so forth.
  • use star import and fix it later: quicker

For the latter, one can list all the variables in a module:

import typing 

print(f'({", ".join(typing.__all__)})')

(Any, Callable, ClassVar, ForwardRef, Generic, Optional, Tuple, Type, TypeVar, Union, AbstractSet, ByteString, Container, ContextManager, Hashable, ItemsView, Iterable, Iterator, KeysView, Mapping, MappingView, MutableMapping, MutableSequence, MutableSet, Sequence, Sized, ValuesView, Awaitable, AsyncIterator, AsyncIterable, Coroutine, Collection, AsyncGenerator, AsyncContextManager, Reversible, SupportsAbs, SupportsBytes, SupportsComplex, SupportsFloat, SupportsInt, SupportsRound, ChainMap, Counter, Deque, Dict, DefaultDict, List, OrderedDict, Set, FrozenSet, NamedTuple, Generator, AnyStr, cast, get_type_hints, NewType, no_type_check, no_type_check_decorator, NoReturn, overload, Text, TYPE_CHECKING)
I have this copy-pasted in my notes: I replace the star with this and optimise imports in PyCharm and done!*

*) Well, mostly, as a lot of these are missing in 3.7 or fun things like Unpack appear in 3.11, so one ends up doing a sneaky like a monkeypatch early on, so subsequent imports of typing will have it as the variable name of a module points to the same object as stored in sys.modules dictionary.

import sys
import typing
import typing_extensions
if sys.version_info < (3, 8):
    typing.TypedDict = typing_extensions.TypedDict            

No comments:

Post a Comment