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.
> 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/halloween4.html
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'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)
Thanks for your help,
Michel.
> 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
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.
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
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://pycon.blip.tv/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/
> 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").