This thread looks to me like there might be some miscommunication going on, so I want to try to share my understanding first.
I think that OP is not concerned with slowing down attribute assignment here, because assigning an attribute to an imported module is much less common than looking up an attribute there. The goal is to have some way to intercept attribute assignment so that an exception can be raised to guard against programming errors; of course we should expect this to have some overhead. However, the current best solution for intercepting attribute assignment, means that attribute lookup will also be slowed down. (I assume this is because we now have to work through a Python implementation of the module class instead of using a built-in one.)
However, if we add a __setattr__ hook to the C implementation, although that doesn’t impact on attribute lookups (satisfying OP’s use case), it presumably would slow down assigning attributes to modules for everybody. OP isn’t bothered by this in a SciPy or mpmath context, but a change like that needs serious consideration since the overhead cost would be paid even by people who don’t plan to use the hook.
Personally, my intuition is that it might still be worthwhile. It’s hard for me to imagine a popular third-party library that expects the user to set attributes on modules imported from the library, enough times to become a performance concern. On the other hand, a tight loop repeatedly calling some library function is pretty easy to imagine (granted, the user could trivially cache this lookup).
On the other hand, it’s commonly enough incorrect to assign attributes to a module (after import) that I almost wonder if it needs to be supported by default. (If I had to choose, I find it more annoying not being able to set attributes on an ordinary object instance - that also makes it harder to teach beginners about the concept of attributes in general, at least with my teaching style).
Therefore, I like this suggestion, assuming it works as expected. It should address OP’s use case and, if anything, improve performance rather than making it worse. Meanwhile, people who want to do fancy things with setting attributes on modules still have the option of taking the performance hit of a user-defined subclass (and if they want to do really fancy things, the __setattr__ hook is right there for them, because they already defined a class in Python).
For bonus points, a bit of standard library support, along the lines of:
from types import ModuleType
import sys
def module_setattr_hook(func=None):
"""
A decorator to enable custom logic for setting module attributes.
Decorate a top-level function in a module, to make it implement
attribute assignment for the module. It should accept three arguments:
* self: types.ModuleType - the module being modified.
* attr: str -> the name of the attribute being set.
* value -> the new value for the attribute.
Alternately, just call `module_setattr_hook()` to make it possible
to set attributes with no special logic.
"""
module = sys.modules[func.__module__]
cls = module.__class__
if cls is types.ModuleType:
# base type, needs to be swapped with a user type
cls = type('_UserModule', (types.ModuleType,), {})
module.__class__ = cls
# otherwise, just monkey-patch the existing type
if func is not None:
cls.__setattr__ = func
return func