I want to implement a frozen and ordered dict.
I thought I'd implement it as a subclass of collections.OrderedDict
that prohibits all modifications to the dictionary after it has
been initialized.
In particular, calling this frozen subclass's update method should,
in general, trigger an exception ("object is not mutable").
But OrderedDict's functionality *requires* that its __init__ be
run, and this __init__, in turn, does part of its initialization
by calling the update method.
Therefore, the update method of the new subclass needs to be able
to identify the calling function in order to make a special allowance
for calls coming from OrderedDict.__init__. (Better yet, it should
be able to allow calls coming from its own class's __init__, via
OrderedDict.__init__.)
The best I've been able to do is to use inspect to get the name of
the calling function. For the case I'm trying to identify, this
name is simply "__init__".
But Python code is awash in __init__'s...
Is it possible to achieve a more precise identification? Specifically,
I want to know the *class* (not the file) where this '__init__' is
defined.
(BTW, I don't understand why inspect doesn't provide something as
basic as the *class* that the method belongs to, whenever applicable.
I imagine there's a good reason for this coyness, but I can't figure
it out.)
TIA!
~kj
Rather than trying to identify the caller, I'd do something like:
class FrozenODict(OrderedDict):
def __init__(self, *args, **kwargs):
OrderedDict.__init__(self, *args, **kwargs)
self.update = self._update # init is complete, so override
# update method for this instance
def _update(self, dict2):
raise Exception("object is immutable!!")
After the __init__, calls to the instance's 'update' function will be
mapped to _update. It's essentially overriding the inherited function
on the fly.
Cheers - Chas
One function object can "belong to" (be in the namespace of) more than
one class, so there is no "the class".
That's actually a fairly common question - is an object in
initialization, or has it been fully created? It would be useful
if Python had some standard way to check if initialization
has completed. Sometimes a parent class needs to know if
initialization of the entire object has completed. This typically
comes up with classes that define "__setattr__" and are then
subclassed.
John Nagle
There are many other properties that inspect reports on (e.g.
filename) that may not apply to an individual case. For 99.9% of
methods, the class in which it was lexically defined would be good
enough.
> But OrderedDict's functionality *requires* that its __init__ be
> run, and this __init__, in turn, does part of its initialization
> by calling the update method.
>
> Therefore, the update method of the new subclass needs to be able
> to identify the calling function in order to make a special allowance
> for calls coming from OrderedDict.__init__
That doesn't follow at all. Why not set a `frozen' flag when your
initialization is complete? Something like
class ImmutableOrderedDict (OrderedDict):
def __init__(me, *args, **kw):
me._frozen = False
OrderedDict.__init__(me, *arg, **kw)
me._frozen = True
def _check(me):
if me._frozen:
raise ImmutableError
And so on.
Thank you for explaining your actual objective, by the way.
-- [mdw]
I thought the __new__() method was for customizing how objects where
instantated. Where in __new__() you would get an object instance and
then usually initialize the public data attributes in __init__().
Although I like Mark Wooding's solution as it's clean and easy to
understand.