2

Is it possible to change a class of a C object to a python subclass?

I am using PyGTK, and I have a ListModel that I have wrapped my own class around, but I want to turn it into a TreeModelFilter. The directions tell me to create it by doing:

class MyListStore(gtk.ListStore):
  def __init__(self, title):
    self.title = title

liststore = MyListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
modelfilter = liststore.filter_new()

So I thought I could just create:

class MyFilteredListStore(gtk.TreeModelFilter):
  def __init__(self, title):
    self.title = title

But I don't know how to use filter_new to use my class, instead of gtk.TreeModelFilter.

bradlis7
  • 3,375
  • 3
  • 26
  • 34
  • @agf is that a better title? It's more about the parent/child of general Python, but the PyGTK is just to give an example. – bradlis7 Sep 28 '11 at 21:44
  • http://stackoverflow.com/questions/2153295/python-object-conversion This question is close, but I may want to use the __init__ in my own program. I haven't decided. – bradlis7 Sep 28 '11 at 21:55
  • 2
    What is it you're asking? How to take a class instance that exists, and change it into an instance of a subclass of its class? Or how to get a method to return a different type than it's written to? The answer to the first is "switch the `__class__`" and the answer to the second is "rewrite the method". Whatever it is, your current title isn't much better than the old one; maybe you mean "Create class instance from subclass of it's usual parent class" or something like that? – agf Sep 28 '11 at 21:55
  • Nevermind to question 2153295. I can't assign to __class__, as the object is defined in C. – bradlis7 Sep 28 '11 at 22:05
  • How do I handle a question if there's not an answer (I can't answer it myself either)? I think I may just take another route to solve my problem. Do I delete the question, or just choose the best available? – bradlis7 Sep 29 '11 at 19:16
  • Either post what you ended up doing and accept it after the time limit is up, or just leave it unaccepted. If you didn't get an answer, you shouldn't mark one as accepted. – agf Sep 29 '11 at 19:31
  • Thanks @agf. I also edited the question to be more specific to my needs, while still keeping most of the content, and wrote an answer that solves it. – bradlis7 Sep 29 '11 at 21:34

2 Answers2

1

Inheritance can be a very fluid concept in python. For starters, you should always use new style classes. To do that, make sure your classes should always inherit from "object".

It's important to note that Classes must inherit from other classes, not instances of other classes, so your example really wouldn't work there. In fact, I don't really see the difference between inheriting from X or x1.

Inheritance in python is closely tied to the "Method Resolution Order" (MRO). You can view an objects MRO using the inspect module.

>>> import inspect
>>> import pprint
>>>
>>> class X(object):
...     pass
...
>>> class Y(X):
...     pass
...
>>>
>>> pprint.pprint(inspect.getmro(Y))
(<class '__main__.Y'>, <class '__main__.X'>, <type 'object'>)
>>> 

The tuple at the end shows the order in which python will try to resolve method and attribute calls. You can modify the MRO at runtime by modifying a class's __bases__ attribute.

>>> Y.__bases__
(<class '__main__.X'>,)
>>>
>>> class Z(object):
...     pass
...
>>> Y.__bases__ = tuple([Z])
>>> pprint.pprint(inspect.getmro(Y))
(<class '__main__.Y'>, <class '__main__.Z'>, <type 'object'>)
>>>

This can get complicated if any of your classes use multiple inheritance, or if you want to preserve certain parts of the inheritance tree but not others.

  • Well, the Python programmers don't have a way to directly create a TreeModelFilter, so instead, I'm wanting to turn the instance from one object to a subclass of the object. I can't change __class__ unfortunately. – bradlis7 Sep 28 '11 at 22:05
  • @bradlis7 : if you have problems with TreeModelFilter, open a new question showing the code snippet you try to run, and we will have a serious look at it ! – Louis Sep 29 '11 at 07:26
1

The best way to handle this problem is not to subclass the TreeModel, but to assign a variable to the object that can be the ListStore or the TreeModelFilter.

class MyListStore(object):
  def __init__(self, title, filter=None):
    self.title = title
    self._model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
    if filter_func:
      self._model = self.model.filter_new()
      self._model.set_visible_func(filter)

I think this is the best way to get around this.

Edit

For anyone interested, I found the following to be helpful to keep from breaking old code. It acts like inheritance, without actually doing so:

  def __getattr__(self, name):
    'Get the attribute from the model if possible.'
    if hasattr(self._model, name):
      return getattr(self._model, name)
    if isinstance(self._model, gtk.TreeModelFilter):
      if hasattr(self._model.get_model(), name):
        return getattr(self._model.get_model(), name)
bradlis7
  • 3,375
  • 3
  • 26
  • 34