How to get a unique id for bound methods?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Russell E. Owen

    How to get a unique id for bound methods?

    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
  • Benji York

    #2
    Re: How to get a unique id for bound methods?

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

    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
    [color=blue]
    > I guess that just means bound methods aren't objects in their own right,
    > but it surprised me.[/color]

    Nope, they're objects, they just don't tend to be around very long.
    [color=blue]
    > 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.[/color]

    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

    Comment

    • Bengt Richter

      #3
      Re: How to get a unique id for bound methods?

      On Fri, 19 Aug 2005 13:29:19 -0700, "Russell E. Owen" <rowen@cesmail. net> wrote:
      [color=blue]
      >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).
      >[/color]
      [color=blue]
      >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:
      >[/color]
      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.
      [color=blue]
      >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[/color]
      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.
      [color=blue]
      >print id(c.meth1)
      >3616240
      >print id(c.meth2)
      >3616240[/color]
      This happened to re-use a representation space with another id.[color=blue]
      >
      >I guess that just means bound methods aren't objects in their own right,
      >but it surprised me.[/color]
      No, they are objects in their own right. You were surprised by your
      [mis]interpretation of the above results ;-)[color=blue]
      >
      >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.
      >[/color]
      If you want a particular bound method to have a stable and persistent id,
      make it persist, e.g.,
      [color=blue][color=green][color=darkred]
      >>> class cls(object):[/color][/color][/color]
      ... def __init__(self):
      ... print id(self.meth1)
      ... print id(self.meth2)
      ... def meth1(self):
      ... pass
      ... def meth2(self):
      ... pass
      ...[color=blue][color=green][color=darkred]
      >>> c = cls()[/color][/color][/color]
      49219060
      49219060[color=blue][color=green][color=darkred]
      >>> print id(c.meth1)[/color][/color][/color]
      49219020[color=blue][color=green][color=darkred]
      >>> print id(c.meth2)[/color][/color][/color]
      49219020

      Ok, those were transient, now nail a couple of bound methods down:[color=blue][color=green][color=darkred]
      >>> cm1 = c.meth1
      >>> cm2 = c.meth2[/color][/color][/color]

      And you can look at their id's all you like:
      [color=blue][color=green][color=darkred]
      >>> print id(cm1)[/color][/color][/color]
      49219020[color=blue][color=green][color=darkred]
      >>> print id(cm2)[/color][/color][/color]
      49219060[color=blue][color=green][color=darkred]
      >>> print id(cm1)[/color][/color][/color]
      49219020[color=blue][color=green][color=darkred]
      >>> print id(cm2)[/color][/color][/color]
      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:
      [color=blue][color=green][color=darkred]
      >>> print id(c.meth1)[/color][/color][/color]
      49219180[color=blue][color=green][color=darkred]
      >>> print id(c.meth2)[/color][/color][/color]
      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:
      [color=blue][color=green][color=darkred]
      >>> print id(cm1)[/color][/color][/color]
      49219020[color=blue][color=green][color=darkred]
      >>> print id(cm2)[/color][/color][/color]
      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

      Comment

      • Paolino

        #4
        Re: How to get a unique id for bound methods?

        Russell E. Owen wrote:
        [color=blue]
        > 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.
        >[/color]
        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(sel f.meth.im_func)
        should be a chance for that 'hash' function.

        def methodId(boundM ethod):
        return id(boundMethod. im_self)^id(bou ndMethod.im_fun c)

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

        c = cls()
        print methodId(c.meth 1)
        print methodId(c.meth 2)

        I think this is giving what you expected.

        Regards Paolino





        _______________ _______________ _____
        Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB

        Comment

        • Russell E. Owen

          #5
          Re: How to get a unique id for bound methods?

          In article <mailman.3295.1 124486677.10512 .python-list@python.org >,
          Benji York <benji@benjiyor k.com> wrote:
          [color=blue]
          >Russell E. Owen wrote:[color=green]
          >> The id of two different methods of the same object seems to be the
          >> same, and it may not be stable either.[/color]
          >
          >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)[/color]

          Thank you and Bengt Richter. You both explained it very well.

          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.

          Does the built-in hash function actually do the job?

          If I centralize all tk callback management and keep objects that
          represent the tk callback around then I can avoid the whole issue. I was
          hoping to avoid that, because it complicates housekeeping and adds a
          risk of memory leaks (at least I think so; right now tk deallocates its
          callback functions in the few cases I care about so I don't worry about
          it.)

          -- Russell

          P.S. Paolino: thank you also for your kind reply. Your suggestion sounds
          very useful if I only want a hash for a bound function, but in this case
          since I want a hash for any callable entity I'm not sure it'll work.

          Comment

          • Bengt Richter

            #6
            Re: How to get a unique id for bound methods?

            On Fri, 19 Aug 2005 16:33:22 -0700, "Russell E. Owen" <rowen@cesmail. net> wrote:
            [...][color=blue]
            >
            >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.
            >[/color]
            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 ;-)

            Regards,
            Bengt Richter

            Comment

            • Russell E. Owen

              #7
              Re: How to get a unique id for bound methods?

              In article <43067d0e.19064 48017@news.oz.n et>,
              bokr@oz.net (Bengt Richter) wrote:
              [color=blue]
              >On Fri, 19 Aug 2005 16:33:22 -0700, "Russell E. Owen" <rowen@cesmail. net>
              >wrote:
              >[...][color=green]
              >>
              >>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.
              >>[/color]
              >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 ;-)[/color]

              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(t k, func):
              tkName = "cb%d" % hash(func)
              tk.createcomman d(tkNname, func)
              return tkName

              class TkSocket(TkBase Socket):
              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(s elf._tk, self._doConnect )
              self._tk.call(' fileevent', self._sock, "writable", connName
              except Tkinter.TclErro r, e:
              raise RuntimeError(e)

              Comment

              • Fredrik Lundh

                #8
                Re: How to get a unique id for bound methods?

                Russell E. Owen wrote:
                [color=blue][color=green][color=darkred]
                >>>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.[/color][/color][/color]

                have you tried Tkinter's built-in _register method?
                [color=blue][color=green][color=darkred]
                >>> import Tkinter
                >>> w = Tkinter.Tk()
                >>> help(w._registe r)[/color][/color][/color]
                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.
                [color=blue][color=green][color=darkred]
                >>> def func():[/color][/color][/color]
                .... print "Hello"
                ....[color=blue][color=green][color=darkred]
                >>> name = w._register(fun c)
                >>> name[/color][/color][/color]
                '10768336func'
                [color=blue][color=green][color=darkred]
                >>> w.tk.call(name)[/color][/color][/color]
                Hello
                'None'

                </F>



                Comment

                • Oren Tirosh

                  #9
                  Re: How to get a unique id for bound methods?

                  Russell E. Owen wrote:[color=blue]
                  > 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).[/color]
                  [color=blue][color=green][color=darkred]
                  >>> def persistent_boun d_method(m):[/color][/color][/color]
                  .... return m.im_self.__dic t__.setdefault( m.im_func.func_ name, m)
                  ....[color=blue][color=green][color=darkred]
                  >>> class A:[/color][/color][/color]
                  .... def x(self):
                  .... return
                  ....[color=blue][color=green][color=darkred]
                  >>> a=A()
                  >>> a.x is a.x[/color][/color][/color]
                  False[color=blue][color=green][color=darkred]
                  >>> persistent_boun d_method(a.x) is persistent_boun d_method(a.x)[/color][/color][/color]
                  True[color=blue][color=green][color=darkred]
                  >>>[/color][/color][/color]

                  Comment

                  • Russell E. Owen

                    #10
                    Re: How to get a unique id for bound methods?

                    In article <mailman.3378.1 124742573.10512 .python-list@python.org >,
                    "Fredrik Lundh" <fredrik@python ware.com> wrote:
                    [color=blue]
                    >Russell E. Owen wrote:
                    >[color=green][color=darkred]
                    >>>>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.[/color][/color]
                    >
                    >have you tried Tkinter's built-in _register method?
                    >[color=green][color=darkred]
                    >>>> import Tkinter
                    >>>> w = Tkinter.Tk()
                    >>>> help(w._registe r)[/color][/color]
                    >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.[/color]

                    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

                    Comment

                    • Russell E. Owen

                      #11
                      Re: How to get a unique id for bound methods?

                      In article <mailman.3378.1 124742573.10512 .python-list@python.org >,
                      "Fredrik Lundh" <fredrik@python ware.com> wrote:
                      [color=blue]
                      >Russell E. Owen wrote:
                      >[color=green][color=darkred]
                      >>>>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.[/color][/color]
                      >
                      >have you tried Tkinter's built-in _register method?
                      >[color=green][color=darkred]
                      >>>> import Tkinter
                      >>>> w = Tkinter.Tk()
                      >>>> help(w._registe r)[/color][/color]
                      >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.[/color]

                      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

                      Comment

                      • Fredrik Lundh

                        #12
                        Re: How to get a unique id for bound methods?

                        Russell E. Owen wrote:
                        [color=blue]
                        > 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.[/color]

                        of course it keeps a reference to it; how else do you expect
                        the Tcl command to find the right PyObjects?
                        [color=blue][color=green][color=darkred]
                        >>> import Tkinter
                        >>> w = Tkinter.Tk()
                        >>> def f():[/color][/color][/color]
                        .... pass
                        ....[color=blue][color=green][color=darkred]
                        >>> import sys
                        >>> sys.getrefcount (f)[/color][/color][/color]
                        2[color=blue][color=green][color=darkred]
                        >>> w.register(f)[/color][/color][/color]
                        '9571664f'[color=blue][color=green][color=darkred]
                        >>> sys.getrefcount (f)[/color][/color][/color]
                        3[color=blue][color=green][color=darkred]
                        >>> del f
                        >>> w.tk.call("9571 664f")[/color][/color][/color]
                        'None'

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

                        </F>



                        Comment

                        • Russell E. Owen

                          #13
                          Re: How to get a unique id for bound methods?

                          In article <mailman.3448.1 124861507.10512 .python-list@python.org >,
                          "Fredrik Lundh" <fredrik@python ware.com> wrote:
                          [color=blue]
                          >Russell E. Owen wrote:
                          >[color=green]
                          >> 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.[/color]
                          >
                          >of course it keeps a reference to it; how else do you expect
                          >the Tcl command to find the right PyObjects?[/color]

                          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

                          Comment

                          Working...