Is there an official way to add methods to an instance?

  • Thread starter Brian Vanderburg II
  • Start date
B

Brian Vanderburg II

I don't know if this is the correct place to send this question.

I've checked out some ways to get this to work. I want to be able to
add a new function to an instance of an object. I've tested two
different methods that cause problems with 'deleting'/garbage collection
(__del__ may never get called), but implemented one sort of hackishly
maybe that works find. I'm wondering if there is more of an official way
than mine.

1.
import new
import gc

class A:
def __del__(x):
print "Deleting"

def f(x):
print x

a = A()
a.f = new.instancemethod(a,f)
a.f() # This works
del a # Not what is expected
gc.collect() # Works, but __del__ does not get called

2.
import gc

def addmethod(self,func,name):
def wrapper(*args,**kwargs):
return func(self,*args,**kwargs)
setattr(self,name,func)

class A:
def __del__(x):
print "Deleting"

def f(x):
print x

a = A()
addmethod(a, f, "f")
a.f() # Works as expected
del a # nope
gc.collect() # Still __del__ doesn't get called

3. Slightly hackish method, maybe some problems
import gc
import weakref

def addmethod(self,func,name):
# change the value of 'self' so wrapper.func_globals will reference
the new value
self = weakref.ref(self)
def wrapper(*args,**kwargs):
return func(self(),*args,**kwargs)
setattr(self(),name,func)

class A:
def __del__(x):
print "Deleting"

def f(x):
print x

a = A()
addmethod(a, f, "f")
a.f() # Works as expected
del a
gc.collect()

With this method 'del a' does the expected most of the time, and
"Deleting" does get printed or when calling 'gc.collect()' it prints
correctly. This seems the best approach so that when 'a' is no longer
valid, the object can die instead of continuing to exitng because
wrapper.func_globals still contains a reference, but seems very hackish
an maybe problematic. I'm wondering if there is a better way?

Brian Vanderburg II
 
R

Roger Miller

I've checked out some ways to get this to work. I want to be able to
add a new function to an instance of an object. I've tested two
different methods that cause problems with 'deleting'/garbage collection
(__del__ may never get called), but implemented one sort of hackishly
maybe that works find. I'm wondering if there is more of an official way
than mine.

Maybe I'm missing something, but the boring old straightforward
approach works for me:

class A:
def __del__(self):
print "Deleting"

def f(x):
print x

a = A()
a.f = f
a.f(42)
del a

Output:
42
Deleting
 
G

Gabriel Genellina

En Thu, 03 Apr 2008 22:43:30 -0300, Roger Miller
Maybe I'm missing something, but the boring old straightforward
approach works for me:

class A:
def __del__(self):
print "Deleting"

def f(x):
print x

a = A()
a.f = f
a.f(42)
del a

This doesn't create an instance method. You can't access `a` (as `self`)
from inside f.
 
P

Peter Otten

Brian said:
I don't know if this is the correct place to send this question.

It is.
I've checked out some ways to get this to work. I want to be able to
add a new function to an instance of an object. I've tested two
different methods that cause problems with 'deleting'/garbage collection
(__del__ may never get called), but implemented one sort of hackishly
maybe that works find. I'm wondering if there is more of an official way
than mine.

[snip]

I think "Try hard to avoid __del__()" is as close to an official stance as
you can get ;)

Anyway, here is one more option to add too the zoo:
.... def __init__(self, f, x):
.... self._f = f
.... self.x = x
.... @property
.... def f(self):
.... return self._f.__get__(self)
.... def __del__(self):
.... print "deleting"
....deleting

Peter
 
B

Bruno Desthuilliers

Peter Otten a écrit :
(snip)
Anyway, here is one more option to add too the zoo:

... def __init__(self, f, x):
... self._f = f
... self.x = x
... @property
... def f(self):
... return self._f.__get__(self)
... def __del__(self):
... print "deleting"
...

This is nice but requires that you know in advance how many methods
you're going to add and how they will be named (which is not a bad thing
in itself - on the contrary - but may not be what the OP is after), and
that you can add these methods at instanciation time.

A variant could be:

class A(object):
def __init__(self, x):
self.x = x

def __getattr__(self, name):
target = '_' + name
# avoids recursion
if hasattr(self, target):
func = getattr(self, target)
if hasattr(func, '__get__'):
return func.__get__(self, type(self))

# nothing found, bye...
raise AttributeError(
"%s object has no attribute %s" % (self, name)
)


a = A(21)
a._foo = lambda self: "answer is %s" % (self.x * 2)
print a.foo()
 
J

John Nagle

Bruno said:
Paul Rubin a écrit :

Why so ? OO is about objects, not classes, and adding methods on a
per-object basis is perfectly legitimate.

It's what professional programmers call a "l33t feature",
one not suitable for production code. Typically such features
are used by programmers with about two years experience,
trying too hard to prove that they're cool.

John Nagle
 
M

méchoui

It's what professional programmers call a "l33t feature",
one not suitable for production code. Typically such features
are used by programmers with about two years experience,
trying too hard to prove that they're cool.

John Nagle

Yes, and the reason is quite obvious: if you read the code of the
class, you can't see the function. That makes it much more difficult
to understand and to debug.
 
B

bruno.desthuilliers

@john:

I've ten years of experience, definitively don't care about looking
"cool" or "l33t", and sorry, but I won't buy your purely ideological
arguments. This reminds me of the lead engineer in one of my first job
forbidding using OO because he didn't get it, or some Java guy trying
to convince me that a language with dynamic typing and no access
restriction could not be used for "production code".
Yes, and the reason is quite obvious: if you read the code of the
class, you can't see the function. That makes it much more difficult
to understand and to debug.

Then we should forbid inheritence - you don't see the inherited
functions when reading the code of the class. And we should forbid
monkey-patching, metaclasses and quite a lot of other things as well.
And also, we should go back to static typing - with dynamic typing,
you don't know by reading the signature of a function what kind of
arguments it expects.

C'mon, be serious guys. As everything else, the problem is not with
the feature, but with knowing how to properly use it and how to not
abuse it. If you don't trust the programmer, then don't use a dynamic
language. You know where to find Java and Ada...
 

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,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top