class factory example needed (long)

G

Gary Ruben

I have a class factory problem. You could say that my main problem is
that I don't understand class factories.
My specific problem:
I have a class with several methods I've defined.
To this class I want to add a number of other class methods where the
method names are taken from a list.
For each list member, I want to build a method having the list member
name so that I can override another method of the same name for objects
which are instances of this class. Finally, I want my class factory
which creates the method to call the overridden method.

I'm sure my description is confusing, so I'll try to illustrate it.


import Numeric
# The Numeric module contains a whole lot of methods which operate on
certain number types

class foo:
""" this is a number type class
"""
def __init__(self, value):
self.value = float(value)
def __str__(self):
.
. other methods here
.

import string
ufuncs = string.split("""
sqrt arccos arccosh arcsin arcsinh arctan arctanh cos cosh tan tanh
log10 sin sinh sqrt absolute fabs floor ceil fmod exp log conjugate
""") # these are the methods from Numeric that I want to
override/wrap for my number type

for u in ufuncs:
I need something here which builds methods called sqrt(),
arccos(), etc.

An illustrative example of the class methods I want to build with
some sort of class factory is
def sqrt(self):
val = Numeric.sqrt(self.value)
return foo(Numeric.sqrt(self.value) + 42)

def arccos(self):
val = Numeric.arccos(self.value)
return foo(Numeric.arccos(self.value) + 42)


if __name__ == "__main__":
a = 9
b = foo(7)
print Numeric.sqrt(a)
print Numeric.sqrt(b)


This would print
3
7

Note that the methods I want to create under program control are all
identical in form. In this example they all call the wrapped method with
an argument 42 greater than the value of the number.
Does anyone have an example where they've done something similar or
could help me out with an example?
thanks in anticipation,
Gary
 
R

Rainer Mansfeld

Gary said:
I have a class factory problem. You could say that my main problem is
that I don't understand class factories.
My specific problem:
I have a class with several methods I've defined.
To this class I want to add a number of other class methods where the
method names are taken from a list.
For each list member, I want to build a method having the list member
name so that I can override another method of the same name for objects
which are instances of this class. Finally, I want my class factory
which creates the method to call the overridden method.

I'm sure my description is confusing, so I'll try to illustrate it.


import Numeric
# The Numeric module contains a whole lot of methods which operate on
certain number types

class foo:
""" this is a number type class
"""
def __init__(self, value):
self.value = float(value)
def __str__(self):
.
. other methods here
.

import string
ufuncs = string.split("""
sqrt arccos arccosh arcsin arcsinh arctan arctanh cos cosh tan tanh
log10 sin sinh sqrt absolute fabs floor ceil fmod exp log conjugate
""") # these are the methods from Numeric that I want to
override/wrap for my number type

for u in ufuncs:
I need something here which builds methods called sqrt(),
arccos(), etc.

An illustrative example of the class methods I want to build with
some sort of class factory is
def sqrt(self):
val = Numeric.sqrt(self.value)
return foo(Numeric.sqrt(self.value) + 42)

def arccos(self):
val = Numeric.arccos(self.value)
return foo(Numeric.arccos(self.value) + 42)


if __name__ == "__main__":
a = 9
b = foo(7)
print Numeric.sqrt(a)
print Numeric.sqrt(b)


This would print
3
7

Note that the methods I want to create under program control are all
identical in form. In this example they all call the wrapped method with
an argument 42 greater than the value of the number.
Does anyone have an example where they've done something similar or
could help me out with an example?
thanks in anticipation,
Gary

Hi Gary,

you want your 'class factory' to change the methods of Numeric, so
that they accept foo objects and return foo objects?
I've not the slightest idea how to achieve that.

If OTOH you want your foo class to have sqrt, arccos, etc. methods
without defining them explicitly, I think you're looking for
something like:

.. import Numeric
..
.. class Foo(object):
.. def __init__(self, value):
.. self.value = float(value)
.. for u in ['sqrt', 'cos', 'tan']:
.. setattr(self, u, lambda uf=getattr(Numeric, u):
.. uf(self.value + 42.0))
7.0

HTH
Rainer
 
G

Gary Ruben

Thanks for the very helpful reply Rainer,
I thought I couldn't use setattr because I need the syntactic sugar
sqrt(f) to work, but with your example code Numeric.sqrt(f) does in fact
work correctly. I also need to do a bit more than may be possible with a
simple lambda function, but I should be able to sort it out from here
with the info you provided,
thanks again,
Gary

Rainer Mansfeld wrote:
Hi Gary,

you want your 'class factory' to change the methods of Numeric, so that
they accept foo objects and return foo objects?
I've not the slightest idea how to achieve that.

If OTOH you want your foo class to have sqrt, arccos, etc. methods
without defining them explicitly, I think you're looking for something
like:

. import Numeric
.
. class Foo(object):
. def __init__(self, value):
. self.value = float(value)
. for u in ['sqrt', 'cos', 'tan']:
. setattr(self, u, lambda uf=getattr(Numeric, u):
. uf(self.value + 42.0))
7.0

HTH
Rainer
 
G

Gary Ruben

OK, I've managed to get this to work with Rainer's method, but I
realised it is not the best way to do it, since the methods are being
added by the constructor, i.e. they are instance methods. This means
that every time a foo object is created, a whole lot of code is being
run. It would be better to do the same thing with class 'static'
methods, if this is possible, so that the methods are created just once.
Is this possible?
Gary

Rainer Mansfeld wrote:
If OTOH you want your foo class to have sqrt, arccos, etc. methods
without defining them explicitly, I think you're looking for something
like:

. import Numeric
.
. class Foo(object):
. def __init__(self, value):
. self.value = float(value)
. for u in ['sqrt', 'cos', 'tan']:
. setattr(self, u, lambda uf=getattr(Numeric, u):
. uf(self.value + 42.0))
7.0

HTH
Rainer
 
S

Steven Bethard

Gary said:
OK, I've managed to get this to work with Rainer's method, but I
realised it is not the best way to do it, since the methods are being
added by the constructor, i.e. they are instance methods. This means
that every time a foo object is created, a whole lot of code is being
run. It would be better to do the same thing with class 'static'
methods, if this is possible, so that the methods are created just once.
Is this possible?

See my comment on the recipe at:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/389793

STeVe
 
K

Kent Johnson

Gary said:
OK, I've managed to get this to work with Rainer's method, but I
realised it is not the best way to do it, since the methods are being
added by the constructor, i.e. they are instance methods. This means
that every time a foo object is created, a whole lot of code is being
run. It would be better to do the same thing with class 'static'
methods, if this is possible, so that the methods are created just once.
Is this possible?

Here is a solution using a metaclass:

import Numeric

class MetaFoo(type):
def __init__(cls, name, bases, d):
super(MetaFoo, cls).__init__(cls, name, bases, d)
for u in ['sqrt', 'cos', 'tan']:
setattr(cls, u, lambda self, uf=getattr(Numeric, u): uf(self.value + 42.0))


class Foo(object):
__metaclass__ = MetaFoo

def __init__(self, value):
self.value = float(value)

f = Foo(7)
print f.sqrt()


Kent
 
G

Gary Ruben

Thanks Steven and Kent, both of your suggestions look good to me. I'll
try both out and pick one.
Gary
 

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
474,222
Messages
2,571,137
Members
47,754
Latest member
Armand37T7

Latest Threads

Top