Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How can a function find the function that called it?

10 views
Skip to first unread message

kj

unread,
Dec 24, 2010, 11:24:34 AM12/24/10
to


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

Chris Gonnerman

unread,
Dec 24, 2010, 11:51:03 AM12/24/10
to pytho...@python.org
On 12/24/2010 10:24 AM, kj wrote:
> 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.
Use a flag, "private" to your new class, to indicate whether
initialization is complete or not; your update method would see that
initialization is not yet complete when called by __init__, and so it
would do its business (calling the class method). At the end of the
__init__ function, set the initialized property to true. If your update
is called with the initialized property already set to true, it will
raise the exception.

ChasBrown

unread,
Dec 24, 2010, 1:23:59 PM12/24/10
to
On Dec 24, 8:24 am, kj <no.em...@please.post> wrote:
> 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.
>

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

Daniel Urban

unread,
Dec 24, 2010, 1:26:06 PM12/24/10
to pytho...@python.org
On Fri, Dec 24, 2010 at 17:24, kj <no.e...@please.post> wrote:
> (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.)

One function object can "belong to" (be in the namespace of) more than
one class, so there is no "the class".

John Nagle

unread,
Dec 24, 2010, 1:26:40 PM12/24/10
to
On 12/24/2010 8:51 AM, Chris Gonnerman wrote:
> On 12/24/2010 10:24 AM, kj wrote:
>> 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.

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

kj

unread,
Dec 24, 2010, 1:43:06 PM12/24/10
to

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.

Mark Wooding

unread,
Dec 24, 2010, 1:58:37 PM12/24/10
to
kj <no.e...@please.post> writes:

> 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]

DevPlayer

unread,
Dec 25, 2010, 5:41:16 PM12/25/10
to
> Original Poster

> I thought I'd implement it as a subclass of collections.OrderedDict
> that prohibits all modifications to the dictionary after it has
> been initialized.

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.

0 new messages