This is a purely stylistic discussion, but one I tend to feel quite strongly about. There is a lot of disparity in contemporary Python code when it comes to how library classes are named, usually taking one of the forms:
The first and third forms are particularly amenable to producing readable code when ‘from … import foo’ is used:
from myprotocol.tcp import TcpMyProtocolConnection
# .... many pages later ....
# Self-describing, assuming you know where "TcpMyProtocolConnection"
# came from.
conn = TcpMyProtocolConnection()
While the second form is particularly incompatible for the same:
from myprotocol.tcp import Connection
# .... many pages later ....
# Connection to what?!
conn = Connection()
If we instead decide not to use import aliases, the table is flipped. First and third forms:
# Explicit, but my fingers are bleeding!
conn = myprotocol.tcp.TcpMyProtocolConnection()
<myprotocol.tcp.TcpMyProtocolConnection object at 0x1099ecc90>
And the second form:
# Self-documenting, yet concise:
conn = myprotocol.tcp.Connection()
<myprotocol.tcp.Connection object at 0x1099eccd0>
Which leads to an interesting choice: either we always ignore the namespace a class is defined in, for the purposes of naming it, and allow succinct use of ‘from .. import foo’, or we explicitly acknowledge the class’s namespace as being part of its name, and punish ‘from .. import foo’.
I’m slowly coming to the belief that the second form above is *always* better code, as evidenced at least by Python’s own treatment of the class name, but also by the pain of picking up third party code written in the first/third styles. In alias-heavy code, we must constantly rely on backwards-search to find out where some alias or class comes from, along with any constants or free functions that were similarly imported.
However in the second form, where aliases are no longer self-describing, but the canonical form “myprotocol.tcp.Connection” is both easy to type and explicitly self-documenting, no such backwards search needs to be performed.
Additionally once a module is imported without aliases, its entire content is available without the need to constantly edit the top of a module each time you wish to use a new function or class from some other namespace. Another benefit is that when pruning dead code, you’re much less likely to leave behind a stray unused import.
I like this rule at least for “toy” examples, though it breaks down a lot, again, with module aliases (which I similarly avoid wherever possible):
from myprotocol import tcp
# ... sometime later ...
# Ugh, this is very readable, but incredibly misleading.
conn = tcp.Connection()
Still, when consuming my own packages I rarely find the need (or desire) to make module aliases, outside of the confined environment which is the package implementation itself, where the aliases usually come from a very limited vocabulary.
The reason for that appears to be that I mostly try to avoid deeply nested namespaces wherever possible: I can’t remember the last time I wrote a module named even just “myfoo.bar.baz”.
This is more or less just thinking aloud, I don’t see any rule here, even if I strongly prefer the second form above. It is however worth remembering that by prefixing your classes with “namespace summaries”, you are punishing users who do not like import aliases, and by avoiding such summaries, you are punishing those who do.