badmaash
badmaash

Reputation: 4845

Using reflection to peep into a module and its classes

I've got a problem which is a bit difficult to explain. I have a module which consists of more than one class: someModule.py

#imports over here
class Default(Base):
 def __init__(self):
   a = Rectangle() #all these guys derive from Shape
   b = Circle()
   c = Sphere()

class Foo:
 #members over here

#other classes/functions/whatever we can define here, except the boiler plate code to check __main__

What i want to do is create an object of the class which derives from a specific base class (eg. Base) at run time and manipulate those data members which derive from another specific base class (eg. Shape). Meaning i want to write such a script that takes module name and performs the above task. Any ideas how i can do this using inspect or something else? I've taken a look at inspect but didn't quite find the methods that should get the job done. I may be missing something.

Upvotes: 3

Views: 149

Answers (2)

Rik Poggi
Rik Poggi

Reputation: 29302

There is no way to know what's inside __init__ before the creation of the instance.

You can only check them after, and one way to do it is with vars():

defy = Default()
for name,value in vars(defy).items():
    if isinstance(value, Shape):
        # manipulate

To do the above on all the classes in someModule.py that are also subclasses of Base:

import someModule

instances = []
for cls_name,cls in vars(someModule):
    if issubclass(cls, Base):
        obj = cls()
        for name,value in vars(cls).items():
            if isinstance(value, Shape):
                # manipulate
        instances.append(obj)

Instead, if you want to manipulate which Shape subclass is going to be instanciated, you'll have to make them class attributes, example:

class Default(Base):
    default_shapes = [Rectangle, Circle, Sphere]
    def __init__(self):
        self.shapes = [shape() for shape in self.__class__.default_shapes]

Upvotes: 1

voithos
voithos

Reputation: 70552

Here's one way: make sure that your base classes (e.g. Base, Shape) are new-style classes (they inherit from object). By doing so, you can use the built-in __subclasses__() function to get a list of all derived classes. Then you can simply create an object and go through the fields, comparing them with the classes that you're interested in.

baseDerived = Base.__subclasses__()
shapeDerived = Shape.__subclasses__()

# Iterate through derived classes
for derivedClass in baseDerived:
    derivedObject = derivedClass()

    # Iterate through data attributes
    for attr, dataMember in derivedObject.__dict__.iteritems():
        if dataMember.__class__ in shapeDerived:
            # Do stuff with the data member here

Upvotes: 0

Related Questions