Что предпочтительнее: наследование или обёртка?
Парсер в данном случае просто интерфейс. Поскольку Python - язык с динамической типизацией, то наследование или обертки не требуются вовсе. Просто все конкретные парсеры должны реализовать подразумеваемый интерфейс:class CsvParser:
    def parse(self, file_name):

class XlsParser:
    def parse(self, file_name);
Экземпляры конкретных парсеров, по мере их появления складываем в обычный словарь, где ключ - это расширение файла, под которое заточен парсер.{ 'csv': CsvParser(), 'xls': XlsParser(), 'xml': XmlParser() }
В конечном итоге можно реализовать поставщик парсеров, который будет выбирать подходящий парсер из вышеозначенного словаря, используя расширение имени файла:class ParserProvider:
        def provide(file_name):
Есть хорошее правило. 
Если  B является A то это наследование
иначе агрегация
Банально на школьных примерах, стол является предметом мебели, но в него входят столешница, ножки и т.д
А что касается твоего примера. Я бы предпочел вариант на базе 2 но с фабричным/реестровым получением парсера по типу файла.