Skip to content

Commit

Permalink
feat: seção sobre atributos de classe iniciada em POO
Browse files Browse the repository at this point in the history
  • Loading branch information
HenriqueAJNB committed Oct 9, 2024
1 parent cf34ee7 commit 4347443
Show file tree
Hide file tree
Showing 2 changed files with 283 additions and 0 deletions.
282 changes: 282 additions & 0 deletions book/10-orientacao-objetos/02-atributo-classe.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Atributos de classes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vimos que podemos definir atributos de instância em uma classe, que são variáveis que pertencem a cada objeto da classe. Mas também podemos definir atributos de classe, que são variáveis que pertencem à classe em si, e não a cada objeto da classe. A diferença é que os atributos de classe são compartilhados por todos os objetos da classe. \n",
"\n",
"Eu sei que é difícil entender isso só com palavras, então vamos ver um exemplo."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Carro:\n",
" quantidade_rodas: int = 4\n",
"\n",
" def __init__(self, marca: str, modelo: str):\n",
" self.marca = marca\n",
" self.modelo = modelo\n",
"\n",
"\n",
"corolla = Carro(\"Toyota\", \"Corolla\")\n",
"civic = Carro(\"Honda\", \"Civic\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O que há de diferente no código acima? Percebam que o atributo `quantidade_rodas` é definido dentro da classe, porém fora do método `__init__` e sem usar a referência à instância `self` com a notação de ponto `self.quantidade_rodas`. O que isso quer dizer? Isso significa que ele é um atributo de classe e não de instância. Por ele ser um atributo de classe, significa que todas as instâncias da classe `Carro` compartilham o mesmo valor para `quantidade_rodas`.\n",
"\n",
"Por ele ser um atributo de classe, significa que todas as instâncias da classe `Carro` compartilham o mesmo valor para `quantidade_rodas`. Tal valor pode ser acessado por cada uma das instâncias ou a partir da própria classe com a notação de ponto `Carro.quantidade_rodas`."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4\n",
"4\n"
]
}
],
"source": [
"class Carro:\n",
" quantidade_rodas: int = 4\n",
"\n",
" def __init__(self, marca: str, modelo: str):\n",
" self.marca = marca\n",
" self.modelo = modelo\n",
"\n",
"\n",
"corolla = Carro(\"Toyota\", \"Corolla\")\n",
"civic = Carro(\"Honda\", \"Civic\")\n",
"\n",
"# Todas as instâncias compartilham o mesmo valor do atributo de classe quantidade_rodas\n",
"print(Carro.quantidade_rodas) # 4\n",
"print(corolla.quantidade_rodas) # 4\n",
"print(civic.quantidade_rodas) # 4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podemos mudar de forma global o valor de `quantidade_rodas` para todas as instâncias da classe `Carro`, e isso será refletido em todas as instâncias. Nem sempre isso é desejado e é por isso que devemos ter cuidado ao usar atributos de classe principalmente quando alteramos tal valor."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Atributo de classe quantidade_rodas antes da alteração de valor\n",
"Corolla tem 4 rodas\n",
"Civi tem 4 rodas\n",
"---\n",
"Alteramos o valor do atributo de classe quantidade_rodas para 5\n",
"---\n",
"Instâncias criadas antes da alteração de valor do atributo de classe\n",
"Corolla tem 5 rodas\n",
"Civi tem 5 rodas\n",
"Instância criada após a alteração de valor do atributo de classe\n",
"Gol tem 5\n"
]
}
],
"source": [
"class Carro:\n",
" quantidade_rodas: int = 4\n",
"\n",
" def __init__(self, marca: str, modelo: str):\n",
" self.marca = marca\n",
" self.modelo = modelo\n",
"\n",
"\n",
"corolla = Carro(\"Toyota\", \"Corolla\")\n",
"civic = Carro(\"Honda\", \"Civic\")\n",
"\n",
"print(\"Atributo de classe quantidade_rodas antes da alteração de valor\")\n",
"print(f\"Corolla tem {corolla.quantidade_rodas} rodas\") # 4\n",
"print(f\"Civi tem {civic.quantidade_rodas} rodas\") # 4\n",
"\n",
"# Alterando o valor do atributo de classe quantidade_rodas.\n",
"# Isso terá reflexo tanto em instâncias criadas antes da\n",
"# alteração quanto em instâncias criadas após a alteração!\n",
"print(\"---\")\n",
"print(\"Alteramos o valor do atributo de classe quantidade_rodas para 5!\")\n",
"print(\"---\")\n",
"\n",
"Carro.quantidade_rodas = 5\n",
"\n",
"gol = Carro(\"Volkswagen\", \"Gol\")\n",
"\n",
"print(\"Instâncias criadas antes da alteração de valor do atributo de classe\")\n",
"print(f\"Corolla tem {corolla.quantidade_rodas} rodas\") # 5\n",
"print(f\"Civi tem {civic.quantidade_rodas} rodas\") # 5\n",
"\n",
"print(\"Instância criada após a alteração de valor do atributo de classe\")\n",
"print(f\"Gol tem {gol.quantidade_rodas} rodas\") # 5"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Atributos de classe são úteis para definir valores que são compartilhados por todas as instâncias da classe, como por exemplo, valores padrão que são comuns a todas as instâncias. Porém, é preciso ter muito cuidado ao alterar tais valores, pois isso pode causar efeitos colaterais inesperados, conforme vimos acima.\n",
"\n",
"Vamos ver um exemplo real de aplicação de atributos de classe."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Salários iniciais:\n",
"10000\n",
"10000\n",
"10000\n",
"\n",
"Salários após aumento de 5% para todos os sêniors da empresa:\n",
"10500.0\n",
"10500.0\n",
"10500.0\n",
"\n",
"Salários após bônus individual para Carlos:\n",
"10500.0\n",
"11500.0\n",
"10500.0\n"
]
}
],
"source": [
"# 1\n",
"class Senior:\n",
" # 2\n",
" salario_base = 10_000\n",
"\n",
" # 3\n",
" def __init__(self, nome: str, id_funcionario: int, anos_experiencia: int):\n",
" self.nome = nome\n",
" self.id_funcionario = id_funcionario\n",
" self.anos_experiencia = anos_experiencia\n",
" self.bonus_individual = 0\n",
"\n",
" # 4\n",
" def calcular_salario(self) -> int:\n",
" return Senior.salario_base + self.bonus_individual\n",
"\n",
" # 5\n",
" def aplicar_bonus(self, valor: int) -> None:\n",
" self.bonus_individual += valor\n",
"\n",
"\n",
"# 6\n",
"senior1 = Senior(nome=\"Ana Silva\", id_funcionario=1, anos_experiencia=8)\n",
"senior2 = Senior(nome=\"Carlos Oliveira\", id_funcionario=2, anos_experiencia=10)\n",
"senior3 = Senior(nome=\"Mariana Santos\", id_funcionario=3, anos_experiencia=7)\n",
"\n",
"# 7\n",
"print(\"Salários iniciais:\")\n",
"print(senior1.calcular_salario())\n",
"print(senior2.calcular_salario())\n",
"print(senior3.calcular_salario())\n",
"\n",
"# 8\n",
"Senior.salario_base = Senior.salario_base * (1 + 5 / 100)\n",
"\n",
"# 9\n",
"print(\"\\nSalários após aumento de 5% para todos os sêniors da empresa:\")\n",
"print(senior1.calcular_salario())\n",
"print(senior2.calcular_salario())\n",
"print(senior3.calcular_salario())\n",
"\n",
"# 10\n",
"senior2.aplicar_bonus(1_000)\n",
"\n",
"# 11\n",
"print(\"\\nSalários após bônus individual para Carlos:\")\n",
"print(senior1.calcular_salario())\n",
"print(senior2.calcular_salario())\n",
"print(senior3.calcular_salario())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos entender o código acima com calma. Vá acompanhando pelas numerações no código e a respectiva explicação abaixo.\n",
"\n",
"1. Criamos a classe `Senior`, que representa um colaborador sênior de uma empresa\n",
"2. Definimos o atributo de classe `10_000`. Todos os sêniors da empresa recebem o mesmo salário.\n",
"3. O método construtor define os atributos de instância `nome`, `id_funcionario`, `anos_experiencia` e `bonus_individual`.\n",
"4. Temos um método que calcula o salário do colaborador sênior. O salário é a soma do salário base mais o bônus individual.\n",
"5. Temos um outro método que acrescenta um valor ao bônus individual do colaborador sênior com base em um parâmetro informado.\n",
"6. Criamos 3 funcionários seniores.\n",
"7. Imprimimos os salários iniciais de cada um deles. Todos são iguais até aqui.\n",
"8. **Aplicamos um aumento de 5% para todos os seniores modificando o atributo de classe.**\n",
"9. Imprimimos novamente os salários de cada um deles. Todos tiveram um aumento de 5%.\n",
"10. Configuramos um bônus individual para um dos seniores.\n",
"11. Imprimimos novamente os salários de cada um deles. Apenas o salário do senior, que teve o bônus individual aplicado, foi alterado.\n",
"\n",
"O passo 8 é o principal, pois refere-se ao tópico desta seção. Ele poderia ser muito bem definido como uma regra igualitária da empresa na qual todos os colaboradores sêniores recebem um aumento de 5% no salário. Isso é um exemplo de aplicação de atributos de classe.\n",
"\n",
"Mas novamente, notem que ao alterar o atributo de classe, literalmente **todas as instâncias**, tanto aquelas criadas antes da alteração quanto as criadas após a alteração do atributo de classe **são afetadas.**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ⚒️👷 (WIP) capítulo em construção ⚒️👷"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
1 change: 1 addition & 0 deletions book/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ parts:
- caption: Programação orientada a objetos
chapters:
- file: 10-orientacao-objetos/01-introducao.ipynb
- file: 10-orientacao-objetos/02-atributo-classe.ipynb

- caption: Pratique
chapters:
Expand Down

0 comments on commit 4347443

Please sign in to comment.