Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Passing a function as an argument from within the same class?

Reply
Thread Tools

Passing a function as an argument from within the same class?

 
 
zealalot
Guest
Posts: n/a
 
      05-01-2009
So, I'm trying to come up with a way to pass a method (from the same
class) as the default argument for another method in the same class.
Unfortunately though, I keep getting "self not defined" errors since
the class hasn't been read completely before it references itself.

Is there a better way of doing this?

--- CODE ---

class SomeClass():
def doNothing(self):
pass
def function1(self):
print "Running function 1."
def function2(self, passedFunction=self.doNothing):
print "Running passed function."
passedFunction()

someObject = SomeClass()
someObject.function2(someobject.function1)

--- CODE ---

Thanks,
- Zealalot
 
Reply With Quote
 
 
 
 
bearophileHUGS@lycos.com
Guest
Posts: n/a
 
      05-01-2009
Zealalot, probably there are some ways to do that, but a simple one is
the following (not tested):

def function2(self, passed_function=None):
if passed_function is None:
passed_function = self.doNothing
...

Bye,
bearophile
 
Reply With Quote
 
 
 
 
CTO
Guest
Posts: n/a
 
      05-01-2009
Make doNothing a classmethod.

class SomeClass:

@classmethod
def doNothing(cls):
pass

def function1(self):
print "Running function 1"

def function2(self, passedFunction=SomeClass.doNothing):
print "Running passed function"
passedFunction()

someObject = SomeClass()
someObject.function2()
someObject.function2(someObject.function1)


 
Reply With Quote
 
zealalot
Guest
Posts: n/a
 
      05-01-2009
On May 1, 10:50*am, CTO <debat...@gmail.com> wrote:
> Make doNothing a classmethod.
>
> class SomeClass:
>
> * * @classmethod
> * * def doNothing(cls):
> * * * * pass
>
> * * def function1(self):
> * * * * print "Running function 1"
>
> * * def function2(self, passedFunction=SomeClass.doNothing):
> * * * * print "Running passed function"
> * * * * passedFunction()
>
> someObject = SomeClass()
> someObject.function2()
> someObject.function2(someObject.function1)


It's not surprising, but I've never heard of a classmethod before.
Basically, I read that it basically removes the need for the 'self'
argument. Very cool!

And thanks for the quick response,

- Zealalot
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      05-01-2009
CTO wrote:

> Make doNothing a classmethod.
>
> class SomeClass:
>
> @classmethod
> def doNothing(cls):
> pass
>
> def function1(self):
> print "Running function 1"
>
> def function2(self, passedFunction=SomeClass.doNothing):
> print "Running passed function"
> passedFunction()
>
> someObject = SomeClass()
> someObject.function2()
> someObject.function2(someObject.function1)


To make that run without error you have to jump through a lot of hoops:

class SomeClass(object):
@classmethod
def doNothing(cls):
pass
def function1(self):
print "Running function 1"

def function2(self, passedFunction=SomeClass.doNothing):
print "Running passed function"
passedFunction()

SomeClass.function2 = function2

someObject = SomeClass()
someObject.function2()
someObject.function2(someObject.function1)

And if you don't need access to the instance you may not need access to the
class either. In this case you can simplify:

def doNothing():
pass

class SomeClass(object):
def function1(self):
print "Running function 1"
def function2(self, passedFunction=doNothing):
print "Running passed function"
passedFunction()

If you do need information about the state of the instance you can either
pass it explicitly

class SomeClass(object):
def doNothing(self):
pass
def function1(self):
print "Running function 1"
def function2(self, passedFunction=doNothing):
print "Running passed function"
passedFunction.__get__(self)()

or (better, I think) use a sentinel as shown by Bearophile.

Peter

 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      05-01-2009
On Fri, 01 May 2009 08:11:01 -0700, zealalot wrote:

> On May 1, 10:50Â*am, CTO <debat...@gmail.com> wrote:
>> Make doNothing a classmethod.
>>
>> class SomeClass:
>>
>> Â* Â* @classmethod
>> Â* Â* def doNothing(cls):
>> Â* Â* Â* Â* pass
>>
>> Â* Â* def function1(self):
>> Â* Â* Â* Â* print "Running function 1"
>>
>> Â* Â* def function2(self, passedFunction=SomeClass.doNothing):
>> Â* Â* Â* Â* print "Running passed function"
>> Â* Â* Â* Â* passedFunction()
>>
>> someObject = SomeClass()
>> someObject.function2()
>> someObject.function2(someObject.function1)

>
> It's not surprising, but I've never heard of a classmethod before.
> Basically, I read that it basically removes the need for the 'self'
> argument. Very cool!


Not so.

When you call an ordinary method (an "instance method"), Python
automatically inserts the object itself as the first argument. So you
need to define the method with one extra parameter, self.

(Using the name self is just a convention. You can call it anything you
like.)

For classmethods, Python automatically inserts not the object itself, but
the object's *class* as the first argument. So you still need to define
the method with an extra parameter, only now the convention is to call is
cls rather than self.

Here's an example:

class Test(object):
x = 0 # class attribute
def __init__(self, x):
self.x = x # instance attribute
def spam(self):
print self, self.x
@classmethod
def ham(cls):
print cls, cls.x


And in use:

>>> t = Test(42)
>>> t.spam()

<__main__.Test object at 0xb7cccc6c> 42
>>> t.ham()

<class '__main__.Test'> 0


There is one other related built-in decorator, staticmethod().
staticmethod() tells Python not to pass any extra argument to the method.
That means the inside a static method, you can't refer to either the
instance (self) or the class! Needless to say, there aren't very many
uses for staticmethod().



--
Steven
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      05-01-2009
On Fri, 01 May 2009 07:35:40 -0700, zealalot wrote:

> So, I'm trying to come up with a way to pass a method (from the same
> class) as the default argument for another method in the same class.
> Unfortunately though, I keep getting "self not defined" errors since the
> class hasn't been read completely before it references itself.
>
> Is there a better way of doing this?


My first instinct is to say "Don't do that!", but let's see if there's a
way to get what you want. It's actually very easy: just put the
definition of the passed method before the method you want to use it in,
then refer to it by name *without* self.

However, there is a catch: you need to manually pass in the instance,
instead of letting Python do it for you.

class Spam(object):
def ham(self):
return "ham"
def spam(self, func=ham):
return "spam is a tasty %s-like food product" % func(self)


And in use:

>>> obj = Spam()
>>> obj.ham()

'ham'
>>> obj.spam()

'spam is a tasty ham-like food product'



--
Steven
 
Reply With Quote
 
CTO
Guest
Posts: n/a
 
      05-01-2009
> Careful, bearophiles' answer remains the best one.
>
> The only reason your example worked is that you had already had
> SomeClass defined (probably from a previous experiment).


Scott is correct, and if bearophile and I ever give you conflicting
advice, take bearophile's.

A (corrected) bit of code that might serve your purpose would be
as follows:

class SomeClass:

def doNothing():
pass

def function1(self):
print "running function 1"

def function2(self, passedFunction=doNothing):
print "running passed function"
passedFunction()

again, though- bearophile's is the best, and most standard,
answer here
 
Reply With Quote
 
Dave Angel
Guest
Posts: n/a
 
      05-01-2009
zealalot wrote:
> On May 1, 10:50 am, CTO <debat...@gmail.com> wrote:
>
>> Make doNothing a classmethod.
>>
>> class SomeClass:
>>
>> @classmethod
>> def doNothing(cls):
>> pass
>>
>> def function1(self):
>> print "Running function 1"
>>
>> def function2(self, passedFunction=meClass.doNothing):
>> print "Running passed function"
>> passedFunction()
>>
>> someObject =omeClass()
>> someObject.function2()
>> someObject.function2(someObject.function1)
>>

>
> It's not surprising, but I've never heard of a classmethod before.
> Basically, I read that it basically removes the need for the 'self'
> argument. Very cool!
>
> And thanks for the quick response,
>
> - Zealalot
>
>

As you've probably figured out by now, that also gets an error, since
you can't refer to the SomeClass until the definition is complete.
Better is either the sentinel approach, or defining the function outside
the class. Note that since the signature must match the passed
function, you presumably need neither a self nor a cls. So keep it
simple and define doNothing as a top-level function.

But it's worth expanding on the notion of a classmethod. This type of
function is callable with any object, or just with the class name
itself. But it doesn't have an access to instance attributes. That's
good, but not very common. Class attributes are more common, and
they're attributes which are shared among all the objects of the class.


 
Reply With Quote
 
Terry Reedy
Guest
Posts: n/a
 
      05-01-2009
zealalot wrote:
> So, I'm trying to come up with a way to pass a method (from the same
> class) as the default argument for another method in the same class.
> Unfortunately though, I keep getting "self not defined" errors since
> the class hasn't been read completely before it references itself.
>
> Is there a better way of doing this?
>
> --- CODE ---
>
> class SomeClass():
> def doNothing(self):
> pass
> def function1(self):
> print "Running function 1."
> def function2(self, passedFunction=self.doNothing):
> print "Running passed function."
> passedFunction()
>
> someObject = SomeClass()
> someObject.function2(someobject.function1)


As Stephen D'Aprano indicated, this is very easy

class SomeClass():
def doNothing(self):
print("Doing nothing")
def function1(self):
print ("Running function 1.")
def function2(self, passedFunction=doNothing):
print ("Running passed function.")
passedFunction(self)

someObject = SomeClass()
someObject.function2()
someObject.function2(SomeClass.function1)

produces (with 3.0.1)

Running passed function.
Doing nothing
Running passed function.
Running function 1.

Key 1: a class statement introduces a new local namespace. The body of
the class statement is executed in that namespace. Default arguments
are evaluated, when a def statement is executed, in the local namespace
of that def statement. For methods, that is the local namespace of the
class. Hence, 'passedFunction = doNothing' works fine.

Key 2: When a parameter is a function, the signature of the default and
passed args are effectively part of the required type for the args. In
this case, passedFunction is a function with one parameter. When
captured, doNothing is not yet a method of the yet-to-become Someclass.
So non-defaults passed to .function2 do not have to be methods either.
In Python 3, unbound methods are simply functions anyway.

Terry Jan Reedy

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Variable argument function as a parameter of a variable argument function AikidoGuy C Programming 11 11-21-2011 10:43 PM
function argument dependent on another function argument? Reckoner Python 11 01-19-2009 03:31 AM
How to use a passing argument(returned argument)? ±è ÁØ¿µ Ruby 7 11-27-2008 03:53 AM
Passing a function as an argument and using the evaluated functionas an argument User1014 Javascript 1 11-30-2006 12:13 PM
Argument-per-argument Passing Trans Ruby 3 01-26-2005 05:58 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57