is it possible to to write a class which, f.e. takes an argument in
__init__() and that doesn't return an instance object but a new class
object?
The problem is that I've got a base class and there should be many
subclasses of it. Each subclass just overwriting an output method and
serving as a template:
class base1:
def __init__(self):
...
def output(self):
...
class template1(base1):
def output(self):
...
class template2(base1):
def ouptut(self):
...
I need many, many of these "template" classes, so a sorter way would be
to accustom the base class to take another argument which then outputs
the right thing:
class base2:
def __init__(self, text):
...
def output(self):
print self.text
template1 = base2('some text')
template2 = base2('another example')
...
My problem with this is that this produces instance objects and in the
above example I had class objects. I can hardly use the latter case
because I would always modify the original.
I also cannot create new templates as I need them, because I'm writing
utility classes which are much more complex and take much more
arguments.
Is it somehow possible to have the "base2" class return a class instead
of an instance?
Is there another way to solve this problem?
Thanks in advance
Uwe
> The problem is that I've got a base class and there should be many
> subclasses of it. Each subclass just overwriting an output method and
> serving as a template:
>
> class base1:
> def __init__(self):
> ...
> def output(self):
> ...
>
> class template1(base1):
> def output(self):
> ...
>
> class template2(base1):
> def ouptut(self):
> ...
>
> I need many, many of these "template" classes, so a sorter way would be
> to accustom the base class to take another argument which then outputs
> the right thing:
This problems begs for you to create a factory function::
def factory(objType, initValue):
classTable = {
'template1':template1
'template2':template2
}
return classTable[objType](initValue)
This way you don't have to know the specifics anout the class that your
create.
you would then just have to::
import templates
newObj = templates.factory('template2', 'Initial text')
regards Max M
Sure, but you have to do it closer to the source level. One
quibble here: you can't do it with the __init__() method, that's
defined to always return an instance. You have to do it with some
kind of generator or factory function.
The way you do it is to create the source in a string, and
then use exec.
However, as another poster mentions, there may be better
ways of solving your specific problem. Dynamically generating
pieces of program is useful in some highly specialized
circumstances, but this might not be one of them.
John Roth
This leads into metaclass programming. Read GvR's descintro on Python
2.2, it has some material - it may be all you need. Roughly you need
something like
class Whatever(type):
...
type is the mother of all metaclasses, its instances are classes
themselves.
Hope it helped, all the best,
Gonçalo Rodrigues
So far I've seen suggestions that:
(1) Create a factory function which returns the appropriate class.
(2) Somehow use exec to build the classes at runtime.
(3) Use metaclass programming.
I would suggest that (1) is by far the best solution, and that you stay
away from (2) and (3) unless you KNOW what you are doing, or you are
more interested in playing around (and learning) than getting your
problem solved.
But just to be confusing, I'm going to add a (4)th solution, completely
different from the other three!
(4) In python, you can change individual methods of an instance, so you
may not even NEED to have many separate classes, if they differ only in
that one method.
Here is an illustration of how it would work:
Python 2.2.1 (#34, Apr 9 2002, 19:34:33) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Base:
... def output_0(self):
... print 'zero'
... def output_1(self):
... print 'one'
... def output_2(self):
... print 'two'
... def __init__(self, n):
... self.output = (
... [self.output_0, self.output_1, self.output_2] [n] )
...
>>> b = Base(0)
>>> b.output()
zero
>>> b = Base(2)
>>> b.output()
two
HOWEVER... if your subclasses need more than just the one function
defined in them, then you are better off going with solution (1) above.
-- Michael Chermside
In Python 2.1 and above, you can take advantage of nested scopes to
generate different classes from a template. The idea is to put the
template class definition inside a function, and have the class refer
to the function's arguments.
def template_factory(baseclass,text):
class template(baseclass):
def output(self):
print text
return template
Remember to use from __future__ import nested_scopes if you're on
Python 2.1. If you're using 2.0 or lower, you can still fake the
nested scopes thing with a default argument:
def template_factory(baseclass,text):
class template(baseclass):
def output(self,text=text):
print text
return template
Here's an example session:
Python 2.1.3 (#1, Apr 20 2002, 10:14:34)
[GCC 2.95.4 20011002 (Debian prerelease)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> from __future__ import nested_scopes
>>> def template_factory(text):
... class template:
... def output(self):
... print text
... return template
...
>>> a = template_factory("hello, world")
>>> b = a()
>>> b.output()
hello, world
>>> c = template_factory("hello, my name is inigo montoya")
>>> d = c()
>>> d.output()
hello, my name is inigo montoya
--
CARL BANKS http://www.aerojockey.com
"Nullum mihi placet tamquam provocatio magna. Hoc ex eis non est."
>
> "Uwe Mayer" <Uwe....@ifib.uni-karlsruhe.de> wrote in message
> news:3D16E465...@ifib.uni-karlsruhe.de...
>> Hi,
>>
>> is it possible to to write a class which, f.e. takes an argument in
>> __init__() and that doesn't return an instance object but a new class
>> object?
>
> Sure, but you have to do it closer to the source level. One
> quibble here: you can't do it with the __init__() method, that's
> defined to always return an instance. You have to do it with some
> kind of generator or factory function.
just to clarify: __init__ is _not_ return anything.
1. an instance is created, you can already call methods on it.
2. __init__ is called if defined. (it's an initializer, notthing more or
less)
that why it isn't called __new__ [hint, hint]
>>> class A(type):
... def __new__(klass, arg):
... return int(arg)
...
>>> A(5)
5
>>> type(A(5))
<type 'int'>
chris
--
Chris <clie...@gmx.net>
Several people have offered ways to do this with metaclasses or
run-time code generation with exec, but I agree with Michael Chermside
that you should use a factory function or just override the output
method on individual instances instead.
And naturally you can extend this slightly with a closure to avoid
having to declare all your methods in the class upfront ie.
class Base:
def __init__(self, text):
def closure():
print text
self._output = closure
def output(self):
self._output()
b = Base("Hello")
c = Base("World")
b.output()
Hello
c.output()
World
> HOWEVER... if your subclasses need more than just the one function
> defined in them, then you are better off going with solution (1) above.
Agreed. The original post requested generic python, AFAIK this is
best done by runtime definition of classes inside factory
methods/functions.
Andrae Muys