473,401 Members | 2,139 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,401 software developers and data experts.

Adding method to a class on the fly

Hi list,

I have a need to create class methods on the fly. For example, if I
do:

class Dummy:
def __init__(self):
exec '''def method_dynamic(self):\n\treturn
self.method_static("it's me")'''
return

def method_static(self, text):
print text
return

I like that to be the same as:

class Dummy:
def __init__(self):
return

def method_dynamic(self):
return self.method_static("it's me")

def method_static(self, text):
print text
return

so that I can do:

dum=Dummy.method_dynamic()

and see "it's me" printed.

Can that be done?

Thanks,

Jun 22 '07 #1
21 2320
Found a message on the web that says I need to use setattr to add the
method to the class at run time. But how do I do that?

Regards,

On Jun 22, 12:02 pm, John Henry <john106he...@hotmail.comwrote:
Hi list,

I have a need to create class methods on the fly. For example, if I
do:

class Dummy:
def __init__(self):
exec '''def method_dynamic(self):\n\treturn
self.method_static("it's me")'''
return

def method_static(self, text):
print text
return

I like that to be the same as:

class Dummy:
def __init__(self):
return

def method_dynamic(self):
return self.method_static("it's me")

def method_static(self, text):
print text
return

so that I can do:

dum=Dummy.method_dynamic()

and see "it's me" printed.

Can that be done?

Thanks,

Jun 22 '07 #2
On Jun 22, 3:02 pm, John Henry <john106he...@hotmail.comwrote:
Hi list,

I have a need to create class methods on the fly. For example, if I
do:

class Dummy:
def __init__(self):
exec '''def method_dynamic(self):\n\treturn
self.method_static("it's me")'''
return

def method_static(self, text):
print text
return

I like that to be the same as:

class Dummy:
def __init__(self):
return

def method_dynamic(self):
return self.method_static("it's me")

def method_static(self, text):
print text
return

so that I can do:

dum=Dummy.method_dynamic()

and see "it's me" printed.

Can that be done?

Thanks,
class Dummy:
def method(self, arg):
print arg

def method2(self, arg):
self.method(arg)

Dummy.method2 = method2
Dummy.method2('Hello, world!')

Jun 22 '07 #3
On Jun 22, 2:24 pm, askel <dummy...@mail.ruwrote:
class Dummy:
def method(self, arg):
print arg

def method2(self, arg):
self.method(arg)

Dummy.method2 = method2
Dummy.method2('Hello, world!')
Traceback (most recent call last):
File "test1.py", line 8, in ?
Dummy.method2('Hello, world!')
TypeError: unbound method method2() must be called with Dummy instance
as first argument (got str instance
instead)
>I like that to be the same as:

class Dummy:
def __init__(self):
return

def method_dynamic(self):
return self.method_static("it's me")

def method_static(self, text):
print text
return
so that I can do:

dum=Dummy.method_dynamic()

and see "it's me" printed.
When are you able to see that?

Jun 22 '07 #4
On Jun 22, 5:17 pm, 7stud <bbxx789_0...@yahoo.comwrote:
On Jun 22, 2:24 pm, askel <dummy...@mail.ruwrote:
class Dummy:
def method(self, arg):
print arg
def method2(self, arg):
self.method(arg)
Dummy.method2 = method2
Dummy.method2('Hello, world!')

Traceback (most recent call last):
File "test1.py", line 8, in ?
Dummy.method2('Hello, world!')
TypeError: unbound method method2() must be called with Dummy instance
as first argument (got str instance
instead)
I like that to be the same as:
class Dummy:
def __init__(self):
return
def method_dynamic(self):
return self.method_static("it's me")
def method_static(self, text):
print text
return
so that I can do:
dum=Dummy.method_dynamic()
and see "it's me" printed.

When are you able to see that?
sorry, of course last line should be:
Dummy().method2('Hello, world!')

Jun 22 '07 #5
On Jun 22, 3:23 pm, askel <dummy...@mail.ruwrote:
sorry, of course last line should be:
Dummy().method2('Hello, world!')
...which doesn't meet the op's requirements.

Jun 22 '07 #6
On Jun 22, 5:17 pm, 7stud <bbxx789_0...@yahoo.comwrote:
On Jun 22, 2:24 pm, askel <dummy...@mail.ruwrote:
class Dummy:
def method(self, arg):
print arg
def method2(self, arg):
self.method(arg)
Dummy.method2 = method2
Dummy.method2('Hello, world!')

Traceback (most recent call last):
File "test1.py", line 8, in ?
Dummy.method2('Hello, world!')
TypeError: unbound method method2() must be called with Dummy instance
as first argument (got str instance
instead)
I like that to be the same as:
class Dummy:
def __init__(self):
return
def method_dynamic(self):
return self.method_static("it's me")
def method_static(self, text):
print text
return
so that I can do:
dum=Dummy.method_dynamic()
and see "it's me" printed.

When are you able to see that?
there is no way to call instance method from static one. but in your
case you can make something like:

class Dummy:
@staticmethod
def method(arg):
print arg

def method2(arg):
Dummy.method(arg)

Dummy.method2 = staticmethod(method2)
Dummy.method2('Hello, world!')

- OR -

def method2(cls, arg):
cls.method(arg)

Dummy.method2 = classmethod(method2)
Dummy.method2('Hello, world!')

Jun 22 '07 #7
On Jun 22, 2:28 pm, askel <dummy...@mail.ruwrote:
On Jun 22, 5:17 pm, 7stud <bbxx789_0...@yahoo.comwrote:
On Jun 22, 2:24 pm, askel <dummy...@mail.ruwrote:
class Dummy:
def method(self, arg):
print arg
def method2(self, arg):
self.method(arg)
Dummy.method2 = method2
Dummy.method2('Hello, world!')
Traceback (most recent call last):
File "test1.py", line 8, in ?
Dummy.method2('Hello, world!')
TypeError: unbound method method2() must be called with Dummy instance
as first argument (got str instance
instead)
>I like that to be the same as:
>class Dummy:
def __init__(self):
return
def method_dynamic(self):
return self.method_static("it's me")
def method_static(self, text):
print text
return
>so that I can do:
>dum=Dummy.method_dynamic()
>and see "it's me" printed.
When are you able to see that?

there is no way to call instance method from static one. but in your
case you can make something like:

class Dummy:
@staticmethod
def method(arg):
print arg

def method2(arg):
Dummy.method(arg)

Dummy.method2 = staticmethod(method2)
Dummy.method2('Hello, world!')

- OR -

def method2(cls, arg):
cls.method(arg)

Dummy.method2 = classmethod(method2)
Dummy.method2('Hello, world!')


Thanks for the response.

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

dum=Dummy().method_dynamic()
Thanks again.

Jun 22 '07 #8
On Jun 22, 2:44 pm, John Henry <john106he...@hotmail.comwrote:
On Jun 22, 2:28 pm, askel <dummy...@mail.ruwrote:
(snipped)
>
The above doesn't exactly do I what need. I was looking for a way to
add method to a class at run time.

I'm not sure what you mean by this. Bind an attribute -- a method --
to class Dummy if and only if an instance of this class is created?
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

dum=Dummy().method_dynamic()

Thanks again.

I tend to avoid exec if possible. Also, you
seem to be a bit inexact with regard to the
term "static".
class Dummy(object):
def __init__(self):
new_method_name = 'method_dynamic'
try:
getattr(Dummy, new_method_name)
except AttributeError:
print "Creating an instance method..."
def newf(self):
"""Something Descriptive Here"""
return self.method_static("it's me")
newf.__name__ = new_method_name
setattr(Dummy, new_method_name, newf)
def method_static(self, text):
"""I hate this name. Do not confuse this with a staticmethod;
what you probably meant was that this is an attribute (a
method)
bound within the class body as opposed to elsewhere"""
print text
return # is this necessary?

d1 = Dummy()
d1.method_dynamic()
d2 = Dummy()
d2.method_dynamic()
print d1.method_dynamic.im_func.__name__
print d1.method_dynamic.im_func.__dict__
print d1.method_dynamic.im_func.__doc__
print d1.method_dynamic.im_func.__module__
print d1.method_dynamic.im_self

--
Hope this helps,
Steven

Jun 22 '07 #9
7stud wrote:
On Jun 22, 3:23 pm, askel <dummy...@mail.ruwrote:
>>sorry, of course last line should be:
Dummy().method2('Hello, world!')


..which doesn't meet the op's requirements.
Which were contradictory.
Jun 23 '07 #10
John Henry wrote:
Hi list,

I have a need to create class methods on the fly. For example, if I
do:

class Dummy:
def __init__(self):
exec '''def method_dynamic(self):\n\treturn
self.method_static("it's me")'''
return

def method_static(self, text):
print text
return
Where is the text for the exec statement coming from? A file? User
input? What you are doing above makes absolutely no sense. You confuse
everyone who attempts to understand what you want to do with the above
because no one in his right mind would do anything like it.
I like that to be the same as:

class Dummy:
def __init__(self):
return

def method_dynamic(self):
return self.method_static("it's me")

def method_static(self, text):
print text
return
Are you looking to fill in text and create new methods for Dummy based
on the text and method_static() such that these will become true
instance methods for instances of Dummy?

def add_dynamic(cls_name, f, name, *args, **kwargs):
cls = globals()[cls_name]
def _f(self):
return getattr(cls, f)(self, *args, **kwargs)
setattr(cls, name, _f)

e.g.

pyclass Dummy:
.... def method_static(self, text):
.... print text
.... return
....
pydef add_dynamic(cls_name, f, name, *args, **kwargs):
.... cls = globals()[cls_name]
.... def _f(self):
.... return getattr(cls, f)(self, *args, **kwargs)
.... setattr(cls, name, _f)
....
pyadd_dynamic('Dummy', 'method_static', 'method_dynamic', 'abc xyz')
pyDummy.method_dynamic
<unbound method Dummy._f>
pyd = Dummy()
pyd.method_dynamic()
abc xyz

Note that this is "completely dynamic" in that all arguments to
add_dynamic() are strings. This may or may not be what you want--in such
a case, you will want to study the code to see how it works and fix it
yourself. Note also that methods added to classes after instances are
made will be available to said instances:
pyadd_dynamic('Dummy', 'method_static', 'method2_dynamic', 'asdf jkl')
pyd.method2_dynamic()
asdf jkl

so that I can do:

dum=Dummy.method_dynamic()
Here you confuse everyone. This last line is not the same as you
describe in the above example. Here you imply the dynamic creation of a
"static method" (not a "method_static"--don't be confused by the names
you invent as they may already have a meaning to everyone else). Static
methods are different from unbound class methods that are later bound to
instances of a class upon instantiation.

Here is an analagous solution for static methods:
def add_static(cls_name, f, name, *args, **kwargs):
cls = globals()[cls_name]
def _f():
return getattr(cls, f)(*args, **kwargs)
setattr(cls, name, staticmethod(_f))

class Dummy:
@staticmethod
def method_static(text):
print text
e.g.:
pydef add_static(cls_name, f, name, *args, **kwargs):
.... cls = globals()[cls_name]
.... def _f():
.... return getattr(cls, f)(*args, **kwargs)
.... setattr(cls, name, staticmethod(_f))
....
pyclass Dummy:
.... @staticmethod
.... def method_static(text):
.... print text
....
pyadd_static('Dummy', 'method_static', 'real_static', 'aaa bbb')
pyDummy.real_static
<function _f at 0x406bf684>
pyDummy.real_static()
aaa bbb

Again, this will do what you want, but if it doesn't do *exactly* what
you want, you need to study and modify the code. Also, creating static
methods from unbound methods requires trickery. If this is what you
want, you should be very clear about it.

and see "it's me" printed.

Can that be done?

Yes. Anything is possible with python. That's why I use it.
James
Jun 23 '07 #11
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.

Jun 23 '07 #12
On Jun 22, 7:36 pm, Steven D'Aprano
<s...@REMOVE.THIS.cybersource.com.auwrote:
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.

Thanks everybody for your responses. I know my terminology isn't
quite exact. Hopefully that didn't confuse you too much. I used that
example hoping to simplify the question. As you'll see below, it
takes more if I have to explain the entire story.

Of all the answers, I think the new.instancemethod is most
appropriate. I'll try to explain:

With a PythonCard application, if you want to have a button, normally
you use the layout editor which creates a dictionary representing the
button, and you would have a function for each of the events it has to
handle. For instance, a simple one button ap might look like this:

#!/usr/bin/python

"""
__version__ = "$Revision: 1.6 $"
__date__ = "$Date: 2004/08/17 19:46:06 $"
"""

from PythonCard import model

rsrc = {'application':{'type':'Application',
'name':'Minimal',
'backgrounds': [
{'type':'Background',
'name':'bgMin',
'title':'Minimal PythonCard Application',
'size':(200, 100),
'components': [
{'type':'Button', 'name':'Button1', 'position':(5, 35),
'label':'Button1'},
] # end components
} # end background
] # end backgrounds
} }

class Minimal(model.Background):

def on_initialize(self, event):
pass
def on_Button1_mouseClick(self, event):
print "Clicked Button1"
if __name__ == '__main__':
app = model.Application(Minimal, None, rsrc)
app.MainLoop()
Notice that the event handler for mouseClick to Button1 is done via
the function on_Button1_mouseClick. This is very simple and works
great - until you try to create the button on the fly.

Creating the button itself is no problem. You simply do a:

self.components['Button1'] = {'type':'Button',
'name':'Button1',
'position':(5, 35),
'label':'Button1'}

But then how do I create the on_Button1_mouseClick function? With the
application I have to come up with, I have a tree on the left, and
then depending which branch the user clicks, I have to create various
controls on the right. So, it becomes some what of a nightmare for me
(since I have lots of branches and they are all quite different).
Each time the use click a branch, I have to create the buttons, data
entry-fields, and so forth on the fly - along with all of the
functions to handle them.

This is what I came up with so far (before reading your messages):

#!/usr/bin/python

"""
__version__ = "$Revision: 1.6 $"
__date__ = "$Date: 2004/08/17 19:46:06 $"
"""

from PythonCard import model

rsrc = {'application':{'type':'Application',
'name':'Minimal',
'backgrounds': [
{'type':'Background',
'name':'bgMin',
'title':'Minimal PythonCard Application',
'size':(200, 300),
'components': [

] # end components
} # end background
] # end backgrounds
} }

class Minimal(model.Background):
def on_initialize(self, event):
return

nButtons = 7

text="class MinimalChild(Minimal):"
text += "\n\t" + "def on_initialize(self, event):"
text += "\n\t" + "\tMinimal.on_initialize(self,event)"
for iButton in xrange(nButtons):
name = "Button"+str(iButton+1)
text += "\n\t" + "\tself.components['"+name+"'] = {" +\
"'type':'Button', " +\
"'name':'"+name+"', " +\
"'label':'"+name+"', "+\
"'position':(5, "+str(35+iButton*30)+")}"
if iButton!=nButtons-1:
text += "\n\t" + "def on_"+name+"_mouseClick(self, event):"
exec(text)

if __name__ == '__main__':
app = model.Application(MinimalChild, None, rsrc)
app.MainLoop()
With this approach, each time I click a button, a new one gets
created, along with a new handler for mouseClick of that new button.

Now, knowing the new.instancemethod way, may be I can simplify the
above somewhat and improve the efficiencies but I still don't see how
one can do it without using the exec function.

Regards,

Jun 23 '07 #13
On Sat, 23 Jun 2007 00:02:09 -0700, John Henry wrote:

[snip]
Notice that the event handler for mouseClick to Button1 is done via
the function on_Button1_mouseClick. This is very simple and works
great - until you try to create the button on the fly.

Creating the button itself is no problem. You simply do a:

self.components['Button1'] = {'type':'Button',
'name':'Button1',
'position':(5, 35),
'label':'Button1'}

But then how do I create the on_Button1_mouseClick function?
That depends on what it is supposed to do, but in general you want a
factory function -- a function that returns functions. Here's a simple
example:

def mouseclick_factory(arg):
def on_mouseClick(self, event):
print "You clicked '%s'." % arg
return on_mouseClick

func1 = mouseclick_factory("Button 1")
func2 = mouseclick_factory("this button")
func3 = mouseclick_factory("something")
Now let's try them out, faking the "self" and "event" parameters:

>>func1(None, None)
You clicked 'Button 1'.
>>func2(None, None)
You clicked 'this button'.
>>func3(None, None)
You clicked 'something'.
Obviously in a real application, self and event are important and can't be
faked with None.

Now, there are two ways of using that factory function in a class. Here
is an example of both.

class Parrot:
def __init__(self, arg):
self.bar = mouseclick_factory(arg)
foo = mouseclick_factory("Foo")

p = Parrot("bar")

If you do it like this, there is a slight Gotcha to watch out for: as
provided, foo is an instance method (and so has the self argument
supplied automatically) but bar is not (and so needs the self argument to
be supplied manually.
>>p.foo(None) # fake event argument
You clicked 'Foo'.
>>p.bar(p, None) # self and fake event arguments
You clicked 'bar'.

If this is a problem -- and believe me, it will be -- you can use
new.instancemethod to convert bar.
[snip]
Now, knowing the new.instancemethod way, may be I can simplify the
above somewhat and improve the efficiencies but I still don't see how
one can do it without using the exec function.
Rule 1:
Never use exec.

Exception for experts:
If you know enough to never need exec, you can use it.

Rule 1 is actually not quite true, but as an approximation to the truth,
it is quite good.

--
Steven.

Jun 23 '07 #14
>
But then how do I create the on_Button1_mouseClick function?

That depends on what it is supposed to do, but in general you want a
factory function -- a function that returns functions. Here's a simple
example:
<snip>

Steven,

May be I didn't explain it clearly: the PythonCard package expects to
see a function by the name of on_Button1_mouseClick. I don't do
anything to register the callback function. The package assumes that
there is a function by that name whenever I create a button named
Button1. So, if I don't use exec, how can I create a function by that
exact name?

Jun 23 '07 #15
On Sat, 23 Jun 2007 09:06:36 -0700, John Henry wrote:
>>
But then how do I create the on_Button1_mouseClick function?

That depends on what it is supposed to do, but in general you want a
factory function -- a function that returns functions. Here's a simple
example:
<snip>

Steven,

May be I didn't explain it clearly: the PythonCard package expects to
see a function by the name of on_Button1_mouseClick. I don't do
anything to register the callback function. The package assumes that
there is a function by that name whenever I create a button named
Button1. So, if I don't use exec, how can I create a function by that
exact name?

def mouseclick_factory(name):
def function(self, event):
print "You clicked '%s'." % name
function.name = "on_%s_mouseClick" % name
return function

class Parrot:
def __init__(self, name):
function = mouseclick_factory(name) # as before
method = new.instancemethod(function, self, self.__class__)
setattr(self, function.name, method)
And here it is in action:
>>p = Parrot("Button1")
p.on_Button1_mouseClick("event")
You clicked 'Button1'.

--
Steven.

Jun 23 '07 #16
On Jun 23, 10:56 am, Steven D'Aprano
<s...@REMOVE.THIS.cybersource.com.auwrote:
On Sat, 23 Jun 2007 09:06:36 -0700, John Henry wrote:
But then how do I create the on_Button1_mouseClick function?
That depends on what it is supposed to do, but in general you want a
factory function -- a function that returns functions. Here's a simple
example:
<snip>
Steven,
May be I didn't explain it clearly: the PythonCard package expects to
see a function by the name of on_Button1_mouseClick. I don't do
anything to register the callback function. The package assumes that
there is a function by that name whenever I create a button named
Button1. So, if I don't use exec, how can I create a function by that
exact name?

def mouseclick_factory(name):
def function(self, event):
print "You clicked '%s'." % name
function.name = "on_%s_mouseClick" % name
return function

class Parrot:
def __init__(self, name):
function = mouseclick_factory(name) # as before
method = new.instancemethod(function, self, self.__class__)
setattr(self, function.name, method)

And here it is in action:
>p = Parrot("Button1")
p.on_Button1_mouseClick("event")

You clicked 'Button1'.

--
Steven.

Thank you. I think that should work perfectly. By using
mouseclick_factory, you've avoided using exec and result in a much
more readable code. The part I really didn't know how is the use of
the new.instancemethod followed by setattr. I'll go try it now.

Thanks again.

Jun 23 '07 #17
On Jun 23, 10:56 am, Steven D'Aprano
<s...@REMOVE.THIS.cybersource.com.auwrote:
On Sat, 23 Jun 2007 09:06:36 -0700, John Henry wrote:
But then how do I create the on_Button1_mouseClick function?
That depends on what it is supposed to do, but in general you want a
factory function -- a function that returns functions. Here's a simple
example:
<snip>
Steven,
May be I didn't explain it clearly: the PythonCard package expects to
see a function by the name of on_Button1_mouseClick. I don't do
anything to register the callback function. The package assumes that
there is a function by that name whenever I create a button named
Button1. So, if I don't use exec, how can I create a function by that
exact name?

def mouseclick_factory(name):
def function(self, event):
print "You clicked '%s'." % name
function.name = "on_%s_mouseClick" % name
return function

class Parrot:
def __init__(self, name):
function = mouseclick_factory(name) # as before
method = new.instancemethod(function, self, self.__class__)
setattr(self, function.name, method)

And here it is in action:
>p = Parrot("Button1")
p.on_Button1_mouseClick("event")

You clicked 'Button1'.

--
Steven.

Wouldn't it be nice if it works right away? :=)

I tried the above method and this is what I have:

#!/usr/bin/python

"""
__version__ = "$Revision: 1.6 $"
__date__ = "$Date: 2004/08/17 19:46:06 $"
"""

import new

from PythonCard import model

rsrc = {'application':{'type':'Application',
'name':'Minimal',
'backgrounds': [
{'type':'Background',
'name':'bgMin',
'title':'Minimal PythonCard Application',
'size':(200, 300),
'components': [

] # end components
} # end background
] # end backgrounds
} }

def mouseclick_factory(parent, name):
id_num=int(name[-1:])
parent.components[name] = {'type':'Button',
'name':name,
'label':name,
'position':(5, 5+id_num*30),
'text':name}
def function(self, event):
print "You clicked '%s'." % name
function.name = "on_%s_mouseClick" % name
return function

class Minimal(model.Background):
def on_initialize(self, event):
self.components['field1'] =
{'type':'TextField','name':'field1','position':(5, 5),'size':(150,
-1),'text':'Hello PythonCard'}
name = "Button1"
function = mouseclick_factory(self, name) # as before
method = new.instancemethod(function, self, self.__class__)
setattr(self, function.name, method)

if __name__ == '__main__':
app = model.Application(Minimal, None, rsrc)
app.MainLoop()

When I click on the button, nothing happens. However, if I call the
function directly (like right after the setattr line:

self.on_Button1_mouseClick(event)

it works fine but PythonCard isn't calling this function when I
clicked on the button.

Jun 23 '07 #18
On Sat, 23 Jun 2007 12:31:39 -0700, John Henry wrote:
it works fine but PythonCard isn't calling this function when I
clicked on the button.

I think you need to take this question onto a PythonCard list. I have no
idea how PythonCard decides which method to call.
--
Steven.

Jun 24 '07 #19
On Jun 23, 6:24 pm, Steven D'Aprano
<s...@REMOVE.THIS.cybersource.com.auwrote:
On Sat, 23 Jun 2007 12:31:39 -0700, John Henry wrote:
it works fine but PythonCard isn't calling this function when I
clicked on the button.

I think you need to take this question onto a PythonCard list. I have no
idea how PythonCard decides which method to call.

--
Steven.

I did. I am not sure I'll get an answer though.

Thanks for the help.

Jun 24 '07 #20
On Jun 24, 1:19 am, John Henry <john106he...@hotmail.comwrote:
On Jun 23, 6:24 pm, Steven D'Aprano

<s...@REMOVE.THIS.cybersource.com.auwrote:
On Sat, 23 Jun 2007 12:31:39 -0700, John Henry wrote:
it works fine but PythonCard isn't calling this function when I
clicked on the button.
I think you need to take this question onto a PythonCard list. I have no
idea how PythonCard decides which method to call.
--
Steven.

I did. I am not sure I'll get an answer though.

Thanks for the help.
Upon further investigation, I found the problem.

Pythoncard is relying on the __name__ attribute and that's why it
didn't know about the newly careated function. I can not set that
attribute directly, of course, since it's a readonly attribute. Need
other workaround.

The author of Pythoncard has responded and so I am shifting this
thread over to the Pythoncard list.

Thanks again for all the help. I learned a few things about Python
through this exercise.

Jun 24 '07 #21
On Jun 24, 12:40 pm, John Henry <john106he...@hotmail.comwrote:
On Jun 24, 1:19 am, John Henry <john106he...@hotmail.comwrote:
On Jun 23, 6:24 pm, Steven D'Aprano
<s...@REMOVE.THIS.cybersource.com.auwrote:
On Sat, 23 Jun 2007 12:31:39 -0700, John Henry wrote:
it works fine but PythonCard isn't calling this function when I
clicked on the button.
I think you need to take this question onto a PythonCard list. I have no
idea how PythonCard decides which method to call.
--
Steven.
I did. I am not sure I'll get an answer though.
Thanks for the help.

Upon further investigation, I found the problem.

Pythoncard is relying on the __name__ attribute and that's why it
didn't know about the newly careated function. I can not set that
attribute directly, of course, since it's a readonly attribute. Need
other workaround.

The author of Pythoncard has responded and so I am shifting this
thread over to the Pythoncard list.

Thanks again for all the help. I learned a few things about Python
through this exercise.

Okay, just to complete the record - in case anybody tries to google
for a solution to add control to PythonCard at run time, here's a
complete code:

#!/usr/bin/python

"""
__version__ = "$Revision: 1.6 $"
__date__ = "$Date: 2004/08/17 19:46:06 $"
"""

import new

from PythonCard import log
from PythonCard import model
from PythonCard.model import SetInitParam

rsrc = {'application':{'type':'Application',
'name':'Minimal',
'backgrounds': [
{'type':'Background',
'name':'bgMin',
'title':'Minimal PythonCard Application',
'size':(200, 300),
'components': [

] # end components
} # end background
] # end backgrounds
} }

class Background_Dynamic(model.Background):

def __init__(self, aParent, aBgRsrc,
SetInitParamFct=SetInitParam):
model.Background.__init__(self, aParent, aBgRsrc,
SetInitParamFct)

def addHandler(self, aMethod):
# Add the Handler to our Handler list.
if aMethod.name not in self._handlers:
log.debug("addHandler: " + aMethod.name)
#self._handlers[aMethod.name] = event.Handler(aMethod)
self._handlers[aMethod.name] = aMethod

def mouseclick_factory(self, name):
def function(self, background, event):
self.mouseclick_factory("Button"+str(int(name[-1:])+1))
function.name = "on_%s_mouseClick" % name
method = new.instancemethod(function, self, self.__class__)
setattr(self, function.name, method)
self.addHandler(method)
self.components[name] = {'type':'Button',
'name':name,
'label':name,
'position':(5,
5+int(name[-1:])*30),
'text':name}
return function

class Minimal(Background_Dynamic):
def on_initialize(self, event):
self.components['field1'] =
{'type':'TextField','name':'field1','position':(5, 5),'size':(150,
-1),'text':'Hello PythonCard'}
self.mouseclick_factory("Button1")

if __name__ == '__main__':
app = model.Application(Minimal, None, rsrc)
app.MainLoop()
It goes to show how flexible and powerful PythonCard is. Too bad it
doesn't draw the attention of more new comers.

Jun 24 '07 #22

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

Similar topics

8
by: Thomas Guettler | last post by:
Hi! How can I add a method to an object. This code does not work: class Foo: def __init__(self): self.counter=0 f=Foo()
0
by: Federico Caselli | last post by:
Hi, Im using Visual basic.NET and adding a .cs file in my project (that contains myCsClass class in MyNameSpace namespace), I can't see myCsClass in the Visual Studio class explorer. Obvously,...
5
by: surrealtrauma | last post by:
the requirement is : Create a class called Rational (rational.h) for performing arithmetic with fractions. Write a program to test your class. Use Integer variables to represent the private data...
3
by: Casper | last post by:
Hi .Net experts, I am trying to build a user control of textbox and would like to add a public method to the object like public void CheckOptions(string str) { // codes here }
0
by: Ye | last post by:
I have a problem adding a class Wizard in .Net after I add a dialoge in the class. As somebody suggested, I tried to add stdafx.h as a member of the project (using add existing item) and then try...
0
by: Alex | last post by:
Hi, all I'm writing my first project under VS8 in MC++. I would like to create some helper class, which will provide communication with the SQL Server through ADO.NET. I'm thinking of...
4
by: marek.rocki | last post by:
First of all, please don't flame me immediately. I did browse archives and didn't see any solution to my problem. Assume I want to add a method to an object at runtime. Yes, to an object, not a...
3
by: raylopez99 | last post by:
Oh, I know, I should have provided complete code in console mode form. But for the rest of you (sorry Jon, just kidding) I have an example of why, once again, you must pick the correct entry point...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 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 a new...

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.