> That said, is there a reason not to use relative imports?<p>Yes, they make reading imports across your entire project rather difficult: Suddenly there are multiple ways of referring to the same module. If you ever have to do a project-wide search & replace during a refactoring (because your favorite refactoring tool failed you), this will be hell.<p>Moreover, in each file you'll end up with a weird blend of absolute and relative imports, depending on what was shorter or looked nicer to the author at the time. Not nice to look at <i>at all</i>.<p>> This led me to dig into why we might add to __init__.py<p>…or why we might rather not. Init files are one of the main reasons imports in Python often behave in unexpected ways. As a library user I do <i>not</i> want to study the library's init files first, but unfortunately I often have to in order to understand what is going on. (Case in point: Tensorflow 1/2. To this day, I can't claim I understand how exactly their init magic works and time and again I get bitten by failed imports.)
“There should be one– and preferably only one –obvious way to do it.“<p>If you’re not maintaining one of the libraries listed in the article, and try to pull any of this “clever” stuff you’ll be bitten on the ankle by a pythonic snake. No exceptions.
Surely the most common reason for __init__ file content is re-exporting some otherwise deeper objects. The second is probably laziness - just bung it all in __init__!
Recently was also looking around for quantifiable stats on Python for: downloads, usage, FAQs, etc. — and found these:<p><a href="https://pypistats.org/top" rel="nofollow">https://pypistats.org/top</a><p><a href="https://www.programcreek.com/python/index/module/list" rel="nofollow">https://www.programcreek.com/python/index/module/list</a><p><a href="https://stackoverflow.com/questions/tagged/python?tab=Votes" rel="nofollow">https://stackoverflow.com/questions/tagged/python?tab=Votes</a><p>Anyone know of any others or large collections of Python source code that are easy to download?
I would add overriding boolean dunder methods: __and__, __or__, __xor__ dunder methods.<p>Even more rare is overriding bitwise shift operations: __rshift__, __lshift__ etc. This is unfortunate, as these methods are only natively implemented in integers, so they’re basically freebies.
I think multiple inheritance will always scare me. What order do the superclass inits run in? What happens if they do conflicting things? What if some superclasses call super().__init__ and others don't?<p>No thanks, I'll suffer through reading a few additional lines of:<p>class SomeBusinessyThing:<p><pre><code> def __init__(self, util, other_util):
self._util = util
self._other_util = other_util
@classmethod
def create(cls):
return cls(util_module.Util(), other_module.Other())
def calculate(self):
source = self_other_util.get_source()
return self._util.get_stuff(source)
</code></pre>
vs<p>class SomeBusinessyThing(Utils, Other):<p><pre><code> def __init__(self, \*kwargs):
# What does this do? No one knows
super().__init__(self, \*kwargs)
def calculate(self):
source = self.get_source()
return self.get_stuff(source)</code></pre>
I thought the article would be about "uncommon uses" as in "I didn't know this library had pieces written in Python". Relatedly, the original BitTorrent client might be one of the first widely-distributed applications written in Python.