Skip to content

Commit 588aef7

Browse files
authored
Merge pull request #317 from eduardoklosowski/artigo
Adiciona artigo: Orientação a objetos de outra forma: Métodos estáticos e de classes
2 parents b1e3fee + 755c5fc commit 588aef7

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

content/oo-de-outra-forma-2.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
Title: Orientação a objetos de outra forma: Métodos estáticos e de classes
2+
Slug: oo-de-outra-forma-2
3+
Date: 2021-04-19 17:00
4+
Category: Python
5+
Tags: python, orientação a objetos
6+
Author: Eduardo Klosowski
7+
8+
Github: eduardoklosowski
9+
Twitter: eduklosowski
10+
Site: https://dev.to/eduardoklosowski
11+
About_author: Programador, formado em redes de computadores e estuda DevOps
12+
13+
Na [postagem anterior](https://dev.to/acaverna/orientacao-a-objetos-de-outra-forma-classes-e-objetos-3mfd) foi apresentado o `self`, nessa postagem será discutido mais a respeito desse argumento, considerando opções para ele e suas aplicações.
14+
15+
## Métodos estáticos
16+
17+
Nem todas as funções de uma classe precisam receber uma referência de um objeto para lê-lo ou alterá-lo, muitas vezes uma função pode fazer o seu papel apenas com os dados passados como argumento, por exemplo, receber um nome e validar se ele possui pelo menos três caracteres sem espaço. Dessa forma, essa função poderia ser colocada fora do escopo da classe, porém para facilitar sua chamada, e possíveis alterações (que será discutido em outra postagem), é possível colocar essa função dentro da classe e informar que ela não receberá o argumento `self` com o decorador `@staticmethod`:
18+
19+
```python
20+
class Pessoa:
21+
... # Demais funções
22+
23+
@staticmethod
24+
def valida_nome(nome):
25+
return len(nome) >= 3 and ' ' not in nome
26+
```
27+
28+
Dessa forma, essa função pode ser chamada diretamente de um objeto pessoa, ou até mesmo diretamente da classe, sem precisar criar um objeto primeiro:
29+
30+
```python
31+
# Chamando diretamente da classe
32+
print(Pessoa.valida_nome('João'))
33+
34+
# Chamando através de um objeto do tipo Pessoa
35+
p1 = Pessoa('João', 'da Silva', 20)
36+
print(p1.valida_nome(p1.nome))
37+
```
38+
39+
E essa função também pode ser utilizada dendro de outras funções, como validar o nome na criação de uma pessoa, de forma que caso o nome informado seja válido, será criado um objeto do tipo Pessoa, e caso o nome seja inválido, será lançado uma exceção:
40+
41+
```python
42+
class Pessoa:
43+
def __init__(self, nome, sobrenome, idade):
44+
if not self.valida_nome(nome):
45+
raise ValueError('Nome inválido')
46+
47+
self.nome = nome
48+
self.sobrenome = sobrenome
49+
self.idade = idade
50+
51+
... # Demais funções
52+
53+
@staticmethod
54+
def valida_nome(nome):
55+
return len(nome) >= 3 and ' ' not in nome
56+
57+
58+
p1 = Pessoa('João', 'da Silva', 20) # Cria objeto
59+
p2 = Pessoa('a', 'da Silva', 20) # Lança ValueError: Nome inválido
60+
```
61+
62+
## Métodos da classe
63+
64+
Entretanto algumas funções podem precisar de um meio termo, necessitar acessar o contexto da classe, porém sem necessitar de um objeto. Isso é feito através do decorador `@classmethod`, onde a função decorada com ele, em vez de receber um objeto como primeiro argumento, recebe a própria classe.
65+
66+
Para demonstrar essa funcionalidade será implementado um *id* auto incremental para os objetos da classe `Pessoa`:
67+
68+
```python
69+
class Pessoa:
70+
total_de_pessoas = 0
71+
72+
@classmethod
73+
def novo_id(cls):
74+
cls.total_de_pessoas += 1
75+
return cls.total_de_pessoas
76+
77+
def __init__(self, nome, sobrenome, idade):
78+
self.id = self.novo_id()
79+
self.nome = nome
80+
self.sobrenome = sobrenome
81+
self.idade = idade
82+
83+
p1 = Pessoa('João', 'da Silva', 20)
84+
print(p1.id) # Imprime 1
85+
p2 = Pessoa('Maria', 'dos Santos', 18)
86+
print(p2.id) # Imprime 2
87+
print(Pessoa.total_de_pessoas) # Imprime 2
88+
print(p1.total_de_pessoas) # Imprime 2
89+
print(p2.total_de_pessoas) # Imprime 2
90+
```
91+
92+
Nesse código é criado uma variável `total_de_pessoas` dentro do escopo da classe `Pessoas`, e que é compartilhado tanto pela classe, como pelos objetos dessa classe, diferente de declará-la com `self.` dentro do `__init__`, onde esse valor pertenceria apenas ao objeto, e não é compartilhado com os demais objetos. Declarar variáveis dentro do contexto da classe é similar ao se declarar variáveis com `static` em outras linguagens, assim como o `@classmethod` é semelhante a declaração de funções com `static`.
93+
94+
As funções declaradas com `@classmethod` também podem ser chamadas sem a necessidade de se criar um objeto, como `Pessoa.novo_id()`, embora que para essa função específica isso não faça muito sentido, ou receber outros argumentos, tudo depende do que essa função fará.
95+
96+
## Considerações
97+
98+
Embora possa parecer confuso identificar a diferença de uma função de um objeto (função sem decorador), função de uma classe (com decorador `@classmethod`) e função sem acesso a nenhum outro contexto (com decorador `@staticmethod`), essa diferença fica mais clara ao se analisar o primeiro argumento recebido por cada tipo de função. Podendo ser a referência a um objeto (`self`) e assim necessitando que um objeto seja criado anteriormente, ser uma classe (`cls`) e não necessitando receber um objeto, ou simplesmente não recebendo nenhum argumento especial, apenas os demais argumentos necessários para a função. Sendo diferenciados pelo uso dos decoradores.
99+
100+
Na orientação a objetos implementada pelo Python, algumas coisas podem ficar confusas quando se mistura com nomenclaturas de outras linguagens que possuem implementações diferentes. A linguagem Java, por exemplo, utiliza a palavra-chave `static` para definir os atributos e métodos de classe, enquanto no Python um método estático é aquele que não acessa nem um objeto, nem uma classe, devendo ser utilizado o escopo da classe e o decorador `@classmethod` para se criar atributos e métodos da classe.
101+
102+
---
103+
104+
Esse artigo foi publicado originalmente no [meu blog](https://eduardoklosowski.github.io/blog/), passe por lá, ou siga-me no [DEV](https://dev.to/eduardoklosowski) para ver mais artigos que eu escrevi.

0 commit comments

Comments
 (0)