Olá Franco, tudo bem? Apenas para reforçar o seu posicionamento, concordo que a situação acima não seja um boa prática para a maioria dos contextos, a implementação de getters e setters com uso dos decorators @property e *@codigo.setter* é mais elagante.
Mas segue uma pequena correção no teu questionamento, o atributo _codigo com apenas um underscore deve ser entendido como um atributo de visibilidade protegida, já os atributos privados com dois underscores.
Referencia: Encapsulamento Apostila de Python da Caelum
Dessa forma, se o design da classe Cliente foi projetada com a intenção de deixar o atributo codigo como protegido, eu pessoalmente não desencorajaria a atribuição como está, ao invés disso questionaria se não seria a visibilidade da variável _codigo que poderia estar errada.
Reitero que concordo com seu posicionamento, a única ressalva que levanto para insentivar ou não, é o quê design do objeto quis nos expressar configurando o codigo como um atributo protegido.