[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Create a class at run-time

Michel

3/25/2010 10:01:00 PM

Hi everyone,

I'm trying to dynamically create a class. What I need is to define a
class, add methods to it and later instantiate this class. Methods
need to be bound to the instance though, and that's my problem. Here
is what I have so far:

method_template = "def test_foo(self):\
#actual test_foo\
pass"
exec method_template

TestClass = types.ClassType("MyTestClass", (unittest.TestCase, ), {})
TestClass.__module__ = "test"

now what to do next?
I looked at types.MethodType but it needs an instance to bind the
method and a function object.
Should I define __new__ to bind the method during instantiation?

Hope this makes sense,

Michel.
10 Answers

Michiel Overtoom

3/25/2010 10:18:00 PM

0

On 2010-03-25 23:00, Michel wrote:

> I'm trying to dynamically create a class. What I need is to define a
> class, add methods to it and later instantiate this class. Methods
> need to be bound to the instance though, and that's my problem.

Maybe this snippet is of any help?

import functools

class Template(object):
pass

def printmyname(self):
print self.name

t=Template()
t.name="Pete"
t.printmyname=functools.partial(printmyname,t)

u=Template()
u.name="Mary"
u.printmyname=functools.partial(printmyname,u)

t.printmyname()
u.printmyname()

Greetings,


--
"The ability of the OSS process to collect and harness
the collective IQ of thousands of individuals across
the Internet is simply amazing." - Vinod Valloppillil
http://www.catb.org/~esr/halloween/hallo...

Patrick Maupin

3/25/2010 10:35:00 PM

0

On Mar 25, 5:00 pm, Michel <michel.metz...@gmail.com> wrote:
> Hi everyone,
>
> I'm trying to dynamically create a class. What I need is to define a
> class, add methods to it and later instantiate this class. Methods
> need to be bound to the instance though, and that's my problem. Here
> is what I have so far:

Well, you should just fill your empty dict with function definitions,
BEFORE you build the class. That's easiest. Also, you can just use
type:

def foo(*whatever):
print foo

bar = type('MyDynamicClass', (object,), dict(foo=foo))

HTH,
Pat

I V

3/26/2010 1:53:00 AM

0

On Thu, 25 Mar 2010 15:00:35 -0700, Michel wrote:
> I'm trying to dynamically create a class. What I need is to define a
> class, add methods to it and later instantiate this class. Methods need
> to be bound to the instance though, and that's my problem. Here is what
> I have so far:

I'm not entirely sure what you mean by binding methods to the instance.
Do you mean you need to dynamically add methods to a specific instance?
Or that you need to add methods to a class, such that they can be invoked
on specific instances? For the latter, just do:

TestClass.test_foo = test_foo

For the former, try:

tc = TestClass()
tc.test_foo = types.MethodType(test_foo, tc)

Michel

3/26/2010 3:01:00 PM

0

Well, I don't have the reference to the instance. The class is
actually instantiated later by a the unittest library.

On Mar 25, 6:18 pm, Michiel Overtoom <mot...@xs4all.nl> wrote:
> On 2010-03-25 23:00, Michel wrote:
>
> > I'm trying to dynamically create a class. What I need is to define a
> > class, add methods to it and later instantiate this class. Methods
> > need to be bound to the instance though, and that's my problem.
>
> Maybe this snippet is of any help?
>
> import functools
>
> class Template(object):
>      pass
>
> def printmyname(self):
>      print self.name
>
> t=Template()
> t.name="Pete"
> t.printmyname=functools.partial(printmyname,t)
>
> u=Template()
> u.name="Mary"
> u.printmyname=functools.partial(printmyname,u)
>
> t.printmyname()
> u.printmyname()
>
> Greetings,
>
> --
> "The ability of the OSS process to collect and harness
> the collective IQ of thousands of individuals across
> the Internet is simply amazing." - Vinod Valloppillilhttp://www.catb.org/~esr/halloween/hallo...

Michel

3/26/2010 3:54:00 PM

0

I want to add a method to a class such that it can be invoked on
specifics instances.
You solution works (as well as Patrick's one), thanks !
I still have a question though. If I print the type of the self object
I get when my method is
called, I get "<class 'test.TestClass'>". I guess this is because the
method is defined as a class method.
This is ok in my case, but just out of curiosity, what should I do to
change this method to an instance method?

Thanks for your help,

Michel.

On Mar 25, 9:53 pm, I V <ivle...@gmail.com> wrote:
> On Thu, 25 Mar 2010 15:00:35 -0700, Michel wrote:
> > I'm trying to dynamically create a class. What I need is to define a
> > class, add methods to it and later instantiate this class. Methods need
> > to be bound to the instance though, and that's my problem. Here is what
> > I have so far:
>
> I'm not entirely sure what you mean by binding methods to the instance.
> Do you mean you need to dynamically add methods to a specific instance?
> Or that you need to add methods to a class, such that they can be invoked
> on specific instances? For the latter, just do:
>
> TestClass.test_foo = test_foo
>
> For the former, try:
>
> tc = TestClass()
> tc.test_foo = types.MethodType(test_foo, tc)

Peter Otten

3/26/2010 5:29:00 PM

0

Michel wrote:

> Hi everyone,
>
> I'm trying to dynamically create a class. What I need is to define a
> class, add methods to it and later instantiate this class. Methods
> need to be bound to the instance though, and that's my problem. Here
> is what I have so far:
>
> method_template = "def test_foo(self):\
> #actual test_foo\
> pass"
> exec method_template
>
> TestClass = types.ClassType("MyTestClass", (unittest.TestCase, ), {})
> TestClass.__module__ = "test"
>
> now what to do next?

Just assign it:

>>> import unittest
>>> class MyTestClass(unittest.TestCase): pass
....
>>> def test_foo(self):
.... self.assertEquals(1, 2)
....
>>> MyTestClass.test_foo = test_foo # <----
>>> unittest.main()
F
======================================================================
FAIL: test_foo (__main__.MyTestClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 2, in test_foo
AssertionError: 1 != 2

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

If you don't know the method name beforehand use

setattr(MyTestClass, method_name, method), e. g:

>>> import unittest
>>> class MyTestClass(unittest.TestCase): pass
....
>>> def make_method(n):
.... def test(self): self.assertEquals(2, n)
.... return test
....
>>> for i in range(3):
.... setattr(MyTestClass, "test_%d" % i, make_method(i))
....
>>> unittest.main()
FF.
======================================================================
FAIL: test_0 (__main__.MyTestClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 2, in test
AssertionError: 2 != 0

======================================================================
FAIL: test_1 (__main__.MyTestClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 2, in test
AssertionError: 2 != 1

----------------------------------------------------------------------
Ran 3 tests in 0.000s

FAILED (failures=2)

Peter

Michel

3/26/2010 6:41:00 PM

0

Thanks Peter.

I searched a little bit more and wrote the following example:

------------------------------------
import types

class MyClass:

def test_toto(self):
print type(self)
print self.name

def test_toto(self):
print type(self)
print self.name

MyDynClass = types.ClassType("MyDynClass", (object, ), {})
MyDynClass.__module__ = "test.complex.hierarchy"
MyDynClass.test_toto = test_toto

t1 = MyDynClass()
t2 = MyDynClass()

t1.name = "Marcel"
t2.name = "Oscar"

t1.test_toto()
t2.test_toto()

c1 = MyClass()
c1.name = "Raoul"
c1.test_toto()
--------------------------------

the output is:

<class 'test.complex.hierarchy.MyDynClass'>
Marcel
<class 'test.complex.hierarchy.MyDynClass'>
Oscar
<type 'instance'>
Raoul

I'm wondering why the type of the self parameter is not 'instance' in
the calls
t1.test_toto() and t2.test_toto()

The rest of the behavior is correct though, so I guess it's just
internal Python stuff.

Thanks for your help,

Michel.

On Mar 26, 1:29 pm, Peter Otten <__pete...@web.de> wrote:
> Michel wrote:
> > Hi everyone,
>
> > I'm trying to dynamically create a class. What I need is to define a
> > class, add methods to it and later instantiate this class. Methods
> > need to be bound to the instance though, and that's my problem. Here
> > is what I have so far:
>
> > method_template = "def test_foo(self):\
> >     #actual test_foo\
> >     pass"
> > exec method_template
>
> > TestClass = types.ClassType("MyTestClass", (unittest.TestCase, ), {})
> > TestClass.__module__ = "test"
>
> > now what to do next?
>
> Just assign it:
>
> >>> import unittest
> >>> class MyTestClass(unittest.TestCase): pass
> ...
> >>> def test_foo(self):
>
> ...     self.assertEquals(1, 2)
> ...>>> MyTestClass.test_foo = test_foo # <----
> >>> unittest.main()
>
> F
> ======================================================================
> FAIL: test_foo (__main__.MyTestClass)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File "<stdin>", line 2, in test_foo
> AssertionError: 1 != 2
>
> ----------------------------------------------------------------------
> Ran 1 test in 0.000s
>
> FAILED (failures=1)
>
> If you don't know the method name beforehand use
>
> setattr(MyTestClass, method_name, method), e. g:
>
> >>> import unittest
> >>> class MyTestClass(unittest.TestCase): pass
>
> ...                                          >>> def make_method(n):
>
> ...     def test(self): self.assertEquals(2, n)
> ...     return test                            
> ...>>> for i in range(3):
>
> ...     setattr(MyTestClass, "test_%d" % i, make_method(i))
> ...>>> unittest.main()
>
> FF.
> ======================================================================
> FAIL: test_0 (__main__.MyTestClass)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File "<stdin>", line 2, in test
> AssertionError: 2 != 0
>
> ======================================================================
> FAIL: test_1 (__main__.MyTestClass)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File "<stdin>", line 2, in test
> AssertionError: 2 != 1
>
> ----------------------------------------------------------------------
> Ran 3 tests in 0.000s
>
> FAILED (failures=2)
>
> Peter

Peter Otten

3/26/2010 7:16:00 PM

0

Michel wrote:

> Thanks Peter.
>
> I searched a little bit more and wrote the following example:
>
> ------------------------------------
> import types
>
> class MyClass:
>
> def test_toto(self):
> print type(self)
> print self.name
>
> def test_toto(self):
> print type(self)
> print self.name
>
> MyDynClass = types.ClassType("MyDynClass", (object, ), {})
> MyDynClass.__module__ = "test.complex.hierarchy"
> MyDynClass.test_toto = test_toto
>
> t1 = MyDynClass()
> t2 = MyDynClass()
>
> t1.name = "Marcel"
> t2.name = "Oscar"
>
> t1.test_toto()
> t2.test_toto()
>
> c1 = MyClass()
> c1.name = "Raoul"
> c1.test_toto()
> --------------------------------
>
> the output is:
>
> <class 'test.complex.hierarchy.MyDynClass'>
> Marcel
> <class 'test.complex.hierarchy.MyDynClass'>
> Oscar
> <type 'instance'>
> Raoul
>
> I'm wondering why the type of the self parameter is not 'instance' in
> the calls
> t1.test_toto() and t2.test_toto()
>
> The rest of the behavior is correct though, so I guess it's just
> internal Python stuff.

In Python 2.x there are "classic" and "newstyle" classes. In practice the
main differences are that classic classes are more likely to call
__getattr__() and that only newstyle classes support properties correctly.

By inheriting from object you make MyDynClass a newstyle class:

>>> classic = types.ClassType("A", (), {})
>>> newstyle = types.ClassType("A", (object,), {})

>>> type(classic()), type(classic)
(<type 'instance'>, <type 'classobj'>)

>>> type(newstyle()), type(newstyle)
(<class '__main__.A'>, <type 'type'>)

Classic classes exist for backwards compatibility and because most
programmers are too lazy to have their classes inherit from object when the
difference doesn't matter. When you create a class dynamically I recommend
that you use the type() builtin instead of types.ClassType(). This will
always create a newstyle class -- even when you don't inherit from object
explicitly:

>>> type(type("A", (), {}))
<type 'type'>
>>> type("A", (), {}).__bases__
(<type 'object'>,)

Peter

Steve Holden

3/26/2010 7:20:00 PM

0

Michel wrote:
> Thanks Peter.
>
> I searched a little bit more and wrote the following example:
>
> ------------------------------------
> import types
>
> class MyClass:
>
> def test_toto(self):
> print type(self)
> print self.name
>
> def test_toto(self):
> print type(self)
> print self.name
>
> MyDynClass = types.ClassType("MyDynClass", (object, ), {})
> MyDynClass.__module__ = "test.complex.hierarchy"
> MyDynClass.test_toto = test_toto
>
> t1 = MyDynClass()
> t2 = MyDynClass()
>
> t1.name = "Marcel"
> t2.name = "Oscar"
>
> t1.test_toto()
> t2.test_toto()
>
> c1 = MyClass()
> c1.name = "Raoul"
> c1.test_toto()
> --------------------------------
>
> the output is:
>
> <class 'test.complex.hierarchy.MyDynClass'>
> Marcel
> <class 'test.complex.hierarchy.MyDynClass'>
> Oscar
> <type 'instance'>
> Raoul
>
> I'm wondering why the type of the self parameter is not 'instance' in
> the calls
> t1.test_toto() and t2.test_toto()
>
> The rest of the behavior is correct though, so I guess it's just
> internal Python stuff.
>
Yes, it's just that MyClass is an old-style class (its type is <type
'classobj'>) whereas MyDynClass is a new-style class (its type is <type
'type'>, because it inherits from object).

It's as though you had written

class MyClass:
...

class MyDynClass(object):
...

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
See PyCon Talks from Atlanta 2010 http://pyco...
Holden Web LLC http://www.hold...
UPCOMING EVENTS: http://holdenweb.event...

I V

3/26/2010 8:46:00 PM

0

On Fri, 26 Mar 2010 08:54:11 -0700, Michel wrote:

> I want to add a method to a class such that it can be invoked on
> specifics instances.
> You solution works (as well as Patrick's one), thanks ! I still have a
> question though. If I print the type of the self object I get when my
> method is
> called, I get "<class 'test.TestClass'>". I guess this is because the
> method is defined as a class method.
> This is ok in my case, but just out of curiosity, what should I do to
> change this method to an instance method?

It already is an instance method. When you create a TestClass instance,
the type of that instance is TestClass (the type of TestClass itself is
"type").