Prev: Revisiting Generators and Subgenerators
Next: Don't understand behavior; instance form a class in another class'instance
From: Michel on 26 Mar 2010 11:54 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...(a)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)
From: Peter Otten on 26 Mar 2010 13:29 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
From: Michel on 26 Mar 2010 14:41 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...(a)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
From: Peter Otten on 26 Mar 2010 15:16 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
From: Steve Holden on 26 Mar 2010 15:19 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://pycon.blip.tv/ Holden Web LLC http://www.holdenweb.com/ UPCOMING EVENTS: http://holdenweb.eventbrite.com/
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: Revisiting Generators and Subgenerators Next: Don't understand behavior; instance form a class in another class'instance |