Velocity Reviews > Method binding confusion

# Method binding confusion

A B Carter
Guest
Posts: n/a

 05-03-2004
I'm a bit confused by the behavior of the following code:

import math
import myModule

class Klass(object):
def doOperation(self, x, y):
return self.operator(x, y)

class KlassMath(Klass):
operator = math.pow

class KlassMyModule(Klass):
operator = myModule.pow

km = KlassMath()
kmy = KlassMyModule()

km.doOperation(2,4)
km.doOperation(2,4)

The last call fails with "TypeError: takes exactly 2 argumetns (3
given)" I understand that in KlassMyModule the operator is being
treated as a method and a reference to the class instance is being
past as the first argument. And I also understand that Python is
treating a function from the standard math libary differently from a
function I defined in my own module. What I don't understand is why.

A B Carter

Peter Otten
Guest
Posts: n/a

 05-03-2004
A B Carter wrote:

> I'm a bit confused by the behavior of the following code:
>
>
> import math
> import myModule
>
> class Klass(object):
> def doOperation(self, x, y):
> return self.operator(x, y)
>
> class KlassMath(Klass):
> operator = math.pow
>
> class KlassMyModule(Klass):
> operator = myModule.pow
>
> km = KlassMath()
> kmy = KlassMyModule()
>
> km.doOperation(2,4)
> km.doOperation(2,4)

Should that be kmy.doOperation(2,4)? Please cut and paste actual code. (The
same goes for the tracebacks)

> The last call fails with "TypeError: takes exactly 2 argumetns (3
> given)" I understand that in KlassMyModule the operator is being
> treated as a method and a reference to the class instance is being
> past as the first argument. And I also understand that Python is
> treating a function from the standard math libary differently from a
> function I defined in my own module. What I don't understand is why.

Assuming that myModule.pow (which you do not to provide) is a function that
takes two arguments, all these will fail:

kmy.doOperation(2, 4)
kmy.operator(2, 4)
km.doOperation(2, 4)
km.operator(2, 4)

If you want to avoid the automatic addition of self, use staticmethod:

>>> def mypow(a, b):

.... return "%s ** %s" % (a, b)
....
>>> class MyClass:

.... operator = staticmethod(mypow)
....
>>> MyClass().operator(2, 4)

'2 ** 4'
>>>

Peter

Andrew Bennetts
Guest
Posts: n/a

 05-03-2004
On Sun, May 02, 2004 at 11:57:26PM -0700, A B Carter wrote:
> I'm a bit confused by the behavior of the following code:

[...]
>
> The last call fails with "TypeError: takes exactly 2 argumetns (3
> given)" I understand that in KlassMyModule the operator is being
> treated as a method and a reference to the class instance is being
> past as the first argument. And I also understand that Python is
> treating a function from the standard math libary differently from a
> function I defined in my own module. What I don't understand is why.

Builtin functions aren't descriptors; in particular, they don't have the
method-wrapping magic in their __get__ that ordinary (i.e. pure-python)
function objects do.

section on Functions and Methods.

-Andrew.

Eric Brunel
Guest
Posts: n/a

 05-03-2004
Peter Otten wrote:
> A B Carter wrote:
>
>
>>I'm a bit confused by the behavior of the following code:
>>
>>
>>import math
>>import myModule
>>
>>class Klass(object):
>> def doOperation(self, x, y):
>> return self.operator(x, y)
>>
>>class KlassMath(Klass):
>> operator = math.pow
>>
>>class KlassMyModule(Klass):
>> operator = myModule.pow
>>
>>km = KlassMath()
>>kmy = KlassMyModule()
>>
>>km.doOperation(2,4)
>>km.doOperation(2,4)

>
>
> Should that be kmy.doOperation(2,4)? Please cut and paste actual code. (The
> same goes for the tracebacks)
>
>
>>The last call fails with "TypeError: takes exactly 2 argumetns (3
>>given)" I understand that in KlassMyModule the operator is being
>>treated as a method and a reference to the class instance is being
>>past as the first argument. And I also understand that Python is
>>treating a function from the standard math libary differently from a
>>function I defined in my own module. What I don't understand is why.

>
>
> Assuming that myModule.pow (which you do not to provide) is a function that
> takes two arguments, all these will fail:
>
> kmy.doOperation(2, 4)
> kmy.operator(2, 4)
> km.doOperation(2, 4)
> km.operator(2, 4)
>
> If you want to avoid the automatic addition of self, use staticmethod:
>
>
>>>>def mypow(a, b):
>>>

> ... return "%s ** %s" % (a, b)
> ...
>
>>>>class MyClass:
>>>

> ... operator = staticmethod(mypow)
> ...
>
>>>>MyClass().operator(2, 4)
>>>

> '2 ** 4'
>
>
> Peter

I can reproduce the OP's behaviour with old-style classes in Python 2.1.1:

>>> class C:

.... def op(self, x, y):
.... return self.operator(x, y)
....
>>> import math
>>> class C1(C):

.... operator = math.pow
....
>>> o1 = C1()
>>> o1.op(2, 3)

8.0
>>> def myPow(x, y): return '%s ** %s' % (x, y)

....
>>> class C2(C):

.... operator = myPow
....
>>> o2 = C2()
>>> o2.op(2, 3)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in op
TypeError: myPow() takes exactly 2 arguments (3 given)

I also cannot understand the difference between C1 and C2: math.pow and myPow
are both functions with two parameters, so why does the first work and not the
second? Or was it an "unwanted feature" that was removed in a later version?

I also have some difficulty to understand the "automatic addition of self" you
mention. In what case is it needed? I would have sworn the two classes worked...
--
- Eric Brunel <eric (underscore) brunel (at) despammed (dot) com> -

Peter Otten
Guest
Posts: n/a

 05-03-2004

Peter

Peter Otten
Guest
Posts: n/a

 05-03-2004
Eric Brunel wrote:

> I can reproduce the OP's behaviour with old-style classes in Python 2.1.1:

Me too, with new-style classes in Python 2.3.3:

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

Running the above:
\$ python -V
Python 2.3.3
\$ python kmy.py
16.0
Traceback (most recent call last):
File "kmy.py", line 21, in ?
print kmy.doOperation(2,4)
File "kmy.py", line 9, in doOperation
return self.operator(x, y)
TypeError: mypow() takes exactly 2 arguments (3 given)

> I also cannot understand the difference between C1 and C2: math.pow and
> myPow are both functions with two parameters, so why does the first work
> and not the second? Or was it an "unwanted feature" that was removed in a
> later version?
>
> I also have some difficulty to understand the "automatic addition of self"
> you mention. In what case is it needed? I would have sworn the two classes
> worked...

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

Peter

Sridhar R
Guest
Posts: n/a

 05-03-2004
Bound and Unbound methods are different and server different purposes.
See documentation for more details.

http://www.velocityreviews.com/forums/(E-Mail Removed) (A B Carter) wrote in message news:<(E-Mail Removed). com>...
> I'm a bit confused by the behavior of the following code:
>
>
> import math
> import myModule
>
> class Klass(object):
> def doOperation(self, x, y):
> return self.operator(x, y)
>
> class KlassMath(Klass):
> operator = math.pow
>
> class KlassMyModule(Klass):
> operator = myModule.pow
>
> km = KlassMath()
> kmy = KlassMyModule()
>
> km.doOperation(2,4)
> km.doOperation(2,4)
>
>
> The last call fails with "TypeError: takes exactly 2 argumetns (3
> given)" I understand that in KlassMyModule the operator is being
> treated as a method and a reference to the class instance is being
> past as the first argument. And I also understand that Python is
> treating a function from the standard math libary differently from a
> function I defined in my own module. What I don't understand is why.
>
> A B Carter