adding methods at runtime and lambda

M

Mike

I was messing around with adding methods to a class instance at
runtime and saw the usual code one finds online for this. All the
examples I saw say, of course, to make sure that for your method that
you have 'self' as the first parameter. I got to thinking and thought
"I have a lot of arbitrary methods in several utility files that I
might like to add to things. How would I do that?" And this is what I
came up with:


def AddMethod(currObject, method, name = None):
if name is None: name = method.func_name
class newclass(currObject.__class__):pass
setattr(newclass, name, method)
return newclass()

And lets say I have a utility function that can check if a drive
exists on my windows box called HasDrive. I can add that like this:

superdict = addm(dict(), lambda self, d: myUtils.HasDrive(d),
"hasdrive")

and then I can call

superdict.HasDrive('c')

lambda makes it possible to add any random function because you can
use it to set self as the first parameter. I've found several real
uses for this already. My big question is, will something like this be
possible in python 3000 if lambda really does go away? I've not heard
much about lambda, reduce, etc. lately but I know Guido wanted them
out of the language.

Is there a better way to do this today than to use lambda? It seemed
the simplest way to do this that I could find.
 
M

Mike

In the above example 'addm' should be 'AddMethod'

superdict = AddMethod(dict(), lambda self, d:
myUtils.HasDrive(d),"hasdrive")
 
J

James Stroud

Mike said:
I was messing around with adding methods to a class instance at
runtime and saw the usual code one finds online for this. All the
examples I saw say, of course, to make sure that for your method that
you have 'self' as the first parameter. I got to thinking and thought
"I have a lot of arbitrary methods in several utility files that I
might like to add to things. How would I do that?" And this is what I
came up with:


def AddMethod(currObject, method, name = None):
if name is None: name = method.func_name
class newclass(currObject.__class__):pass
setattr(newclass, name, method)
return newclass()

And lets say I have a utility function that can check if a drive
exists on my windows box called HasDrive. I can add that like this:

superdict = addm(dict(), lambda self, d: myUtils.HasDrive(d),
"hasdrive")

and then I can call

superdict.HasDrive('c')

lambda makes it possible to add any random function because you can
use it to set self as the first parameter. I've found several real
uses for this already. My big question is, will something like this be
possible in python 3000 if lambda really does go away? I've not heard
much about lambda, reduce, etc. lately but I know Guido wanted them
out of the language.

Is there a better way to do this today than to use lambda? It seemed
the simplest way to do this that I could find.

You don't absolutely require lambda.

def add_self(afun):
def _f(self, *args, **kwargs):
return afun(*args, **kwargs)
return _f

superdict = addm(dict(), add_self(myUtils.HasDrive), "hasdrive")

James
 
I

ici

I was messing around with adding methods to a class instance at
runtime and saw the usual code one finds online for this. All the
examples I saw say, of course, to make sure that for your method that
you have 'self' as the first parameter. I got to thinking and thought
"I have a lot of arbitrary methods in several utility files that I
might like to add to things. How would I do that?" And this is what I
came up with:

def AddMethod(currObject, method, name = None):
if name is None: name = method.func_name
class newclass(currObject.__class__):pass
setattr(newclass, name, method)
return newclass()

And lets say I have a utility function that can check if a drive
exists on my windows box called HasDrive. I can add that like this:

superdict = addm(dict(), lambda self, d: myUtils.HasDrive(d),
"hasdrive")

and then I can call

superdict.HasDrive('c')

lambda makes it possible to add any random function because you can
use it to set self as the first parameter. I've found several real
uses for this already. My big question is, will something like this be
possible in python 3000 if lambda really does go away? I've not heard
much about lambda, reduce, etc. lately but I know Guido wanted them
out of the language.

Is there a better way to do this today than to use lambda? It seemed
the simplest way to do this that I could find.

from win32com.client import Dispatch as CreateObject

class HDDs(list):
def __init__(self):
fso = CreateObject('Scripting.FileSystemObject')
for d in fso.Drives:
if d.DriveType == 2: # Fixed
list.append(self, d.DriveLetter)

if __name__ == "__main__":
drv_list = HDDs()
for d in drv_list:
print d

try:
# Found
print drv_list.index('P')
except ValueError:
# Not Found
print "P: Not Exists!"
 
G

Gabriel Genellina

I was messing around with adding methods to a class instance at
runtime and saw the usual code one finds online for this. All the
examples I saw say, of course, to make sure that for your method that
you have 'self' as the first parameter. I got to thinking and thought
"I have a lot of arbitrary methods in several utility files that I
might like to add to things. How would I do that?" And this is what I
came up with:

I don't see the reason to do that. If you have a function that does not
use its "self" argument, what do you get from making it an instance method?
If -for whatever strange reason- you want it to actually be a method, use
a static method:

py> def foo(x):
.... print "I like %r" % x
....
py> class A(object): pass
....
py> a = A()
py> A.foo = staticmethod(foo)
py> a.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 argument (0 given)
py> a.foo("coffee")
I like 'coffee'
py> A.foo("tea")
I like 'tea'
 
M

Mike

I don't see the reason to do that. If you have a function that does not
use its "self" argument, what do you get from making it an instance method?
If -for whatever strange reason- you want it to actually be a method, use
a static method:

py> def foo(x):
... print "I like %r" % x
...
py> class A(object): pass
...
py> a = A()
py> A.foo = staticmethod(foo)
py> a.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 argument (0 given)
py> a.foo("coffee")
I like 'coffee'
py> A.foo("tea")
I like 'tea'

staticmethod makes the function available to the whole class according
to the docs. What if I only want it to be available on a particular
instance? Say I'm adding abilities to a character in a game and I want
to give a particular character the ability to 'NukeEverybody'. I don't
want all characters of that type to be able to wipe out the entire
planet, just the particular character that got the powerup.
 
P

Peter Otten

Mike said:
staticmethod makes the function available to the whole class according
to the docs. What if I only want it to be available on a particular
instance? Say I'm adding abilities to a character in a game and I want
to give a particular character the ability to 'NukeEverybody'. I don't
want all characters of that type to be able to wipe out the entire
planet, just the particular character that got the powerup.

Static methods are for specialists, you don't need them. But then, your
initial post looked like you were just exploring the possibilities...

You can

- have the Character.nuke_everybody() method check a self._can_nuke_eb flag
- subclass the Character class with a NukingChar subclass and make only one
instance of that class
- add an instancemethod to one Character instance

The simpler the approach you take the smarter you are ;)

Peter
 
M

Mike

Static methods are for specialists, you don't need them. But then, your
initial post looked like you were just exploring the possibilities...

Yeah, I'm just poking around.
You can

- have the Character.nuke_everybody() method check a self._can_nuke_eb flag

I don't like this one because it would require me to know every
ability everybody might ever have up front.
- subclass the Character class with a NukingChar subclass and make only one
instance of that class

A possibility, I guess, but does this then mean I would need a new
class for every type of character? Probably not, but you would at
least need types grouped by general class, kind of like D&D characters
(Fighter, Magic User, etc.). It makes it harder for anybody to learn
anything they want.
- add an instancemethod to one Character instance

The simpler the approach you take the smarter you are ;)

Peter

I just realized in working with this more that the issues I was having
with instancemethod and other things seems to be tied solely to
builtins like dict or object. I remember at some point just doing
something like:

x.fn = myfnFunction

and having it just work. If I do that with an instance of generic
object however, I get an AttributeError. So:

x = object()
x.fn = myFn

blows up. However, if I do

class nc(object):pass
x = nc()
x.fn = myFn

Then all is well.

checking for an ability on somebody is as simple as

'fn' in dir(x)

or

hasattr(x, 'fn')


I had thought this was a lot easier than I was making it out to be.
What I don't know is why using an object derived from object allows
you to dynamically add methods like this but the base object does not.
At this point it is more of a curiosity than anything, but if somebody
knows the answer off the top of their head, that would be great.

Thanks.
 
P

Peter Otten

Mike said:
I just realized in working with this more that the issues I was having
with instancemethod and other things seems to be tied solely to

What you describe below is a function that happens to be an attribute of an
instance. There are also "real" instance methods that know about "their"
instance:
.... def __init__(self, name):
.... self.name = name
........ print self.name
....Traceback (most recent call last):
builtins like dict or object. I remember at some point just doing
something like:

x.fn = myfnFunction

and having it just work.

With the caveat that x.fn is now an alias for myfnFunction, but doesn't get
x passed as its first argument (conventionally named 'self') and therefore
has no knowledge of the instance x.
If I do that with an instance of generic
object however, I get an AttributeError. So:

x = object()
x.fn = myFn

blows up. However, if I do

class nc(object):pass
x = nc()
x.fn = myFn

Then all is well.

checking for an ability on somebody is as simple as

'fn' in dir(x)

or

hasattr(x, 'fn')


I had thought this was a lot easier than I was making it out to be.
What I don't know is why using an object derived from object allows
you to dynamically add methods like this but the base object does not.
At this point it is more of a curiosity than anything, but if somebody
knows the answer off the top of their head, that would be great.

Arbitrary instance attributes are implemented via a dictionary (called
__dict__), and that incurs a certain overhead which is sometimes better to
avoid (think gazillion instances of some tiny class). For example, tuples
are derived from object but don't have a __dict__.
As a special case, what would happen if dict were to allow attributes? It
would need a __dict__ which would have a __dict__ which would have...
As a consequence object could no longer be the base class of all (newstyle)
classes.

Peter
 
M

Mike

What you describe below is a function that happens to be an attribute of an
instance. There are also "real" instance methods that know about "their"
instance:


... def __init__(self, name):
... self.name = name
...>>> def method(self): # a function...

... print self.name
...>>> a = A("alpha")

Traceback (most recent call last):




With the caveat that x.fn is now an alias for myfnFunction, but doesn't get
x passed as its first argument (conventionally named 'self') and therefore
has no knowledge of the instance x.











Arbitrary instance attributes are implemented via a dictionary (called
__dict__), and that incurs a certain overhead which is sometimes better to
avoid (think gazillion instances of some tiny class). For example, tuples
are derived from object but don't have a __dict__.
As a special case, what would happen if dict were to allow attributes? It
would need a __dict__ which would have a __dict__ which would have...
As a consequence object could no longer be the base class of all (newstyle)
classes.

Peter

Thanks.
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top