dynamically selecting a class to instantiate based on the object attributes.

Ian Kelly ian.g.kelly at gmail.com
Mon May 14 14:30:43 EDT 2012


On Wed, May 9, 2012 at 5:02 AM, J. Mwebaze <jmwebaze at gmail.com> wrote:
>
> I have a  bunch of objects of the same type. Each object has a version
> attribute and this refers to source code that was used to make the object.
> SouceCode is maintained in separate files. eg.
> myclass_01.py, myclass_02.py, myclass_03.py, myclass_04.py ..
>
> During object instantiaton, i would like to use  the specific class, that
> corresponds to the version of the class that was used to create the object.
> However i cant know the specific "myclass_??.py" before i read the version
> attribute of the object.
>
> Seems like a situation where i have to partially instantiate the object to
> read the version attribute, and after that continue with instantiaton with
> the specific version of the version..
>
> Is this doeable?

Why can't you read the version before creating the object?

That said, the class's __new__ method can customize what instance is
actually constructed.  Override it to take an optional version
argument (or whatever else you need to pass in to extract the version
from), and use it to select the type that is actually returned.  If
version is omitted, then you would just create the most recent version
as normal.  For example, you might put this in a shared base class:

def __new__(cls, version=None, *args, **kw):
    class_dict = {1: myclass_1, 2: myclass_2, 3: myclass_3}
    cls = class_dict.get(version, cls)
    return object.__new__(cls)

If you're serializing the objects using pickle version 2 or higher,
then you can use a __getnewargs__ method to have it pass the version
argument to __new__ during deserialization:

def __getnewargs__(self):
    return (self.version,)

Alternatively, it is possible to change the class of an object after
it has been created:

def __init__(self, version=None):
    class_dict = {1: myclass_1, 2: myclass_2, 3: myclass_3}
    if version is not None:
        self.__class__ = class_dict[version]

You should only do this if you really know what you're doing, as it
can potentially get your objects into weird states that are hard to
debug.

Cheers,
Ian



More information about the Python-list mailing list