К слову:
self.name = name if type(name) == 'str' else str(name)
- у вас всегда будет False(если только владельца не зовут str).
Правильный вариант:
self.name = name if isinstance(name, str) else str(name)
А так, эта проверка здесь вообще не нужна, так как в функции new_owner вы используете везде input-ы, которые возвращают строки.
В Vehincle и new_vehicle аналогичная ситуация.
Так же
return ''.join(self.name + ' ' + self.phone_number + ' ' + str(self.age))
пишите либо так:
return ' '.join((self.name, phone_number, str(self.age)))
либо так:
return self.name + ' ' + self.phone_number + ' ' + str(self.age)
или лучше вот так:
return f'{self.name} {self.phone_number} {self.age}'
а можно и:
return '{0} {1} {2}'.format(self.name, self.phone_number, self.age)
Касательно самого вопроса,
data_autowner[auto_owner.name] = auto_owner, auto_vehicle
здесь auto_owner и auto_vehicle это объекты классов, так как ты переопределил их методы __str__ - при печати самих объектов все будет ок, но ты засовываешь эти объекты в словарь, а потом печатаешь САМ СЛОВАРЬ (а это значит что к объектам словаря будет применен repr), поэтому и получаешь то что получаешь. Т.е. если ты сделаешь вот так
data_autowner[auto_owner.name] = str(auto_owner), str(auto_vehicle)
то получишь то что хочешь.
Но так делать это дурной тон(мягко говоря), лучше переопредели еще __repr__, точно так же как ты сделал с __str__.
def __repr__(self):
return ' '.join((self.name, self.phone_number, str(self.age)))