Dynamic Class Creation

Jack Diederich jackdied at gmail.com
Tue Mar 16 12:49:59 EDT 2010


On Tue, Mar 16, 2010 at 2:18 AM, Chris Rebert <clp2 at rebertia.com> wrote:
> On Mon, Mar 15, 2010 at 11:01 PM, Josh English
> <joshua.r.english at gmail.com> wrote:
>> I have a large program with lots of data stored in XML. I'm upgrading
>> my GUI to use ObjectListView, but with my data in XML, I don't have
>> regular objects to interact with the OLV. I do have an XML validator
>> that defines the structure of the XML elements, and I'm trying to
>> dynamically create a class to wrap the XML element.
>>
>> So, an element like:
>>
>> <market code="WotF">
>> <title>Writers of the Future</title>
>> </market>
>>
>> I want to create a class like:
>>
>> class Market(object):
>>    def __init__(self, elem):
>>        self._elem = elem
>>
>>    def get_code(self):
>>        return self._elem.get('code')
>>
>>    def set_code(self, value):
>>        self._elem.set('code', value)
>>
>>    def get_title(self):
>>        return self._elem.find('title').text
>>
>>    def set_title(self, value):
>>        node = self._elem.find('title')
>>        node.text = value
>>
>> Naturally, I don't want to hand code this for every interface but
>> would like to create them dynamically. (The laziness of programming, I
>> guess.)
>>
>> What's the best way to create these helper methods?

You can either define a catch-all __getattr__ method to look them up
dynamically, or as Chris kinda-suggested write descriptors for the
individual elements.

class Market():
  def __init__(self, elem):
    self._elem = elem
  def __getattr__(self, name):
    try:
      # I'm assuming this raises a KeyError when not found
      return self._elem.get(name)
    except KeyError:
      return self._elem.find(name)
  def __setitem__(self, name, value):
     # like __getitem__ but for setting

Chris' property maker function is almost like a descriptor class (how
properties are implemented under the hood), here's a refactoring
[untested]

class ElemGetProperty():
    def __init__(self, name):
      self.name = name
    def __get__(self, ob, cls):
      return ob._elem.get(self.name)
    def __set__(self, ob, val):
       ob._elem.set(self.name, val)

You could write one property class for each kind of element (get/find)
and then put them in your class like this

class Market():
    code = ElemGetProperty('code')
    title = ElemFindProeprty('title')

The getattr/setattr method is easier to understand and will handle
arbitrary elements;  for the descriptors version you'll have to define
one for each tag that might be used on the class.

-Jack



More information about the Python-list mailing list