How can a function find the function that called it?

Discussion in 'Python' started by kj, Dec 24, 2010.

  1. kj

    kj Guest

    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
     
    kj, Dec 24, 2010
    #1
    1. Advertising

  2. Re: [Python] How can a function find the function that called it?

    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.
     
    Chris Gonnerman, Dec 24, 2010
    #2
    1. Advertising

  3. kj

    ChasBrown Guest

    On Dec 24, 8: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.
    >


    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
     
    ChasBrown, Dec 24, 2010
    #3
  4. kj

    Daniel Urban Guest

    On Fri, Dec 24, 2010 at 17:24, kj <> 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".
     
    Daniel Urban, Dec 24, 2010
    #4
  5. kj

    John Nagle Guest

    Re: [Python] How can a function find the function that called it?

    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
     
    John Nagle, Dec 24, 2010
    #5
  6. kj

    kj Guest

    In <> Daniel Urban <> writes:

    >On Fri, Dec 24, 2010 at 17:24, kj <> 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".


    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.
     
    kj, Dec 24, 2010
    #6
  7. kj

    Mark Wooding Guest

    kj <> 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]
     
    Mark Wooding, Dec 24, 2010
    #7
  8. kj

    DevPlayer Guest

    > 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.
     
    DevPlayer, Dec 25, 2010
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Apricot
    Replies:
    4
    Views:
    532
    velthuijsen
    Apr 16, 2004
  2. Weng Tianxiang
    Replies:
    6
    Views:
    593
    glen herrmannsfeldt
    Sep 12, 2007
  3. S_K
    Replies:
    6
    Views:
    1,189
    Robert Dunlop
    Nov 8, 2007
  4. Jimmy Hartzell
    Replies:
    0
    Views:
    421
    Jimmy Hartzell
    May 19, 2008
  5. Jimmy Hartzell
    Replies:
    2
    Views:
    1,171
    Jimmy Hartzell
    May 20, 2008
Loading...

Share This Page