How to get a unique id for bound methods?

Discussion in 'Python' started by Russell E. Owen, Aug 19, 2005.

  1. I have several situations in my code where I want a unique identifier
    for a method of some object (I think this is called a bound method). I
    want this id to be both unique to that method and also stable (so I can
    regenerate it later if necessary).

    I thought the id function was the obvious choice, but it doesn't seem to
    work. The id of two different methods of the same object seems to be the
    same, and it may not be stable either. For instance:

    class cls(object):
    def __init__(self):
    print id(self.meth1)
    print id(self.meth2)
    def meth1(self):
    pass
    def meth2(self):
    pass

    c = cls()
    3741536
    3741536
    print id(c.meth1)
    3616240
    print id(c.meth2)
    3616240

    I guess that just means bound methods aren't objects in their own right,
    but it surprised me.

    The "hash" function looks promising -- it prints out consistent values
    if I use it instead of "id" in the code above. Is it stable and unique?
    The documentation talks about "objects" again, which given the behavior
    of id makes me pretty nervous.

    Any advice would be much appreciated.

    -- Russell
     
    Russell E. Owen, Aug 19, 2005
    #1
    1. Advertising

  2. Russell E. Owen

    Benji York Guest

    Russell E. Owen wrote:
    > The id of two different methods of the same object seems to be the
    > same, and it may not be stable either.


    Two facts you're (apparently) unaware of are conspiring against you:

    1) the "id" of an object is consistent for the lifetime of the object,
    but may be reused after the object goes away

    2) methods are bound on an as-needed basis and then normally discarded
    (unless you do something to keep them around)

    An illustration:

    class cls(object):
    def meth1(self):
    pass
    def meth2(self):
    pass

    c = cls()
    m1 = c.meth1
    print id(m1)
    -1209779308
    m2 = c.meth1
    print id(m2)
    -1209652732

    > I guess that just means bound methods aren't objects in their own right,
    > but it surprised me.


    Nope, they're objects, they just don't tend to be around very long.

    > The "hash" function looks promising -- it prints out consistent values
    > if I use it instead of "id" in the code above. Is it stable and unique?
    > The documentation talks about "objects" again, which given the behavior
    > of id makes me pretty nervous.
    >
    > Any advice would be much appreciated.


    I think you'll get the best advice from this group if you tell us what
    the larger problem is that you're trying to solve.
    --
    Benji York
     
    Benji York, Aug 19, 2005
    #2
    1. Advertising

  3. On Fri, 19 Aug 2005 13:29:19 -0700, "Russell E. Owen" <> wrote:

    >I have several situations in my code where I want a unique identifier
    >for a method of some object (I think this is called a bound method). I
    >want this id to be both unique to that method and also stable (so I can
    >regenerate it later if necessary).
    >


    >I thought the id function was the obvious choice, but it doesn't seem to
    >work. The id of two different methods of the same object seems to be the
    >same, and it may not be stable either. For instance:
    >

    The id function works, but you are applying it to transient objects, which
    is what bound methods are unless you cause them to persist one way or another.

    >class cls(object):
    > def __init__(self):
    > print id(self.meth1)
    > print id(self.meth2)
    > def meth1(self):
    > pass
    > def meth2(self):
    > pass
    >
    >c = cls()
    >3741536
    >3741536

    This means that self.meth1 only existed long enough to be passed to id,
    and when id was done with determining its id, self.meth1 was freed.
    Then self.meth2 was created, and happened to use a representation space
    with the same id as was used for self.meth1. If the two objects (bound methods
    here) existed at the same time, they would be guaranteed not to have the same id
    unless they were actually the same object.

    >print id(c.meth1)
    >3616240
    >print id(c.meth2)
    >3616240

    This happened to re-use a representation space with another id.
    >
    >I guess that just means bound methods aren't objects in their own right,
    >but it surprised me.

    No, they are objects in their own right. You were surprised by your
    [mis]interpretation of the above results ;-)
    >
    >The "hash" function looks promising -- it prints out consistent values
    >if I use it instead of "id" in the code above. Is it stable and unique?
    >The documentation talks about "objects" again, which given the behavior
    >of id makes me pretty nervous.
    >
    >Any advice would be much appreciated.
    >

    If you want a particular bound method to have a stable and persistent id,
    make it persist, e.g.,

    >>> class cls(object):

    ... def __init__(self):
    ... print id(self.meth1)
    ... print id(self.meth2)
    ... def meth1(self):
    ... pass
    ... def meth2(self):
    ... pass
    ...
    >>> c = cls()

    49219060
    49219060
    >>> print id(c.meth1)

    49219020
    >>> print id(c.meth2)

    49219020

    Ok, those were transient, now nail a couple of bound methods down:
    >>> cm1 = c.meth1
    >>> cm2 = c.meth2


    And you can look at their id's all you like:

    >>> print id(cm1)

    49219020
    >>> print id(cm2)

    49219060
    >>> print id(cm1)

    49219020
    >>> print id(cm2)

    49219060

    But every time you just evaluate the attribute expression c.meth1 or c.meth2
    you will get a new transient bound method object, with a new id:

    >>> print id(c.meth1)

    49219180
    >>> print id(c.meth2)

    49219180

    But the ones we forced to persist by binding the expression values to cm1 and cm2
    above still have the same ids as before:

    >>> print id(cm1)

    49219020
    >>> print id(cm2)

    49219060

    So the question would be, why do you (think you ;-) need ids for
    these bound methods as such? I.e., what is the "situation" in your code?

    Regards,
    Bengt Richter
     
    Bengt Richter, Aug 19, 2005
    #3
  4. Russell E. Owen

    Paolino Guest

    Russell E. Owen wrote:

    > The "hash" function looks promising -- it prints out consistent values
    > if I use it instead of "id" in the code above. Is it stable and unique?
    > The documentation talks about "objects" again, which given the behavior
    > of id makes me pretty nervous.
    >

    I dont know how the hash of a bound method is calculated,but as the
    function of the method is a stable and referenced object and as
    instances lives are in your hands,then an id(self)^id(self.meth.im_func)
    should be a chance for that 'hash' function.

    def methodId(boundMethod):
    return id(boundMethod.im_self)^id(boundMethod.im_func)

    class cls(object):
    def __init__(self):
    print methodId(self.meth1)
    print methodId(self.meth2)
    def meth1(self):
    pass
    def meth2(self):
    pass

    c = cls()
    print methodId(c.meth1)
    print methodId(c.meth2)

    I think this is giving what you expected.

    Regards Paolino





    ___________________________________
    Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB
    http://mail.yahoo.it
     
    Paolino, Aug 20, 2005
    #4
  5. In article <>,
    (Bengt Richter) wrote:

    >On Fri, 19 Aug 2005 16:33:22 -0700, "Russell E. Owen" <>
    >wrote:
    >[...]
    >>
    >>The current issue is associated with Tkinter. I'm trying to create a tk
    >>callback function that calls a python "function" (any python callable
    >>entity).
    >>
    >>To do that, I have to create a name for tk that is unique to my python
    >>"function". A hash-like name would be perfect, meaning a name that is
    >>always the same for a particular python "function" and always different
    >>for a different python "function". That would save a lot of housekeeping.
    >>

    >Why do you need a name? Can you post an example snippet that shows
    >a callback function being used with Tkinter as you would wish?
    >I have a feeling there is a much simpler solution than you are imagining ;-)


    Here is an example (simplified from my real code; I may have introduced
    an error in the process). I could switch to the twisted framework, but
    this code has been working very well and it saves my users from having
    to install a 3rd party package.

    -- Russell

    def addTkCallback(tk, func):
    tkName = "cb%d" % hash(func)
    tk.createcommand(tkNname, func)
    return tkName

    class TkSocket(TkBaseSocket):
    def __init__(self,
    addr,
    port,
    binary=False,
    readCallback = None,
    stateCallback = None,
    tkSock = None,
    ):
    ...
    try:
    # create the socket and configure it
    self._sock = self._tk.call("socket", ...)
    self._tk.call("fconfigure", self._sock, ...)

    # add callbacks; the write callback is just used to detect
    state
    readName =addTkCallback(self._tk, self._doRead)
    self._tk.call('fileevent', self._sock, "readable",
    readName)
    connName = addTkCallback(self._tk, self._doConnect)
    self._tk.call('fileevent', self._sock, "writable", connName
    except Tkinter.TclError, e:
    raise RuntimeError(e)
     
    Russell E. Owen, Aug 22, 2005
    #5
  6. Russell E. Owen wrote:

    >>>The current issue is associated with Tkinter. I'm trying to create a tk
    >>>callback function that calls a python "function" (any python callable
    >>>entity).
    >>>
    >>>To do that, I have to create a name for tk that is unique to my python
    >>>"function". A hash-like name would be perfect, meaning a name that is
    >>>always the same for a particular python "function" and always different
    >>>for a different python "function". That would save a lot of housekeeping.


    have you tried Tkinter's built-in _register method?

    >>> import Tkinter
    >>> w = Tkinter.Tk()
    >>> help(w._register)

    Help on method _register in module Tkinter:

    _register(self, func, subst=None, needcleanup=1) method of Tkinter.Tk
    instance
    Return a newly created Tcl function. If this
    function is called, the Python function FUNC will
    be executed. An optional function SUBST can
    be given which will be executed before FUNC.

    >>> def func():

    .... print "Hello"
    ....
    >>> name = w._register(func)
    >>> name

    '10768336func'

    >>> w.tk.call(name)

    Hello
    'None'

    </F>
     
    Fredrik Lundh, Aug 22, 2005
    #6
  7. Russell E. Owen

    Oren Tirosh Guest

    Russell E. Owen wrote:
    > I have several situations in my code where I want a unique identifier
    > for a method of some object (I think this is called a bound method). I
    > want this id to be both unique to that method and also stable (so I can
    > regenerate it later if necessary).


    >>> def persistent_bound_method(m):

    .... return m.im_self.__dict__.setdefault(m.im_func.func_name, m)
    ....
    >>> class A:

    .... def x(self):
    .... return
    ....
    >>> a=A()
    >>> a.x is a.x

    False
    >>> persistent_bound_method(a.x) is persistent_bound_method(a.x)

    True
    >>>
     
    Oren Tirosh, Aug 23, 2005
    #7
  8. In article <>,
    "Fredrik Lundh" <> wrote:

    >Russell E. Owen wrote:
    >
    >>>>The current issue is associated with Tkinter. I'm trying to create a tk
    >>>>callback function that calls a python "function" (any python callable
    >>>>entity).
    >>>>
    >>>>To do that, I have to create a name for tk that is unique to my python
    >>>>"function". A hash-like name would be perfect, meaning a name that is
    >>>>always the same for a particular python "function" and always different
    >>>>for a different python "function". That would save a lot of housekeeping.

    >
    >have you tried Tkinter's built-in _register method?
    >
    >>>> import Tkinter
    >>>> w = Tkinter.Tk()
    >>>> help(w._register)

    >Help on method _register in module Tkinter:
    >
    >_register(self, func, subst=None, needcleanup=1) method of Tkinter.Tk
    >instance
    > Return a newly created Tcl function. If this
    > function is called, the Python function FUNC will
    > be executed. An optional function SUBST can
    > be given which will be executed before FUNC.


    Thanks. That looks like just the thing. I think I had seen it but was
    deterred by the leading underscore (suggesting an internal method whose
    interface might change). Still, I guess if it gets modified I can just
    change my code.

    -- Russell
     
    Russell E. Owen, Aug 23, 2005
    #8
  9. In article <>,
    "Fredrik Lundh" <> wrote:

    >Russell E. Owen wrote:
    >
    >>>>The current issue is associated with Tkinter. I'm trying to create a tk
    >>>>callback function that calls a python "function" (any python callable
    >>>>entity).
    >>>>
    >>>>To do that, I have to create a name for tk that is unique to my python
    >>>>"function". A hash-like name would be perfect, meaning a name that is
    >>>>always the same for a particular python "function" and always different
    >>>>for a different python "function". That would save a lot of housekeeping.

    >
    >have you tried Tkinter's built-in _register method?
    >
    >>>> import Tkinter
    >>>> w = Tkinter.Tk()
    >>>> help(w._register)

    >Help on method _register in module Tkinter:
    >
    >_register(self, func, subst=None, needcleanup=1) method of Tkinter.Tk
    >instance
    > Return a newly created Tcl function. If this
    > function is called, the Python function FUNC will
    > be executed. An optional function SUBST can
    > be given which will be executed before FUNC.


    Having looked at it again, it is familiar. I copied it when I wrote my
    own code. I avoided using at the time both because the initial
    underscore suggested it was a private method and because it introduces
    an extra function call.

    _register has the same weakness that my code had when I used id(func) --
    it uses the id of the function to generate the unique tk function name,
    but it keeps no reference to that function.

    Either Tkinter is clever about keeping a reference to each callable
    around, or else it has the same bug I was seeing and it just doesn't
    show up often enough to have been caught. I should take some time and
    look into that.

    It's a frustrating problem. There should be some simple way to get a
    unique hash-like identifier for any callable entity. If one were just
    using functions then id() would be fine. But bound methods are too
    different.

    I'll use "hash" for now, but given that I"m not sure what hash is even
    doing, I should recode to something that I know works.

    -- Russell
     
    Russell E. Owen, Aug 23, 2005
    #9
  10. Russell E. Owen wrote:

    > Having looked at it again, it is familiar. I copied it when I wrote my
    > own code. I avoided using at the time both because the initial
    > underscore suggested it was a private method and because it introduces
    > an extra function call.
    >
    > _register has the same weakness that my code had when I used id(func) --
    > it uses the id of the function to generate the unique tk function name,
    > but it keeps no reference to that function.
    >
    > Either Tkinter is clever about keeping a reference to each callable
    > around, or else it has the same bug I was seeing and it just doesn't
    > show up often enough to have been caught. I should take some time and
    > look into that.


    of course it keeps a reference to it; how else do you expect
    the Tcl command to find the right PyObjects?

    >>> import Tkinter
    >>> w = Tkinter.Tk()
    >>> def f():

    .... pass
    ....
    >>> import sys
    >>> sys.getrefcount(f)

    2
    >>> w.register(f)

    '9571664f'
    >>> sys.getrefcount(f)

    3
    >>> del f
    >>> w.tk.call("9571664f")

    'None'

    (PyObject pointers to the callable and the interpreter object are
    stored in a Tcl clientData record associated with the command)

    </F>
     
    Fredrik Lundh, Aug 24, 2005
    #10
  11. In article <>,
    "Fredrik Lundh" <> wrote:

    >Russell E. Owen wrote:
    >
    >> Having looked at it again, it is familiar. I copied it when I wrote my
    >> own code. I avoided using at the time both because the initial
    >> underscore suggested it was a private method and because it introduces
    >> an extra function call.
    >>
    >> _register has the same weakness that my code had when I used id(func) --
    >> it uses the id of the function to generate the unique tk function name,
    >> but it keeps no reference to that function.
    >>
    >> Either Tkinter is clever about keeping a reference to each callable
    >> around, or else it has the same bug I was seeing and it just doesn't
    >> show up often enough to have been caught. I should take some time and
    >> look into that.

    >
    >of course it keeps a reference to it; how else do you expect
    >the Tcl command to find the right PyObjects?


    Right. Of course.

    I started out emulating the code for _register but over time made
    various incremental changes. Eventually I messed up and started taking
    the id of the wrong thing. I was able to fix that and all is well --
    without having to use the mysterious hash function.

    I also now keep a reference to the tk function name so I can properly
    delete it when finished. That eliminates a small memory leak.

    Thanks for all your help.

    -- Russell
     
    Russell E. Owen, Aug 24, 2005
    #11
    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. sunil panda

    Lower bound & Upper bound

    sunil panda, Dec 25, 2003, in forum: Java
    Replies:
    9
    Views:
    7,355
    thushara wijeratna
    Oct 7, 2008
  2. Rhiner Dan
    Replies:
    1
    Views:
    773
    Mike Wahler
    Mar 27, 2005
  3. Mario Krsnic
    Replies:
    0
    Views:
    398
    Mario Krsnic
    Jun 23, 2006
  4. ToshiBoy
    Replies:
    6
    Views:
    886
    ToshiBoy
    Aug 12, 2008
  5. Token Type
    Replies:
    9
    Views:
    391
    Chris Angelico
    Sep 9, 2012
Loading...

Share This Page