I think there's been some confusion with regard to this idea, leading to a
combination of technical details vs the merits of the idea.
So I'm going to summarize a bit what I think the discussion has yielded:
Technical issues:
The __repr__ and __str__ are defined on the class, not instances of a class.
You cannot override them in an instance.
modules are instances of the module class.
Thus the only way to change the __repr__ or __str__ (or other magic
methods) is to create a custom subclass of the module class.
Design issues:
You probably don't want to change the __repr__ of a module anyway -- there
are good reasons to keep the repr of all modules the same and standardized.
(which is one reason __repr__'s are defined on the class, not the instance,
you generally wouldn't want different instances of classes to have
different __repr__s (or any other different magic method behavior).
And while customizing the __repr__ of a module to be non standard is a bad
idea, it's not such a bad idea to customize the __str__ of a module --
traditionally that's where you put a more human-readable version of an
object.
But: modules are kind of special: in the VAST majority of the time, the
instances are created by the import mechanism, which the user has little
control over. And the writer of the module even less. In many cases, one
could write a custom subclass of a standard type, and have your code run
that instead of the usual type, and your users would get that custom class,
but it's difficult to do that with modules.
You can define a custom module class by subclassing types.ModuleType. And
you could put that custom module in a __init__.py of a package, and then be
able to do:
from the_package import the_module
and then the_module will have a custom __str__
Here that is, in action:
in module_str/__init__.py:
import types
class StrModule(types.ModuleType):
def __init__(self, name, custom_str):
super().__init__(name)
self.___str__ = custom_str
def __str__(self):
return f"module {self.__name__}: {self.___str__}"
# create a new module with a custom string representation:
a_module = StrModule("a_module", "a custom str() for a_module" )
# put a few things into it
a_module.x = 5
def a_function():
return "a_function was called"
a_module.a_function = a_function
the use it:
"""
test code for a custom string module
"""
from module_str import a_module
print("the repr of the module:", repr(a_module))
print("the str of the module:", str(a_module))
print("and it works:")
print(a_module.x)
print(a_module.a_function())
Which when run:
$ python try_module_str.py
the repr of the module: