chamada precisa ter os parenteses no final. Portanto, e um metodo getter.Se eu quiser que esse detalhe fique realmente escondido, preciso usar uma _property_. Veja o exemplo abaixo: class Pessoa: def __init__(self, nome, sobrenome): self.nome = nome self.sobrenome = sobrenome @property def nome_completo(self): return "%s %s" % (self.nome, self.sobrenome)Agora, para voce pegar o nome completo, basta usar `pessoa.nome_completo` (sem o `get_` inicial e sem os parenteses no final). Para quem usa a classe, usar `pessoa.nome` ou `pessoa.nome_completo` ficou igual. Sem olhar o codigo fonte da classe ninguem sabe como `nome_completo` foi implementado. Se e um atributo normal ou se e uma property. O decorator `@property` faz com que um metodo da classe possa ser acessado como se fosse um atributo. Isso e encapsulamento de verdade!Mas eu posso querer mais detalhes na implementacao da classe `Pessoa`. Por exemplo, o atributo `nome` precisa comecar com uma letra maiuscula. Como fazer isso se estou acessando `pessoa.nome` diretamente? Simples. Basta criarmos outra property. Agora, para o nome: class Pessoa: def __init__(self, nome, sobrenome): self.nome = nome self.sobrenome = sobrenome @property def nome(self): return self._nome @nome.setter def nome(self, value): self._nome = value.capitalize() @property def nome_completo(self): return "%s %s" % (self.nome, self._sobrenome)Para usar essa classe, vamos trabalhar com um exemplo no REPL do Python: >>> a = Pessoa(nome="felipe", sobrenome="da silva") >>> a.nome Felipe >>> a.nome_completo Felipe da silva >>> >>> a.nome = "roberto" >>> a.nome Roberto >>> a.nome_completo Roberto da silva >>> >>> a.nome_completo = "qualquer coisa" Traceback (most recent call last): File "", line 1, in AttributeError: can't set attribute can't set attributeNote os detalhes dessa implementacao: - O nome da pessoa esta guardado no atributo `_nome`. E isso fica completamente encapsulado dentro da property `nome`. - Podemos usar `nome` como se fosse um atributo simples, tanto para pegar o valor, quanto para atribuir um valor. - O atributo `sobrenome` esta sendo acessado diretamente, pois nao temos nenhuma regra especial para ele. - O nome completo e uma property _"read only"_.Se nao usassemos uma property, precisariamos criar um metodo `set_nome()`, com o mesmo resultado. Mas havemos de concordar que a sintaxe da property e muito mais intuitiva para quem usa a classe, nao e?No futuro, se tivermos alguma particularidade para o atributo `sobrenome`, podemos mudar a implementacao da classe sem afetar nenhum codigo externo, simplesmente usando outra property; dessa vez para o sobrenome.As properties sao muitos uteis quando utilizadas em lugar de metodos que retornam algum estado da classe. Por exemplo: - property `is_active` ao inves de um metodo `is_active()` - `is_valid` ao inves de `is_valid()` - `nome_completo` ao inves de `get_nome_completo()` - `contatos` ao inves de `get_contatos()`Vejamos agora um caso real e bem simples onde eu uso properties para retornar estados da minha propria classe de exception. >>> class MinhaException(Exception): ... @property ... def code(self): ... return self.args[0] ... @property ... def message(self): ... return self.args[1] ... >>> try: ... raise MinhaException("003", "Campo obrigatorio") ... except MinhaException as e: ... print ("Erro %s (%s)" % (e.code, e.message)) ... >>>O exemplo acima cria duas properties, `code` e `message`, para abstrair a forma como esse atributos sao guardados