class factory question

A forum for general discussion of the Python programming language.

class factory question

Postby zeycus » Fri Oct 04, 2013 5:19 pm

I am implementing something using for the first time a class factory, and I have some doubts. The classes in my original problem are too complex,I invented a simplified version.

Supose I have a hierarchy of classes, all of which implement a method resetFromDict(dic), where dic is a dictionary. All those classes inherit from Item, that is an abstract class:

File item.py
Code: Select all
class Item(object):
    @classmethod
    def createFromDict(cls, dic):
        obj = cls()
        obj.resetFromDict(dic)
        return obj


Here the classmethod createFromDict() works as a constructor, creating empty instances and using the appropiate resetFromDict method.

Now, I want to be able to create instances of my classes for coordinates, and those can be polar or cartesian.

File coordinatesCartesian
Code: Select all
from item import Item

class CoordinatesCartesian(Item):
    def resetFromDict(self, dic):
        self.x = dic['x']
        self.y = dic['y']

if __name__ == "__main__":
    dic = {'system': 'car', 'x':3.2, 'y':-1.45}
    coords = CoordinatesCartesian.createFromDict(dic)



File coordinatesPolar
Code: Select all
import math

from item import Item


class CoordinatesPolar(Item):
    def resetFromDict(self, dic):
        self.arg = dic['arg'] * 180 / math.pi
        self.mod = dic['mod']

if __name__ == "__main__":
    dic = {'system': 'pol', 'arg':0.235, 'mod':3.2351}
    coords = CoordinatesPolar.createFromDict(dic)


What would be nice is that for any dic containing coordinates, an instance of the class that works for those coordinates would be chosen. That is where I use a class factory Coordinates. It takes a look at the "system" in dic, and decides whether to call the createFromDict of one or the other class. I do it by reimplementing createFromDict in Coordinates:

File coordinates
Code: Select all
from item import Item

class Coordinates(Item):
    @classmethod
    def createFromDict(cls, dic):
        if dic['system'] == 'pol':
            from coordinatesPolar import CoordinatesPolar
            cls = CoordinatesPolar
        elif dic['system'] == 'car':
            from coordinatesCartesian import CoordinatesCartesian
            cls = CoordinatesCartesian
        else:
            raise("Coordinates system unkwnown")
        return cls.createFromDict(dic)

if __name__ == "__main__":
    dic = {'system': 'pol', 'arg':0.235, 'mod':3.2351}
    coords = Coordinates.createFromDict(dic)
    dic = {'system': 'car', 'x':3.2, 'y':-1.45}
    coords = CoordinatesCartesian.createFromDict(dic)


So far so good, this works (although I am not sure the imports in line 9 and 12 of coordinates.py are really a good idea. But how to avoid them, if I want to have separate files for each class?).

The problem is: I wanted that CoordinatesCartesian and CoordinatesPolar whould inherit from Coordinates, so some other methods that are common to all coordinate systems would be coded in Coordinates. But I cannot do it as it is implemented, because then calling createFromDict would fall into an infinite loop. I have thought of two solutions, but I don't like either of them:
* reimplement in CoordinatesPolar and CoordinatesCartesian the method createFromDict(), calling that of Item. Then the infinite loop dissapears.
* Use multiple inheritance and create *another* class CoordinateCommon, or something like that, and make both
CoordinatesCartesian and CoordinatesPolar inherit from it and from Item. But having another class for this, and multiple inheritance, seems cumbersome.

Please, can you tell me how you think this should be implemented?

Thanks in advance.
Image

Live long and prosper.
Spock
User avatar
zeycus
 
Posts: 23
Joined: Sun Feb 17, 2013 10:30 am
Location: Madrid

Re: class factory question

Postby ochichinyezaboombwa » Fri Oct 04, 2013 11:37 pm

Have you considered overriding the __new__? Something like this:

Code: Select all
class Coordinates(object):
    def __new__(cls, *args, **kwds):
        assert(len ( args ) == 2) # For example...
        (dic, smth_else) = args 

        if dic['system'] == 'Cartesian':
            cls = Cartesian
        elif dic['system'] == "Polar':
            cls = Polar
        else:
            assert(False)

        thing = object.__new__(cls)
        thing.__init__(*args, **kwds)

   return thing
ochichinyezaboombwa
 
Posts: 200
Joined: Tue Jun 04, 2013 7:53 pm

Re: class factory question

Postby zeycus » Sat Oct 05, 2013 8:18 am

ochichinyezaboombwa wrote:Have you considered overriding the __new__? Something like this:

Code: Select all
class Coordinates(object):
    def __new__(cls, *args, **kwds):
        assert(len ( args ) == 2) # For example...
        (dic, smth_else) = args 

        if dic['system'] == 'Cartesian':
            cls = Cartesian
        elif dic['system'] == "Polar':
            cls = Polar
        else:
            assert(False)

        thing = object.__new__(cls)
        thing.__init__(*args, **kwds)

   return thing

Thanks for your answer, no, I have not :-). But, could I in that case make CoordinatesPolar and CoordinatesCartesian inherit from Coordinates? Would not __new__ be inherited by them, provoking the same infinite loop I mentioned?
Image

Live long and prosper.
Spock
User avatar
zeycus
 
Posts: 23
Joined: Sun Feb 17, 2013 10:30 am
Location: Madrid

Re: class factory question

Postby micseydel » Sat Oct 05, 2013 7:47 pm

I'm not sure what you want here. Why not use classes instead of dictionaries, and instead of a class method that you pass a dictionary to, you just call a method of the object?
Join the #python-forum IRC channel on irc.freenode.net!
User avatar
micseydel
 
Posts: 929
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: class factory question

Postby zeycus » Sat Oct 05, 2013 8:20 pm

micseydel wrote:I'm not sure what you want here. Why not use classes instead of dictionaries, and instead of a class method that you pass a dictionary to, you just call a method of the object?

Maybe I oversimplified the original program I have in hand. In that one, what is passed is not a dict, but an Element (defined in the ElementTree module). From a huge Element, that contains all kinds of financial data, I am extracting subelements that contain simple pieces of information: one about volatility surfaces, other about discount curves, fixings, etc. And I have implemented classes that store each of those pieces of information. I need that for other transformations that come later. For me it was not relevant how the information is passed in the method resetFromDic(), so I decided to use dictionaries here, in this example. What matters is that every class must have that method resetFromDic (in fact, resetFromElement) implemented, to reset the values of its attributes according to the info passed.

I don't know if this makes more sense.
Image

Live long and prosper.
Spock
User avatar
zeycus
 
Posts: 23
Joined: Sun Feb 17, 2013 10:30 am
Location: Madrid

Re: class factory question

Postby micseydel » Sat Oct 05, 2013 9:52 pm

Could wrapping/subclassing your Elements help? I really appreciate you posting a simplified example, but it might be time to post more code.
Join the #python-forum IRC channel on irc.freenode.net!
User avatar
micseydel
 
Posts: 929
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: class factory question

Postby zeycus » Sun Oct 06, 2013 6:46 am

micseydel wrote:Could wrapping/subclassing your Elements help? I really appreciate you posting a simplified example, but it might be time to post more code.

You are right. But that code is in my workplace, so I don't have access to it right now. I will prepare a small subset, and post it here in about two days, together with the input files used.
Image

Live long and prosper.
Spock
User avatar
zeycus
 
Posts: 23
Joined: Sun Feb 17, 2013 10:30 am
Location: Madrid


Return to General Discussions

Who is online

Users browsing this forum: No registered users and 3 guests

cron