can i define a new method at runtime?

R

Raoul

I have a GUI application where I want to assign validation methods to
controls.

If my control myTextBox has a change() event for on change and I want
to make it verify the input is an integer I could do...

def myTextBox.change():
verifyInteger(myTextBox.Value)

def verifyInteger(x):
try:
string.atoi(x.value)
except ValueError :
message(x," needs to be an integer")
x.setFocus()

but i have literally hundreds of these things to do....

I'd like to be able to say somethign like

myTextBox.change = lambda x : verifyInteger(x)

so when i initialize my form i'd like to run through a list that looks
like

[["controlName1","verifyInteger"],["controlName2,"verifyFloat"],["controlName3
"verifyInteger"]

but i can't seem to make this work.

I've tried to use exec("def foo = lambda x: do something....")

but that doesn't seem to work....

Got any ideas ???
 
R

Reinhold Birkenfeld

Raoul said:
If my control myTextBox has a change() event for on change and I want
to make it verify the input is an integer I could do...

def myTextBox.change():
verifyInteger(myTextBox.Value)

def verifyInteger(x):
try:
string.atoi(x.value)
except ValueError :
message(x," needs to be an integer")
x.setFocus()

but i have literally hundreds of these things to do....

I'd like to be able to say somethign like

myTextBox.change = lambda x : verifyInteger(x)

so when i initialize my form i'd like to run through a list that looks
like

[["controlName1","verifyInteger"],["controlName2,"verifyFloat"],["controlName3
"verifyInteger"]

I'm not a guru, so expect this solution to be bloated ;)

For example, (ab)use a class to build a unit with all the verify-functions:

class Verify(object):
def verify_integer(x): [...]
def verify_float(x): [...]

# Then, iterate over the list:

for pair in list: # list being your example above
control = getattr(__main__, pair[0])
control.changed = eval("lambda self: Verify." + pair[1] + "(self.Value)")
# for this line there MUST be a solution without eval but I don't see it
at the moment

BTW, you should use tuples if the information about the handling
functions is static.

regards, Reinhold
 
V

Ville Vainio

Raoul> I have a GUI application where I want to assign validation
Raoul> methods to controls.

Raoul> If my control myTextBox has a change() event for on change
Raoul> and I want to make it verify the input is an integer I
Raoul> could do...

If there is a change method, I assume you need to implement the class
yourself. Why not just subclass the root TextBox class and create a
IntegerTextBox class that has verifyInteger in the change method? Then
you just choose at instantiation time that this particular textbox
needs an integer...
 
L

Larry Bates

You are close. Try something like

def verifyInteger(x):
try:
string.atoi(x.value)
except ValueError :
message(x," needs to be an integer")
x.setFocus()

In a dictionary put keys (controlNames) and
pointers to what function (or method) to call
for that controlName.

verifiers={'controlName1': verifyInteger,
'controlName2': verifyFloat,
...
'controlNameN': veryfySomething}


In your program call the function from the
dictionary as follows:

verifiers['controlName1'](x)
verifiers['controlName2'](x)
....

This works because the result of the getting
verifiers[controlName] is a pointer to a
function instead of a value. This pointer
has a call method, so you can just put the
arguments after it.

HTH,
Larry Bates
Syscon, Inc.
 
H

Hung Jung Lu

but i have literally hundreds of these things to do....

I'd like to be able to say somethign like

myTextBox.change = lambda x : verifyInteger(x)

so when i initialize my form i'd like to run through a list that looks
like

[["controlName1","verifyInteger"],["controlName2,"verifyFloat"],["controlName3
"verifyInteger"]

def change_Integer(self):
try:
string.atoi(self.value)
except ValueError:
message(...)
self.setFocous()
def change_Currrency(self):
...

dict = {"box1": "Integer", "box2": "Currency"}

import new
for (box_name, box_type) in dict.iteritems():
function_name = 'change_%s' % box_type
f = eval(function_name)
box = getattr(myFrame, box_name)
box.change = new.instancemethod(f, box, box.__class__)

replace eval() by globals() if safety is a concern, or replace by
getattr(...) if functions are defined in modules or classes. (.im_func
maybe needed, anyway, you'll figure out the specifics on your own.)

Hung Jung
 
H

Hung Jung Lu

Ville Vainio said:
If there is a change method, I assume you need to implement the class
yourself. Why not just subclass the root TextBox class and create a
IntegerTextBox class that has verifyInteger in the change method? Then
you just choose at instantiation time that this particular textbox
needs an integer...

This is OK if there are only a few types of boxes. But entry data
types are features, and they tend to grow and become complicated, even
if Regex (regular expression) patterns were used. Besides, the
verification logic is a conceptual unit on its own right, so according
to the AOP (aspect-oriented programming) philosophy, it's best to
group the verification methods together in some "aspect class". There
may be new dimensions to the problem that one may not have foreseen at
the time of design. For instance, localization (currency, dates, usage
of commas and periods, ZIP codes, etc.) Having verification code in
its own hierarchy allows you to make changes more easily and take
advantage of class inheritance for code re-use. Once you have the
verification logic done, you hook it to the widget objects somehow. In
Python, this usually involves some form of metaprogramming. There are
too many ways to do it, and you'll probably not find two people doing
it the same way. Some tools in the arsenal are: using
functions/methods as first class objects and assign them or tweak them
to your heart's content, using the "new" module, using code objects
and "exec" statements, tweaking an existing object's __class__
attribute, implementing/overriding the __getattr__() method in
classes, metaclasses, etc. etc.

regards,

Hung Jung
 
J

Jeff Epler

Something like the untested code below will work, without the need to
"exec" anything.

def verifyInteger(x): ...
def verifyFloat(x): ...
verifiers = {"ControlName1": verifyInteger, "ControlName2": verifyFloat, ....}

class MyTextBox(TextBox):
def __init__(self, controlname, ...):
self.verifyfunc = verifiers[self.controlname]
TextBox.__init__(self, ...)
...
def change(self):
self.verifyfunc(self.value)

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFA1szcJd01MZaTXX0RAizxAJ4lzaIFRv5xeS0+YlD3rKevATT4kACgjbwn
izanXr8+GfuUL9sRfERyi2w=
=12C3
-----END PGP SIGNATURE-----
 

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

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top