RE: Method binding confusion

Discussion in 'Python' started by Robert Brewer, May 3, 2004.

  1. Peter Otten wrote:
    > <kmy.py>
    > import math
    > #import myModule
    >
    > def mypow(x, y):
    > return "%s ** %s" % (x, y)
    >
    > class Klass(object):
    > def doOperation(self, x, y):
    > return self.operator(x, y)
    >
    > class KlassMath(Klass):
    > operator = math.pow
    >
    > class KlassMyModule(Klass):
    > operator = mypow #myModule.pow
    >
    > km = KlassMath()
    > kmy = KlassMyModule()
    >
    > print km.doOperation(2,4)
    > print kmy.doOperation(2,4)
    > </kmy.py>
    >
    > >>> class A:

    > ... pass
    > ...
    > >>> def method(*args):

    > ... print args
    > ...
    > >>> A.m = method
    > >>>
    > >>> A().m(1,2)

    > (<__main__.A instance at 0x40296bac>, 1, 2)
    >
    > See? Although defined outside the class, method() is called with 3
    > parameters. *I* could have sworn that _that_ would always happen. But:
    >
    > >>> import math
    > >>> A.m = math.pow
    > >>> A().m(1,2)

    > 1.0
    > >>>

    >
    > Now I am as confused as you and the OP :-(


    Specifically, one needs to explain why:

    >>> kmy.KlassMath.operator

    <built-in function pow>
    >>> kmy.KlassMath().operator

    <built-in function pow>

    but:

    >>> kmy.KlassMyModule.operator

    <unbound method KlassMyModule.mypow>
    >>> kmy.KlassMyModule().operator

    <bound method KlassMyModule.mypow of <kmy.KlassMyModule object at
    0x0114DCD0>>

    ....which I haven't got the vocabulary or time for right now. ;(


    Robert Brewer
    MIS
    Amor Ministries
     
    Robert Brewer, May 3, 2004
    #1
    1. Advertising

  2. Robert Brewer

    Peter Otten Guest

    Robert Brewer wrote:

    > Specifically, one needs to explain why:
    >
    >>>> kmy.KlassMath.operator

    > <built-in function pow>
    >>>> kmy.KlassMath().operator

    > <built-in function pow>
    >
    > but:
    >
    >>>> kmy.KlassMyModule.operator

    > <unbound method KlassMyModule.mypow>
    >>>> kmy.KlassMyModule().operator

    > <bound method KlassMyModule.mypow of <kmy.KlassMyModule object at
    > 0x0114DCD0>>
    >
    > ...which I haven't got the vocabulary or time for right now. ;(


    Following Andrew Bennetts' hint and rereading parts of
    http://users.rcn.com/python/download/Descriptor.htm
    the following is the most striking example that I could come up with to
    demonstrate how the existence/absence of a __get__() method controls a
    method's behaviour:

    >>> import types
    >>> class Method(object):

    .... def __get__(self, obj, objtype=None):
    .... return types.MethodType(self, obj, objtype)
    .... def __call__(*args):
    .... print "method%r" % (args,)
    ....
    >>> class A: pass

    ....
    >>> A.method = Method()
    >>> a = A()
    >>> a.method(1,2,3)

    method(<__main__.Method object at 0x40296d0c>, <__main__.A instance at
    0x40296c0c>, 1, 2, 3)

    Now away with __get__():

    >>> del Method.__get__
    >>> a.method(1,2,3)

    method(<__main__.Method object at 0x40296d0c>, 1, 2, 3)
    >>>


    Bye the way, I tried this with a simple function first, but failed:

    >>> def f(): pass

    ....
    >>> del f.__get__

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: 'function' object attribute '__get__' is read-only
    >>>


    The machinery behind the observed behaviour is now somewhat clearer - I
    think you can predict a function's behaviour as a method by checking
    hasattr(func, "__get__"). But still the *reason* (or simply use-case) for
    this dichotomy of functions (to me) remains unclear. Why are not all
    functions created equal?

    Peter
     
    Peter Otten, May 3, 2004
    #2
    1. Advertising

  3. On Mon, May 03, 2004 at 07:52:02PM +0200, Peter Otten wrote:
    [...]
    >
    > The machinery behind the observed behaviour is now somewhat clearer - I
    > think you can predict a function's behaviour as a method by checking
    > hasattr(func, "__get__"). But still the *reason* (or simply use-case) for
    > this dichotomy of functions (to me) remains unclear. Why are not all
    > functions created equal?


    I suppose that BuiltinFunctionType is probably slightly simpler and faster
    this way. After all, how often is an instance of a user-defined class going
    to be right type to be the first argument to a builtin function? (I can
    think of contrived cases, but I've never come across a need for this
    behaviour, which is why I'd never noticed it was missing until this thread.)

    That's just me speculating, though...

    Interestingly,
    >>> import types
    >>> types.BuiltinFunctionType is types.BuiltinMethodType

    True

    (types.BuiltinFunctionType seems to distinguish between functions and
    methods by looking at its __self__ attribute; builtin functions have a
    __self__ of None).

    -Andrew.
     
    Andrew Bennetts, May 4, 2004
    #3
  4. On Mon, 03 May 2004 19:52:02 +0200, Peter Otten <>
    wrote:
    <snip>
    >The machinery behind the observed behaviour is now somewhat clearer - I
    >think you can predict a function's behaviour as a method by checking
    >hasattr(func, "__get__"). But still the *reason* (or simply use-case) for
    >this dichotomy of functions (to me) remains unclear. Why are not all
    >functions created equal?


    All functions and methods *should* be unified. See the section
    "Unification of all function forms" in PrototypeSyntax.doc at
    http://www.ece.arizona.edu/~edatools/Python

    I'm astonished at how a problem like this can be tolerated in a
    language that claims to be simple.

    Here is my simplification of the example which started this thread:

    import math

    def mypow(x, y):
    return x**y

    class MathA:
    pow = math.pow

    class MathB:
    pow = mypow

    ma = MathA()
    mb = MathB()

    print ma.pow(2,4) #=>
    16.0
    print mb.pow(2,4) #=>
    # TypeError: mypow() takes exactly 2 arguments (3 given)

    This problem, and a lot of others that confuse beginners could be
    eliminated if all functions and methods had exactly the same sequence
    of arguments (no special first argument).

    -- Dave
     
    David MacQuigg, May 22, 2004
    #4
  5. Robert Brewer

    Dave Brueck Guest

    David MacQuigg wrote:
    > All functions and methods *should* be unified. See the section
    > "Unification of all function forms" in PrototypeSyntax.doc at
    > http://www.ece.arizona.edu/~edatools/Python


    That's cool that you've taken the time to gather your thoughts onto some pages
    that anyone can view. One thing that might make them even more useful to
    illustrate your point would be to have a page that shows unification in the
    absense of the other changes you're proposing (in the page listed above, the
    reader has to set aside prototypes and miscellaneous syntax changes and try to
    focus on just function/method unification).

    Also, such a page would really benefit from a few simple but uncontrived
    examples of how things work now, and how they'd work after your proposed
    changes. From reading that page, I'm not entirely sure how the tasks I
    currently solve with bound methods, unbound methods, static functions, etc.
    would work under the new system - many people learn best by example, but that
    page illustrates (as far as I can tell) how only one method of calling would be
    affected, and the example is obscured by unrelated syntax languages.

    So, for example, find the two or three most common use cases of unbound
    methods, and simplify the examples to make them concise but not so far that
    they becomes overly contrived (in the math example you've posted a few times, I
    have a hard time imagining why I'd ever want to do that, so to me it's not very
    compelling). Show the code for the implementation as well as how the calls
    happen. Then show the same for how things would look after your changes. Repeat
    this whole process for all calling conventions that would be affected.

    Short of this, the ability to convince people will be limited - the problem you
    cite doesn't seem to affect me much in day-to-day development, and I haven't
    seen it be a big hangup for people learning the language (most don't
    notice/care, the rest get past it almost instantly with the simplest of
    explanations). If on top of that it's also unclear to me how I'd get the same
    things done if the language were changed (and it _is_ unclear to me), then it's
    hard to maintain interest in this topic.

    Good luck!
    -Dave
     
    Dave Brueck, May 22, 2004
    #5
  6. Op 2004-05-22, David MacQuigg schreef <>:
    > On Mon, 03 May 2004 19:52:02 +0200, Peter Otten <>
    > wrote:
    ><snip>
    >>The machinery behind the observed behaviour is now somewhat clearer - I
    >>think you can predict a function's behaviour as a method by checking
    >>hasattr(func, "__get__"). But still the *reason* (or simply use-case) for
    >>this dichotomy of functions (to me) remains unclear. Why are not all
    >>functions created equal?

    >
    > All functions and methods *should* be unified. See the section
    > "Unification of all function forms" in PrototypeSyntax.doc at
    > http://www.ece.arizona.edu/~edatools/Python
    >
    > I'm astonished at how a problem like this can be tolerated in a
    > language that claims to be simple.
    >
    > Here is my simplification of the example which started this thread:
    >
    > import math
    >
    > def mypow(x, y):
    > return x**y
    >
    > class MathA:
    > pow = math.pow
    >
    > class MathB:
    > pow = mypow
    >
    > ma = MathA()
    > mb = MathB()
    >
    > print ma.pow(2,4) #=>
    > 16.0
    > print mb.pow(2,4) #=>
    > # TypeError: mypow() takes exactly 2 arguments (3 given)
    >
    > This problem, and a lot of others that confuse beginners could be
    > eliminated if all functions and methods had exactly the same sequence
    > of arguments (no special first argument).


    I agree that what you show here is a problem, because the behaviour of
    the language here is not consistent.

    However I get the impression that a lot of confusion you see with
    beginners is your own confusion you are passing on.

    --
    Antoon Pardon
     
    Antoon Pardon, May 24, 2004
    #6
  7. On Mon, 03 May 2004 19:52:02 +0200, Peter Otten <>
    wrote:
    <snip>
    >The machinery behind the observed behaviour is now somewhat clearer - I
    >think you can predict a function's behaviour as a method by checking
    >hasattr(func, "__get__"). But still the *reason* (or simply use-case) for
    >this dichotomy of functions (to me) remains unclear. Why are not all
    >functions created equal?


    All functions and methods *should* be unified. See the section
    "Unification of all function forms" in PrototypeSyntax.doc at
    http://www.ece.arizona.edu/~edatools/Python

    Here is my simplification of the example which started this thread:

    import math

    def mypow(x, y):
    return x**y

    class MathA:
    pow = math.pow

    class MathB:
    pow = mypow

    ma = MathA()
    mb = MathB()

    print ma.pow(2,4) #=>
    16.0
    print mb.pow(2,4) #=>
    # TypeError: mypow() takes exactly 2 arguments (3 given)

    This problem, and a lot of others that confuse beginners could be
    eliminated if all functions and methods had exactly the same sequence
    of arguments (no special first argument).

    I posted this example in the thread "Unification of Methods and
    Functions" 5/22/04, but got only the standard response "You don't need
    to do that." I don't know the origin of this example, so I don't know
    if there is a valid requirement or not. In any case it seems simple
    enough that there shouldn't be a problem.

    I think the OP is not following this discussion, or even responding to
    emails, so if anyone knows if the above is valid code, please let us
    know.

    -- Dave
     
    David MacQuigg, May 24, 2004
    #7
  8. > This problem, and a lot of others that confuse beginners could be
    > eliminated if all functions and methods had exactly the same sequence
    > of arguments (no special first argument).


    It can be done.

    >>> import math
    >>>
    >>> def mypow(x, y):

    .... return x**y
    ....
    >>> class MathA:

    .... pow = math.pow
    ....
    >>> class MathB:

    .... pow = staticmethod(mypow)
    ....
    >>> ma = MathA()
    >>> mb = MathB()
    >>>
    >>> ma.pow(2,4)

    16.0
    >>> mb.pow(2,4)

    16

    Whether or not there should be an implied self or not, is a value
    judgement. Guido (and everyone else who works on the core Python
    language) has heard your (and everyone else's) arguments before. I
    would put good odds on there not likely to be /any/ sort of change
    toward what you are advocating (the merging of functions and methods) in
    the forseeable future (before Python 3.0) in standard Python. And even
    in the far future (Python 3.0), there is no guarantee.

    - Josiah
     
    Josiah Carlson, May 25, 2004
    #8
  9. Josiah Carlson wrote:
    > [fix]

    In my eyes the inconsistency is the other way around... the built-in
    function acts unexpected.

    Cheers,
    Michael
     
    Michael Walter, May 25, 2004
    #9
  10. Sorry for the double post. My newsreader ( Agent ) seems to be not
    threading properly on this thread, and it looked like the first post
    wasn't received.

    -- Dave
     
    David MacQuigg, May 25, 2004
    #10
  11. On Sat, 22 May 2004 14:10:28 -0600, "Dave Brueck"
    <> wrote:

    >David MacQuigg wrote:
    >> All functions and methods *should* be unified. See the section
    >> "Unification of all function forms" in PrototypeSyntax.doc at
    >> http://www.ece.arizona.edu/~edatools/Python

    >
    >That's cool that you've taken the time to gather your thoughts onto some pages
    >that anyone can view. One thing that might make them even more useful to
    >illustrate your point would be to have a page that shows unification in the
    >absense of the other changes you're proposing (in the page listed above, the
    >reader has to set aside prototypes and miscellaneous syntax changes and try to
    >focus on just function/method unification).


    I wrote a short example in the first post of the "Unification of
    Methods and Functions" thread -- how unification would look without
    the other changes. I also made some notes in the OOP Chapter --
    showing that I plan to drop the "classless prototype" stuff in the
    next revision.

    >Also, such a page would really benefit from a few simple but uncontrived
    >examples of how things work now, and how they'd work after your proposed
    >changes. From reading that page, I'm not entirely sure how the tasks I
    >currently solve with bound methods, unbound methods, static functions, etc.
    >would work under the new system - many people learn best by example, but that
    >page illustrates (as far as I can tell) how only one method of calling would be
    >affected, and the example is obscured by unrelated syntax languages.


    There are some short ( contrived ) examples showing how to translate
    each of the four function/method styles to the new syntax in Appendix
    1 of Prototypes.doc at http://ece.arizona.edu/~edatools/Python I'm
    also planning on translating all the examples people have submitted
    for my Examples and Exercises under the same address.

    >So, for example, find the two or three most common use cases of unbound
    >methods, and simplify the examples to make them concise but not so far that
    >they becomes overly contrived (in the math example you've posted a few times, I
    >have a hard time imagining why I'd ever want to do that, so to me it's not very
    >compelling). Show the code for the implementation as well as how the calls
    >happen. Then show the same for how things would look after your changes. Repeat
    >this whole process for all calling conventions that would be affected.
    >
    >Short of this, the ability to convince people will be limited - the problem you
    >cite doesn't seem to affect me much in day-to-day development, and I haven't
    >seen it be a big hangup for people learning the language (most don't
    >notice/care, the rest get past it almost instantly with the simplest of
    >explanations). If on top of that it's also unclear to me how I'd get the same
    >things done if the language were changed (and it _is_ unclear to me), then it's
    >hard to maintain interest in this topic.


    I'm getting exhausted myself. I'll post again in a few months. Looks
    like there is no rush in planning for Python 3. Meanwhile, those who
    are interested can check on the page above for anything new.

    -- Dave
     
    David MacQuigg, May 25, 2004
    #11
  12. On Mon, 24 May 2004 17:21:07 -0700, Josiah Carlson <>
    wrote:

    >Whether or not there should be an implied self or not, is a value
    >judgement. Guido (and everyone else who works on the core Python
    >language) has heard your (and everyone else's) arguments before.


    I've seen some of the discussions in searching the archives, but what
    I have seen misses the point about unification and goes overboard on
    matters of personal preference. I agree that using an explicit 'self'
    in the body of the method is a personal preference call that only GvR
    can make, and I've tried to steer around this issue. Unfortunately,
    because my suggestion requires taking 'self' out of the first
    argument, there is an automatic reaction -- oh we've heard that
    before, another "self hater".

    >I would put good odds on there not likely to be /any/ sort of change
    >toward what you are advocating (the merging of functions and methods) in
    >the forseeable future (before Python 3.0) in standard Python. And even
    >in the far future (Python 3.0), there is no guarantee.


    This *is* a Python 3 proposal. No way we can make it backward
    compatible with Python 2. My focus instead has been on making the
    changes "migratable" -- that is, we *must* have the ability to
    automatically translate existing Python programs to the new syntax.
    These are minor improvements in the language, and no such improvement
    would be worth the loss of ten years development in Python.

    -- Dave
     
    David MacQuigg, May 25, 2004
    #12
  13. On Mon, 24 May 2004 17:21:07 -0700, Josiah Carlson <>
    wrote:

    >It can be done.
    >
    > >>> import math
    > >>>
    > >>> def mypow(x, y):

    >... return x**y
    >...
    > >>> class MathA:

    >... pow = math.pow
    >...
    > >>> class MathB:

    >... pow = staticmethod(mypow) <== ***
    >...
    > >>> ma = MathA()
    > >>> mb = MathB()
    > >>>
    > >>> ma.pow(2,4)

    >16.0
    > >>> mb.pow(2,4)

    >16


    Yes. This is the solution I came up with. It's a valuable exercise
    for students, but I warn them not to worry about what's going on in
    Python, just look at the error message and see if you can fix the
    problem. The error message is the familiar:

    TypeError: mypow() takes exactly 2 arguments (3 given)

    This message, and the knowledge that calling from an instance adds an
    extra argument, should be sufficient clue to add the staticmethod
    wrapper.

    -- Dave
     
    David MacQuigg, May 25, 2004
    #13
  14. Robert Brewer

    Myles Guest

    > extra argument, should be sufficient clue to add the staticmethod
    > wrapper.


    I'm coming from a dabbler's viewpoint.
    Why the binding tricks ? Couldn't you just "wrap" the methods ?
    My solution:
    ----
    import math

    def mypow(x, y):
    return x**y

    class MathA:
    def pow(self, x, y):
    return mypow(x,y)

    class MathB:
    def pow(self, x, y):
    return math.pow(x,y)

    ma = MathA()
    mb = MathB()

    print ma.pow(2, 3)
    print mb.pow(2, 3)
    ----
    This seems more obvious and consistent to me, or am I missing the
    point of the discussion ?

    Regards, Myles.
     
    Myles, May 26, 2004
    #14
  15. On 25 May 2004 18:11:02 -0700, (Myles) wrote:

    >> extra argument, should be sufficient clue to add the staticmethod
    >> wrapper.

    >
    >I'm coming from a dabbler's viewpoint.
    >Why the binding tricks ? Couldn't you just "wrap" the methods ?
    >My solution:
    >----
    >import math
    >
    >def mypow(x, y):
    > return x**y
    >
    >class MathA:
    > def pow(self, x, y):
    > return mypow(x,y)
    >
    >class MathB:
    > def pow(self, x, y):
    > return math.pow(x,y)
    >
    >ma = MathA()
    >mb = MathB()
    >
    >print ma.pow(2, 3)
    >print mb.pow(2, 3)
    >----
    >This seems more obvious and consistent to me, or am I missing the
    >point of the discussion ?


    This is similar to what the original poster had, before I stripped it
    down to the smallest example that would show the error. I'm sure
    there are other solutions as well, including: Don't do this.

    What makes this problem interesting to me, is that you can actually
    fix a problem as tricky as this without really understanding the
    mechanism behind it. I have seen that error message many times. At
    first it puzzled me, because there were clearly two arguments, not
    three, in the original call. After seeing it a few times, I now
    recognize that the extra argument is coming from Python's method of
    passing 'self'. 'self' is not needed in this case, so we wrap the
    troublesome function in staticmethod( ), and the problem goes away.

    -- Dave
     
    David MacQuigg, May 26, 2004
    #15
    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. Jordan
    Replies:
    2
    Views:
    2,562
    Jordan
    Feb 10, 2004
  2. Replies:
    2
    Views:
    1,079
  3. Amit
    Replies:
    6
    Views:
    13,893
    Assimalyst
    Oct 24, 2006
  4. A B Carter

    Method binding confusion

    A B Carter, May 3, 2004, in forum: Python
    Replies:
    6
    Views:
    343
    Sridhar R
    May 3, 2004
  5. Replies:
    2
    Views:
    897
    Kevin Grover
    Oct 20, 2006
Loading...

Share This Page