Allow the namesake callable to be called when a module is called

I’ve lost count of the number of times I’ve seen Python newbies asking why they’re getting the TypeError: 'module' object is not callable error:

>>> import pprint
>>> pprint([[1, 2], [3, 4]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'module' object is not callable
>>>

And even a more experienced Python user like myself often find it annoying having to repeat the same name in the form of the boilerplate of:

from tqdm import tqdm
for i in tqdm(range(10)): # let's pretend there's no trange for illustration's' sake
    ...

rather than a simple:

import tqdm
for i in tqdm(range(10)):
    ...

when all I want from a module is to call its main function or class that is named the same as the module itself.

Would it not make the usage friendlier if Python allowed a module to be callable by automatically resolving a call to a module object to its attribute of the same name?

To allow cases where the main callable is cased/spelled differently from the module name, such as decimal.Decimal, we can consider either making decimal.decimal an alias to decimal.Decimal, or accept a new module-level dunder such as __call__:

# _pydecimal.py
class Decimal(object):
    ...

decimal = Decimal # alias approach
__call__ = Decimal # dunder approach

However, this would mean we would then see codes spelling the same callable differently:

import decimal
d = decimal('1.23')

and

from decimal import Decimal
d = Decimal('1.23')

so whether or not to support calling a non-namesake callable when a module is called is more debatable.

This was formally rejected by the steering council last year. PEP 713 – Callable Modules | peps.python.org

8 Likes

Thanks for the link to the PEP, which somehow did not show up in my search prior to my post.

Nevertheless, if I understand the reason of rejection of the PEP correctly, the proposal was rejected because it would somehow create a slippery slope of allowing other module-level dunder names such as __or__ or __iter__ to be supported.

I personally find this reason of rejection puzzling because it’s drawing a false equivalence between the utility/demand of a __call__ and an __or__, the latter of which I can’t imagine an intuitive use for, while the benefit of allowing a __call__ is clear. The proposal may not be “compelling” because, of course, we can always continue to live with the boilerplate of from X import X, but when the required change to make this happen is so minimal, I just don’t see why not. We certainly can be selective about which module-level dunders to support and not have to go down a slippery slope. And we can also choose not to introduce a new dunder at all and just make the namesake callable to be called automatically when a module is called, to avoid any potential of a slippery slope, if that is really a concern.

My feeling here is that “special cases aren’t special enough to break the rules”. As long as Python conceives of a module as a fundamentally different thing from a class, the module object is providing an important namespacing feature.

The problem lies in the design of old, leaking batteries like datetime.

2 Likes

It’s also worth considering what happens when that namesake callable happens to be a class and the implications for type checkers. You would end up right back where you started where the namesake callable is not valid as a type, but the actual class is[1], so your small ergonomic improvement instantly evaporates unless you add even more special casing.


  1. another typing related corner case is a generic class, where the module would not be subscriptable, but the class is ↩︎

1 Like

As for pprint, there is now pprint.pprint() and pprint.pp(). The difference between them is tiny, but pprint.pp() was introduced specially to keep pprint.pprint() unchanged. Today, I would rather write from pprint import pp.

So, when make the pprint module callable, what should it call, pprint.pprint() or pprint.pp()? And if tomorrow we add pprint.p() or pprint.ppp(), should it change the behavior (breaking backward compatibility) or keep an older inferior behavior?

4 Likes

I feel like this would only really be okay to use for having the callable a function and not a class, since the naming conventions for modules and classes are not the same.

Outside of the standard library, I think significantly more cases will be named like decimal.Decimal than datetime.datetime.

Please – we’ve had long discussions, a PEP, more discussion, then a PEP rejection. This will not be changed.

6 Likes

This is a good error message and a good learning opportunity. If you are confused about why calling a module gives an error then it is good that you see the error so that you can learn that modules and functions are different things. That distinction is an important fundamental point that Python programmers should learn. Making some modules behave like functions would be more confusing than helpful for new Python programmers.

3 Likes

But I can make the same argument for __call__: it hides the namespace that a callable came from and it isn’t clear to me that it’s a benefit beyond a mistake someone might make once and then learn how namespaces work. I think the explicitness of modules is important for readability.

The SC also only changed by one member since that decision was made, so it isn’t about to reconsider this decision.

Closing as the SC recently evaluated this, and multiple core devs have backed that up.