frozendict (v0.1)

Steven D'Aprano steve at
Fri Oct 8 19:25:28 CEST 2010

On Fri, 08 Oct 2010 14:00:17 +0000, kj wrote:

> In <i8loa2$3oe$1 at> kj < at> writes:
>>At any rate, using your [i.e. Arnaud's] suggestions in this and your
>>other post, the current implementation of frozendict stands at:
>>class frozendict(dict):
>>    for method in ('__delitem__ __setitem__ clear pop popitem'
>>                   'setdefault update').split():
>>        exec """
>>def %s(self, *a, **k):
>>    cn = self.__class__.__name__
>>    raise TypeError("'%%s' object is not mutable" %% cn)
>>""" % method
>>    def __hash__(self):
>>        return hash(frozenset(self.items()))
>>...which is a lot nicer!
> As a side comment on my own post, this is the second time in less than a
> week that I find myself having to resort to exec'ing some code generated
> from a template.  This one is worse, because there's nothing
> runtime-dependent about the code being exec'd.

Er, *all* Python classes are created at runtime. The class statement is 
executed at runtime, not compile time. Not that it really matters.

But in any case, it's easy enough to avoid exec with a factory function. 
The following is untested, but should work:

def no_mutate_factory(name):
    def inner(self, *args, **kwargs):
        cn = self.__class__.__name__
        raise TypeError('%s instance is not mutable' % cn)
    inner.__name__ = name
    return inner

class FrozenDict(dict):
    update = no_mutate_factory('update')
    clear = no_mutate_factory('clear')
    # ...

It's a bit messy to have to list the name of the method twice. But you 
can inject the appropriate methods into the class by adding them from 
outside the class block:

class FrozenDict(dict):

for name in 'update clear'.split()  # and the others
    setattr(FrozenDict, name, no_mutate_factory(name))

del name  # Avoid namespace pollution, if you care.


More information about the Python-list mailing list