Method binding confusion

A

A B Carter

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
 
P

Peter Otten

A said:
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:
.... return "%s ** %s" % (a, b)
........ operator = staticmethod(mypow)
....
Peter
 
A

Andrew Bennetts

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.

See http://users.rcn.com/python/download/Descriptor.htm, particularly the
section on Functions and Methods.

-Andrew.
 
E

Eric Brunel

Peter said:
A B Carter wrote:




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




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:


... return "%s ** %s" % (a, b)
...

... operator = staticmethod(mypow)
...

'2 ** 4'


Peter

I can reproduce the OP's behaviour with old-style classes in Python 2.1.1:
.... def op(self, x, y):
.... return self.operator(x, y)
........ operator = math.pow
........ operator = myPow
....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...
 
P

Peter Otten

Eric said:
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...
.... pass
........ print args
....(<__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:

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

Peter
 
S

Sridhar R

Bound and Unbound methods are different and server different purposes.
See documentation for more details.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,481
Members
44,900
Latest member
Nell636132

Latest Threads

Top