Adding method to a class on the fly
Steven D'Aprano
steve at REMOVE.THIS.cybersource.com.au
Fri Jun 22 22:36:40 EDT 2007
On Fri, 22 Jun 2007 14:44:54 -0700, John Henry wrote:
> The above doesn't exactly do I what need. I was looking for a way to
> add method to a class at run time.
>
> What does work, is to define an entire sub-class at run time. Like:
>
> class DummyParent:
> def __init__(self):
> return
>
> def method_static(self, text):
> print text
> return
>
> text = "class Dummy(DummyParent):"
> text += "\n\t" + "def __init(self):"
> text += "\n\t" + "\tDummyParent.__init__(self)"
> text += "\n\t" + "def method_dynamic(self):"
> text += "\n\t" + "\tself.method_static(\"it's me\")"
>
> exec text
(By the way, you misspelled __init__.)
The correct way to add methods to an instance is with the
instancemethod() function.
class Parrot:
def __init__(self):
import new
# define a function
def method_dynamic(self, *args):
args.insert(0, "hello, it's me!")
return self.method_static(*args)
# convert it into an instance method
method = new.instancemethod(function, self, self.__class__)
# add it to self
self.method_dynamic = method
def method_static(self, text):
return text
And here is how I use it:
>>> p = Parrot()
>>> p.method_dynamic() # call from an instance
"it's me"
>>> Parrot.method_dynamic # does it exist in the class?
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: class Parrot has no attribute 'method_dynamic'
BUT, having said all that, are you sure this is what you want to do? This
is probably a better way to get the same results:
class Parrot:
def __init__(self):
self.text = "hello, it's me!"
def method_dynamic(self):
return self.method_static(self.text)
def method_static(self, text):
return text
Earlier in the thread, you said you wanted a CLASS method, which is very
different. You can use the classmethod built-in function (no need to
import new) to create class methods:
class Parrot:
def method_dynamic(cls):
return cls.method_static(cls(), "hello it's me")
# or alternatively cls().method_static("hello it's me")
method_dynamic = classmethod(method_dynamic)
def method_static(self, text):
return text
Note: if you are using recent versions of Python, instead of saying
"method = classmethod(method)" AFTER the block, you can use a decorator
before the block.
Making method_dynamic a class method and calling an instance method is not
a good way of doing things, since the class method has to create a new
instance before calling method_static, only to throw it away afterwards.
That is wasteful and could be very expensive.
A better way is to change your class so that method_static is a class
method too, especially since it doesn't use self:
class Parrot:
@classmethod
def method_dynamic(cls):
return cls.method_static("hello it's me")
@classmethod
def method_static(cls, text):
return text
(Actually, since method_static doesn't even use the class, you could use
staticmethod instead of classmethod. Remember to remove the "cls" argument.)
Hope this helps,
--
Steven.
More information about the Python-list
mailing list