Вопрос не очень понятен, особенно в части "обрабатывать" можно как через try/catch".
Если я правильно понял, то задача - выбросить кастомное исключение, и выбор между проверкой через if и поимкой встроенного TypeError с последующим перевыбросом исключения со своим текстом ошибки.
В этом случае первый вариант однозначно предпочтительнее.
При ловле исключения будет более сложная логика - его надо не только поймать, но и определить что это именно то, которое мы ждём. И если это какое-то другое, то перевыбросить без изменений.
Кроме того, исключения в основном используются в исключительных, непредвиденных ситуациях. А здесь случай вполне предвиденный.
Я бы только инвертировал условие, чтобы во-первых, сделать логику более стройной (проверили - вывалились), а во-вторых, чтобы избавиться от else и убрать лишний отступ.
if not (isinstance(data_set, list) or isinstance(data_set, tuple)):
raise TypeError('argument must be list or tuple')
return sum(data_set) / len(data_set)
Но в целом я бы использовал другой подход.
Если мы хотим свой собственный текст ошибки, то это явно намекает на
валидацию данных с последующим информированием пользователя об ошибке.
А чтобы сделать валидацию, исключения не нужны. Мы просто проверяем полученные данные и выдаём ошибку.
То есть в реальном коде я бы убрал проверку из функции вообще, а проверял данные при их получении (и выводил ошибку).
А на случай, если вдруг функция всё равно будет вызвана с неверным типом аргумента, есть системное исключение, 'type' object is not iterable