3

I have a module with several classes which inherit from an import:

# electric_cars.py

from cars import ElectricCar

class Tesla(ElectricCar):
    name = "Tesla"

class Faraday(ElectricCar):
    name = "Faraday"

class Zoe(ElectricCar):
    name = "Zoe"

From a different module, I'm doing the following:

# initiate_cars.py

import electric_cars
import tradi_cars
import flying_cars

import inspect

cls_electric_cars = inspect.getmembers(electric_cars, inspect.isclass)
cls_tradi_cars = inspect.getmembers(tradi_cars, inspect.isclass)
cls_flying_cars = inspect.getmembers(flying_cars, inspect.isclass)

all_cars = []

for cls_car in cls_electric_cars + cls_tradi_cars + cls_flying_cars:
    # inspect.getmembers returns a list of tuples
    # with the class as each tuple's second member
    all_cars.append(cls_car[1])

Everything works well except for one problem: the imports of each module electric_cars, tradi_cars, flying_cars make their way into all_cars.

So that with the above code, all_cars begins:

[
    <class 'car.ElectricCar'>,       # i don't want this
    <class 'cars.electric_cars.Tesla'>,
    <class 'cars.electric_cars.Faraday'>,
    <class 'cars.electric_cars.Zoe'>,
    <class 'car.TradiCar'>,          # i don't want this
    <class 'cars.tradi_cars.Pontiac'>,
    <class 'cars.tradi_cars.Chevrolet'>,
    <class 'cars.tradi_cars.Chrysler'>,
    <class 'car.FlyingCar'>,         # i don't want this
    <class 'cars.flying_cars.SpaceX'>
]

Is there a way, without making a complicated parent-class loading and issubclass checking, to exclude the imports from the classes loaded by inspect.getmembers()?

-- To anticipate on the you-shouldn't-do-that remarks that may arise with such a question, the end goal of this construction is to be able to simply add a class in any of electric_cars.py, tradi_cars.py, or flying_cars.py and have it operational without doing anything else. If you think of any other way of doing that, ideas are welcome.

Jivan
  • 21,522
  • 15
  • 80
  • 131
  • 1
    Wouldn't it be easier to just make `all_cars = ElectricCar.__subclasses__() + TradiCar.__subclasses__() + ...`? Then you don't need to faff around with `inspect` at all. – jonrsharpe Apr 23 '16 at 21:48
  • @jonrsharpe that did the trick - I wasn't aware of this method! If you turn your comment into an answer I'll accept it (which could be useful to other people) - thanks! – Jivan Apr 23 '16 at 21:50
  • 1
    If that's the answer, the question already existed: http://stackoverflow.com/q/3862310/3001761 – jonrsharpe Apr 23 '16 at 21:52
  • the question you're referring is obviously exactly what I was talking about – Jivan Apr 23 '16 at 21:54

1 Answers1

2

One easy solution would be to change how you import ElectricCar in the electric_cars module. Rather than from cars import ElectricCar, you could just import cars and then use a fully qualified name for it in your class statements:

import cars

class Tesla(cars.ElectricCar):
    ...

Another approach would be to write your own predicate value for the inspect.getmembers call you're doing:

inspect.getmembers(electric_cars, lambda x: inspect.isclass(x) and 
                                            x.__module__ == electric_cars.__name__)
Blckknght
  • 100,903
  • 11
  • 120
  • 169