473,324 Members | 2,456 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

Function mistaken for a method

Hi all,

I just stepped on a thing that I can't explain. Here is some code showing
the problem:

-----------------------------
class C:
f = None
def __init__(self):
if self.f is not None:
self.x = self.f(0)
else:
self.x = 0

class C1(C):
f = int

class C2(C):
f = lambda x: x != 0

o1 = C1()
print o1.x

o2 = C2()
print o2.x
-----------------------------

Basically, I want an optional variant function across sub-classes of the
same class. I did it like in C1 for a start, then I needed something like
C2. The result is... surprising:

0
Traceback (most recent call last):
File "func-vs-meth.py", line 18, in ?
o2 = C2()
File "func-vs-meth.py", line 5, in __init__
self.x = self.f(0)
TypeError: <lambda>() takes exactly 1 argument (2 given)

So the first works and o1.x is actually 0. But the second fails because
self is also being passed as the first argument to the lambda. Defining a
"real" function doesn't help: the error is the same.

My actual question is: why does it work in one case and not in the other?
As I see it, int is just a function with one parameter, and the lambda is
just another one. So why does the first work, and not the second? What
'black magic' takes place so that int is not mistaken for a method in the
first case?
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 1 '06 #1
17 2203
Le Jeudi 01 Juin 2006 13:12, Eric Brunel a écrit :
class C1(C):
f = int
int is not a function but a type, but it's callable so int(0) return 0.
class C2(C):
f = lambda x: x != 0


lambda is a function, applied as a class attribute it becomes a method so it's
called with a first parameter representing the instance, self.f(0) in the
__init__ becomes C2.f(self, 0), so the lambda should be :

f = lambda s, x: x != 0 # s for self, some poeple use _

this exactly the same as :

def f(self, val) :
return x != 0

(that lambda will return True or False i expect this is not what you want)

--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Jun 1 '06 #2
Le Jeudi 01 Juin 2006 13:29, Maric Michaud a écrit*:
this exactly the same as :

* *def f(self, val) :
* * * *return x != 0

oops,
def f(self, val) :
return val != 0
--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Jun 1 '06 #3
Eric Brunel wrote:
My actual question is: why does it work in one case and not in the other?
As I see it, int is just a function with one parameter, and the lambda is
just another one. So why does the first work, and not the second? What
'black magic' takes place so that int is not mistaken for a method in the
first case?


A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.

Peter
Jun 1 '06 #4
Le Jeudi 01 Juin 2006 13:34, Peter Otten a écrit*:
A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.

I don't think it's about c-coded versus python-coded stuff, C1.f is a type,
C2.f is a method.

In [14]: class t : pass
....:

In [15]: class u :
....: f = t
....:
....:

In [16]: u().f()
Out[16]: <__main__.t instance at 0xa795a9ec>
--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Jun 1 '06 #5
Maric Michaud wrote:
Le Jeudi 01 Juin 2006 13:34, Peter Otten a écrit*:
A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.
I don't think it's about c-coded versus python-coded stuff, C1.f is a
type, C2.f is a method.


You are right, int is a type not a function, but presence (and
implementation, of course) of __get__ is still the distinguishing factor:
class Int(int): .... class __metaclass__(type):
.... def __get__(*args): print "XXX", args
.... class C: .... int = Int
.... C().int XXX (<class '__main__.Int'>, <__main__.C instance at 0x402948cc>, <class
__main__.C at 0x40281f2c>)

Also:
from math import sin
sin <built-in function sin> def son(x): pass .... class C: .... sin = sin
.... son = son
.... C().sin(0) 0.0 C().son(0)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: son() takes exactly 1 argument (2 given)

Peter
Jun 1 '06 #6
On 1/06/2006 9:46 PM, Maric Michaud wrote:
Le Jeudi 01 Juin 2006 13:34, Peter Otten a écrit :
A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.

I don't think it's about c-coded versus python-coded stuff, C1.f is a type,
C2.f is a method.


Try putting f = chr (a C function); it behaves like int, not like a
1-arg Python function. See below.

Cheers,
John

C:\junk>type func_meth.py
class C:
f = None
def __init__(self):
if self.f is not None:
self.x = self.f(0)
else:
self.x = 99 # differs from int(0) :-)
class C1(C):
f = int
class C2(C):
def f(self, arg):
return arg != 0
class C3(C):
pass
class C4(C):
f = chr
for cls in (C1, C2, C3, C4):
o = cls()
print "callable: %r; result: %r" % (o.f, o.x)

C:\junk>func_meth.py
callable: <type 'int'>; result: 0
callable: <bound method C2.f of <__main__.C2 instance at 0x00AE6F58>>;
result: False
callable: None; result: 99
callable: <built-in function chr>; result: '\x00'

C:\junk>

Jun 1 '06 #7
Peter Otten wrote:
Eric Brunel wrote:

My actual question is: why does it work in one case and not in the other?
As I see it, int is just a function with one parameter, and the lambda is
just another one. So why does the first work, and not the second? What
'black magic' takes place so that int is not mistaken for a method in the
first case?

A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.


FWIW:

class Obj(object):
def __new__(cls, val, *args, **kw):
print "in Obj.__new__"
print "- called with :"
print " cls :", cls
print " val :", val
print " args:", str(args)
print " kw :", kw
obj = object.__new__(cls, *args, **kw)
print "got : %s - %s" % (obj, dir(obj))
return obj

class CPlus(C):
f = Obj

Peter

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 1 '06 #8
On Thu, 01 Jun 2006 13:34:53 +0200, Peter Otten <__*******@web.de> wrote:
Eric Brunel wrote:
My actual question is: why does it work in one case and not in the
other?
As I see it, int is just a function with one parameter, and the lambda
is
just another one. So why does the first work, and not the second? What
'black magic' takes place so that int is not mistaken for a method in
the
first case?

A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.


Thanks for your explanations, Peter. I'll have to find another way to do
what I want...
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 1 '06 #9

Michael Yanowitz wrote:
Hello:
I have a Tkinter GUI Dialog with many buttons and labels and text
widgets.


So start a *new* thread.

Jun 1 '06 #10
Le Jeudi 01 Juin 2006 13:12, Eric Brunel a écrit*:
Thanks for your explanations, Peter. I'll have to find another way to do *
what I want...


maybe :

class C:
* *f = None
* *def __init__(self):
* * *if self.f is not None:
* * * *self.x = self.f(0)
* * *else:
* * * *self.x = 0

class C2(C):
* *def __init__(self) :
self.f = lambda x: x != 0

--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Jun 1 '06 #11
Eric Brunel wrote:
On Thu, 01 Jun 2006 13:34:53 +0200, Peter Otten <__*******@web.de> wrote:
Eric Brunel wrote:
My actual question is: why does it work in one case and not in the
other?
As I see it, int is just a function with one parameter, and the lambda
is
just another one. So why does the first work, and not the second? What
'black magic' takes place so that int is not mistaken for a method in
the
first case?

A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.


Thanks for your explanations, Peter. I'll have to find another way to do
what I want...


Maybe just

class C2(C):
f*=*staticmethod(lambda*x:*x*!=*0)

Peter

Jun 1 '06 #12
Eric Brunel wrote:
Hi all,

I just stepped on a thing that I can't explain. Here is some code
showing the problem:

-----------------------------
class C:
Do yourself a favour : use new-style classes.
class C(object)
f = None
def __init__(self):
if self.f is not None:
self.x = self.f(0)
else:
self.x = 0

class C1(C):
f = int

class C2(C):
f = lambda x: x != 0

o1 = C1()
print o1.x

o2 = C2()
print o2.x
-----------------------------

Basically, I want an optional variant function across sub-classes of
the same class.

I did it like in C1 for a start, then I needed
something like C2. The result is... surprising:

0
Traceback (most recent call last):
File "func-vs-meth.py", line 18, in ?
o2 = C2()
File "func-vs-meth.py", line 5, in __init__
self.x = self.f(0)
TypeError: <lambda>() takes exactly 1 argument (2 given)
Not surprising at all.

Functions implement the descriptor protocol[1]. When bound to a class
and looked up via an instance, it's the __get__ method of the function
object that get called - with the instance as param, as defined by the
descriptor protocol. This method then return the function wrapped - with
the instance - in an Method object - which itself, when called, returns
the result of calling the function *with the instance as first
parameter*. Which is how methods can work on the instance, and why one
has to explicitly declare the instance parameter in "functions to be
used as methods", but not explicitly pass it at call time.

(please some guru correct me if I missed something here, but AFAIK it
must be a correct enough description of method invocation mechanism in
Python).

[1] about descriptors, see:
http://docs.python.org/ref/descriptors.html
http://www.geocities.com/foetsch/pyt...tm#descriptors
So the first works and o1.x is actually 0.
int is not a function.
type(int) <type 'type'>

int is a type. A Python type is a callable object, and act as a factory
for instances of it. If the type doesn't implement the descriptor
protocol, when bound to a class and looked up via an instance, normal
lookup rules apply. So the type object is returned as is.
In your case, since int does'nt implement the descriptor protocol, once
looked up (and returned as is), it's called with a correct argument - so
everything runs fine.

Try this:

class Obj(object):
def __new__(cls, val, *args, **kw):
print "in Obj.__new__"
print "- called with :"
print " cls :", cls
print " val :", val
print " args: %s" % str(args)
print " kw : %s" % kw
obj = object.__new__(cls, *args, **kw)
print "got : %s - %s" % (obj, dir(obj))
return obj

def __init__(self, *args, **kw):
print "in Obj.__init__"
print "- called with :"
print " args: %s" % str(args)
print " kw : %s" % kw
class C4(C):
f = Obj
But the second fails because
self is also being passed as the first argument to the lambda.
Of course. It's a function, and it's bound to a class, and looked up via
an instance of the class.

Try this:

def truc(*args, **kw):
print "in truc()__"
print "- called with :"
print " args: %s" % str(args)
print " kw : %s" % kw
if len(args) > 1:
return args[1]

class C6(C):
f = truc

Defining
a "real" function doesn't help: the error is the same.
What' a "real" function ?-) lambdas *are* real functions. type(lambda x: x) <type 'function'>

My actual question is: why does it work in one case and not in the
other?
cf above.
As I see it, int is just a function with one parameter,
Nope, it's a type. Functions are just one kind of callable. Types are
callables too, as are any object overloading the call operator - which
is '()' - by implementing the __call__(self, ...) method.

class NotAFunc(object):
def __call__(self):
print "I'm not a function"
return 42

func = NotAFunc()
func()
and the
lambda is just another one.
True. And functions implement the descriptor protocol.
So why does the first work, and not the
second? What 'black magic' takes place so that int is not mistaken for
a method in the first case?


cf above.

If you understood all my explanations, you now know how to solve the
problem.

Else, here the solution:

class C3(C):
f = lambda self, x: return x
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 1 '06 #13
Eric Brunel a écrit :
On Thu, 01 Jun 2006 13:34:53 +0200, Peter Otten <__*******@web.de> wrote:
Eric Brunel wrote:
My actual question is: why does it work in one case and not in the
other?
As I see it, int is just a function with one parameter, and the
lambda is
just another one. So why does the first work, and not the second? What
'black magic' takes place so that int is not mistaken for a method
in the
first case?


A python-coded function has a __get__ attribute, a C-function doesn't.
Therefore C1.f performs just the normal attribute lookup while C2.f also
triggers the f.__get__(C2(), C2) call via the descriptor protocol which
happens to return a bound method.

Thanks for your explanations, Peter. I'll have to find another way to
do what I want...


You have 2 ways to do it already, here's a third :

class C:
f = None
def __init__(self):
if self.__class__.f is not None:
self.x = self.__class__.f(0)
else:
self.x = 0
Jun 1 '06 #14
Le Jeudi 01 Juin 2006 15:36, Christophe a écrit*:
* * * *self.x = self.__class__.f(0)

nope, this will result in a TypeError "unbound method must be called with
instance as first argument"
--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Jun 1 '06 #15
On Thu, 01 Jun 2006 15:07:26 +0200, bruno at modulix <on***@xiludom.gro>
wrote:
Do yourself a favour : use new-style classes.
class C(object)
I would if I could: I'm stuck with Python 2.1 for the moment (I should
have mentionned it; sorry for that).

[snip]
Basically, I want an optional variant function across sub-classes of
the same class.

I did it like in C1 for a start, then I needed
something like C2. The result is... surprising:

0
Traceback (most recent call last):
File "func-vs-meth.py", line 18, in ?
o2 = C2()
File "func-vs-meth.py", line 5, in __init__
self.x = self.f(0)
TypeError: <lambda>() takes exactly 1 argument (2 given)


Not surprising at all.

Functions implement the descriptor protocol[1]. When bound to a class
and looked up via an instance, it's the __get__ method of the function
object that get called - with the instance as param, as defined by the
descriptor protocol. This method then return the function wrapped - with
the instance - in an Method object - which itself, when called, returns
the result of calling the function *with the instance as first
parameter*. Which is how methods can work on the instance, and why one
has to explicitly declare the instance parameter in "functions to be
used as methods", but not explicitly pass it at call time.

(please some guru correct me if I missed something here, but AFAIK it
must be a correct enough description of method invocation mechanism in
Python).

[1] about descriptors, see:
http://docs.python.org/ref/descriptors.html
http://www.geocities.com/foetsch/pyt...tm#descriptors
So the first works and o1.x is actually 0.


int is not a function.
type(int) <type 'type'>

int is a type.


Python 2.1 again:
type(int)

<type 'builtin_function_or_method'>

But as someone mentionned, the problem is the same with other built-in
functions, such as chr, even in the latest Python version.

I still find that a little counter-intuitive to have different behaviours
for a built-in function and a Python function. I really would expect them
to work (or not to work) the same in all situations, even if I now
understand better how all works behind the scenes. But I'll live with it...

[snip] If you understood all my explanations, you now know how to solve the
problem.

Else, here the solution:

class C3(C):
f = lambda self, x: return x


This is actually the first thing I did, but it seemed a bit weird to me to
have a - let's say - callable with one parameter in one case and another
with two parameters in the other one. So I finally turned my callable
attribute into a real instance method, just for consistency.

Anyway, thanks a lot for your explanations.
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 1 '06 #16
Eric Brunel a écrit :
On Thu, 01 Jun 2006 15:07:26 +0200, bruno at modulix
<on***@xiludom.gro> wrote:
Do yourself a favour : use new-style classes.
class C(object)

I would if I could: I'm stuck with Python 2.1 for the moment (I should
have mentionned it; sorry for that).


Err, yes - it actually makes most of my explanations inaccurate.
[snip]


(snip too)
Jun 1 '06 #17
Maric Michaud a écrit :
Le Jeudi 01 Juin 2006 15:36, Christophe a écrit :
self.x = self.__class__.f(0)


nope, this will result in a TypeError "unbound method must be called with
instance as first argument"


Your right :(

staticmethod it is then.
Jun 2 '06 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: R.G. Vervoort | last post by:
I am using a javafunction (onclick in select) in which i am calling a function in php (thats why i send this to both php and javascript newsgroups). in the onclick i call the function...
9
by: Lenard Lindstrom | last post by:
I was wondering if anyone has suggested having Python determine a method's kind from its first parameter. 'self' is a de facto reserved word; 'cls' is a good indicator of a class method ( __new__...
13
by: Bern McCarty | last post by:
I have run an experiment to try to learn some things about floating point performance in managed C++. I am using Visual Studio 2003. I was hoping to get a feel for whether or not it would make...
6
by: Alexis Nikichine | last post by:
Hello, Today, I have a function: function f() { } and am looking for a way of distinguishing, from inside f, whether it
3
by: ragtopcaddy via AccessMonster.com | last post by:
I have a couple of questions regarding the use of the following function: Public Function dbLocal(Optional ysnInitialize As Boolean = True) As DAO. Database 1. Do I just replace all the...
7
by: alexander.stippler | last post by:
Hi I wonder if their will be a performance penalty in the following situation due to virtual function calls: class Interface { public: virtual void methodA() = 0; virtual void methodB() =...
29
by: Ravishankar S | last post by:
Dear C Experts, While prepating a content for a C course,I made section on function prototypes. Could you kindly provide me your comments on its correctness. Thank you ! Q12: What is the...
7
by: Andrew Poulos | last post by:
Say I have this foo = function() { // blah }; bar = fuction(fnName) { /* If fnName equalled "foo" * How do I test that foo, as a function, * exists and then, if it exists, call it?
53
by: souporpower | last post by:
Hello All I am trying to activate a link using Jquery. Here is my code; <html> <head> <script type="text/javascript" src="../../resources/js/ jquery-1.2.6.js"</script> <script...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.