# PEP 726: Module \_\_setattr\_\_ and \_\_delattr\_\_

**URL:** <https://discuss.python.org/t/pep-726-module-setattr-and-delattr/32640>\
**Category:** PEPs\
**Created:** [August 31, 2023, 3:34am UTC](https://discuss.python.org/t/pep-726-module-setattr-and-delattr/32640 "2023-08-31T03:34:40Z")\
**Posts on this page:** 1\
**Showing post:** 20

<div class="post-metadata">

**Author:** ![Andy\_kl](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/andy_kl/32/12032_2.png) [@Andy\_kl](https://discuss.python.org/u/Andy_kl)\
**Post date:** [September 6, 2023, 10:58am UTC](https://discuss.python.org/t/pep-726-module-setattr-and-delattr/32640/20 "2023-09-06T10:58:12Z")

</div>

> [@Jelle](#):
>
> Normally dunders are looked up on the class, not the instance. This PEP would add two exceptions to that rule. We have two similar exceptions already for modules (` __getattr__ ` and ` __dir__ `), but any additional exceptions would further muddy the general rule. We shouldn’t do it without a strong motivation.

In my mental model of modules `ModuleType` was more of a metaclass and when I write the module I kinda of create a

```auto
class Foo(metaclass=types.ModuleType):
    def __dir__ (self) ...
    ...

```

And only on import I create an instance that is cached in `sys.modules`, but I still can create another instance of the same module. And the way it is in CPython is more an implementation detail.

> [@Jelle](#):
>
> I read the PEP and I don’t find the motivation compelling. The PEP lists a few categories of use cases (e.g., “To prevent setting an attribute at all (i.e. make it read-only)”), but gives no concrete examples. I haven’t personally felt a need for it or heard of a lot of cases where it is useful. Victor gives a good example above with `sys`, but I’m not sure a single module is enough to justify a language change.

One of my use-cases is to invalidate cache when some module attribute is changed, for example

```py
# module.py
default_arg2 = 1

_result_cache = {}
def foo(arg1, arg2=None):
    arg2 = default_arg2 if arg2 is None else arg2
    if (result := _result_cache.get((arg1, arg2))) is not None:
        return result
    # slow computation.
    return _result_cache.setdefault((arg1, arg2), result)

def __setattr__ (self, name, value):
    if name == "default_arg2":
        _result_cache = {k: v for k, v in _result_cache.items() if k[1] == default_arg2}
    globals()[name] = value

```

Right now I have a module with a class that holds default\_arg, cache and computation method and instance of it. And I also have `foo = class_instance.foo` to make computation, and to change default I expect users to do `module.class_instance.default_arg = `.  
It was written that way before I knew about `module. __class__ ` trick, and for my case I would be ok to pay 2x slowdown for attribute access (it shouldn’t happen often enough to be noticeable for normal workloads), I can imagine cases where it’s more a concern.

Well, I think cache is one of the cases of more general “module have some invariant and atrribute mutation should keep the invariant” and I think almost any invariant imaginabe for regular class can exists for module.

---

_[View the full topic](https://discuss.python.org/t/pep-726-module-setattr-and-delattr/32640)._
