Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate through module's classes (but not imports) in Python [duplicate]

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.

like image 698
Jivan Avatar asked Jan 21 '26 06:01

Jivan


1 Answers

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__)
like image 90
Blckknght Avatar answered Jan 23 '26 20:01

Blckknght