Olá Thiago, não existem atributos privados em Python. O "_" é usado como prefixo em atributos que devem ser considerados como privados - isso é uma convenção entre programadores.
_duracao, no seu caso, não é propriamente privado mas considerado como privado. O prefixo _ apenas alerta que esse atributo não deveria ser chamado fora da classe a que ele pertence, ou seja, deve ser considerado privado.
O mais correto seria criar a propriedade duracao usando a anotação @property dentro da classe e ela retorna o self._duracao:
@property
def duracao(self):
return self .__duracao
E, fora da classe, chamar a propriedade e não o _duracao:
detalhes = programa.duracao if hasattr(programa, 'duracao') else programa.temporada
Isso não quebra o encapsulamento já que está chamando a propriedade e não o atributo diretamente:
Não é diferente de fazer um get_duracao() como você fez. Mas neste caso, para manter o encapsulamento, você deve usar o getter e não o atributo _duracao diretamente:
detalhes = programa.get_duracao() if hasattr(programa, 'get_duracao') else programa.get_temporada()
Dessa maneira, você não expõe o atributo "privado" _duracao. Aqui uso a palavra privado entre aspas já que ele não é extamente privado, mas considerado como tal.
Se ainda não estiver claro, poste suas dúvidas novamente aqui.