- Aprender
- Computação e TI
- Programação
- Introdução à programação com Python
- Programação orientada a objetos em Python
Introdução à programação orientada a objetos em Python
==, ordenados e somados com + por meio de métodos especiais, crie programas em que objetos armazenam e chamam outros objetos e avalie quando uma classe torna um programa mais claro do que funções e dicionários.BásicoAula 10 de 10 do curso Curso de Introdução à programação com Python
O que você vai aprender
- Veja que todo valor em Python é um objeto com seus próprios dados e métodos, depois escreva sua própria classe e crie objetos a partir dela.
- Reconheça os objetos que você já usaDescreva strings, listas e dicionários como objetos que têm um tipo, armazenam dados e oferecem métodos que você chama com a notação com ponto.
- Defina uma classe e crie instânciasEscreva uma instrução de classe, crie vários objetos distintos a partir dela e defina e leia seus atributos com a notação com ponto.
- Reconheça os objetos que você já usa
- Use um construtor para dar a cada novo objeto os atributos de que ele precisa, escolha entre atributos de instância e de classe e impeça a criação de objetos inválidos.
- Escreva um construtor com __init__ e selfDefina
__init__para que cada novo objeto comece com seus próprios atributos, obtidos dos argumentos ou definidos com valores iniciais. - Escolha entre atributos de instância e atributos de classeDecida se um valor pertence a cada objeto ou à classe como um todo e preveja como o Python encontra e altera cada tipo.
- Mantenha objetos válidos desde o inícioVerifique os argumentos que um construtor recebe, lance uma exceção clara para valores inválidos e mantenha as regras que dão sentido a um objeto.
- Escreva um construtor com __init__ e self
- Escreva métodos que usam e alteram os dados de um objeto e proteja esses dados contra alterações que tornariam o objeto inválido.
- Defina e chame métodos de instânciaEscreva métodos que trabalham com
self, chame-os em objetos e retorne resultados em vez de imprimi-los. - Altere o estado de um objeto com métodosEscreva métodos que atualizam atributos mantendo o objeto válido e preveja quando uma alteração fica visível por meio de outros nomes para o mesmo objeto.
- Proteja atributos com convenções de nomenclatura e propriedadesMarque atributos como internos com um sublinhado e use propriedades para verificar novos valores ou calcular valores que permanecem atualizados.
- Defina e chame métodos de instância
- Escreva métodos especiais que permitam aos seus objetos mostrar texto legível, ser comparados com
==e<e funcionar com operadores e funções embutidas.- Dê aos objetos representações em string legíveisEscreva
__str__e__repr__para que os objetos mostrem texto útil quando forem impressos, inspecionados ou armazenados em uma lista. - Compare e combine objetos com operadoresDefina
__eq__,__lt__,__add__e__len__para que seus objetos funcionem com==, ordenação,+elen(), e decida quando um operador é mais claro do que um método nomeado.
- Dê aos objetos representações em string legíveis
- Combine objetos para que cada um cuide de seus próprios dados, rastreie programas em que objetos chamam uns aos outros e decida quando uma classe torna um programa mais claro.
- Crie objetos que contenham outros objetosArmazene objetos como atributos ou em listas dentro de outro objeto e escreva métodos que trabalhem com toda a coleção.
- Faça objetos interagirem por meio de métodosPasse objetos para métodos e funções, retorne novos objetos e rastreie um programa curto em que vários objetos trabalham juntos.
- Decida quando uma classe torna um programa mais claroAvalie quando reunir dados e comportamento em uma classe ajuda, planeje uma classe pequena a partir de uma descrição e reescreva código baseado em dicionários como uma classe.
- Crie objetos que contenham outros objetos
Guia de estudo de Programação orientada a objetos em Python
1Entenda objetos e defina sua primeira classe
Objetos já aparecem em todos os programas Python que você escreve: uma string tem métodos, uma lista altera seu conteúdo e um dicionário responde a consultas por chave. Interpretar essas operações familiares como comportamento de objetos oferece um ponto de partida para suas próprias classes. Aprenda como tipos, identidade e referências compartilhadas afetam um programa, depois defina uma classe pequena e dê a instâncias distintas seus próprios atributos.
1.1 Reconheça os objetos que você já usa
Você já usou objetos sempre que trabalhou com um número, uma string, uma lista ou um dicionário. Um objeto tem um tipo, um valor ou estado e operações que aceita. Até funções e None são objetos. Escrever sua própria classe amplia esse sistema familiar.
Encontre o tipo e os métodos de um objeto
type("hello") retorna <class 'str'>; type([1, 2]) retorna <class 'list'>. As palavras tipo e classe descrevem o mesmo papel aqui. isinstance(3.5, float) é True, enquanto isinstance("3.5", float) é False: o segundo valor é texto, embora pareça numérico.
Um método é uma função fornecida por um tipo. Em "ada lovelace".title(), a string antes do ponto é o objeto, title é o método e os parênteses o chamam. O resultado é "Ada Lovelace". dir(value) lista os nomes oferecidos por um objeto; nomes como __len__ são métodos especiais que ligam objetos a operações do Python como len(value).
Acompanhe o resultado e o original
Uma chamada de método pode retornar um resultado, alterar um objeto ou fazer ambos. Verifique o comportamento do método antes de decidir o que atribuir.
word = "level"
print(word.count("l")) # 2
print(word.upper()) # LEVEL
print(word) # level
nums = [3, 1, 2]
result = nums.sort()
print(nums) # [1, 2, 3]
print(result) # None
Strings são imutáveis: seu conteúdo não pode mudar. upper() retorna outra string, então word mantém seu valor original. Para manter o resultado em maiúsculas sob esse nome, escreva word = word.upper().
Listas são mutáveis. sort() altera a própria lista e retorna None. Escrever nums = nums.sort() perde a referência à lista armazenada em nums e atribui None. Use nums.sort() em uma linha própria ou nums = sorted(nums) para obter uma nova lista ordenada. Para um dicionário, {"a": 1}.get("b", 0) retorna 0 porque a chave solicitada está ausente.
Parênteses também importam. word.upper é um objeto de método; word.upper() o executa. O mesmo comportamento pode ser oferecido por muitos objetos: "cat".upper() e "dog".upper() usam um mesmo tipo de método com dados de string diferentes.
Distinga igualdade de identidade
Igualdade verifica se os valores correspondem. Identidade verifica se dois nomes se referem a um mesmo objeto.
a = [1, 2]
b = [1, 2]
c = a
print(a == b) # True
print(a is b) # False
print(c is a) # True
c.append(3)
print(a) # [1, 2, 3]
print(b) # [1, 2]
a e b começam com conteúdos iguais, mas são listas separadas. c = a cria uma referência alternativa, outro nome para a mesma lista. Adicionar um item por meio de c altera o objeto ao qual a também se refere. Isso não altera a lista separada armazenada em b. Ao rastrear um programa, desenhe uma caixa por objeto e uma seta de cada nome até sua caixa.
Principais conclusões
- Todo valor em Python é um objeto com tipo, estado e operações que aceita.
- Chame um método com parênteses; uma referência ao método, sozinha, não o executa.
- Verifique se um método retorna um novo valor ou altera o objeto existente.
==compara valores;iscompara identidade.- Uma atribuição pode fazer dois nomes se referirem ao mesmo objeto mutável.
1.2 Defina uma classe e crie instâncias
Uma classe define um tipo que você pode usar em seu próprio programa. Cada objeto criado a partir dela é uma instância. Uma classe descreve o tipo de coisa; as instâncias armazenam os dados de coisas específicas. Um formulário em branco e suas cópias preenchidas são uma comparação útil.
Escreva uma classe e chame-a
Uma instrução de classe tem a palavra reservada class, um nome, dois-pontos e um corpo indentado. pass fornece um corpo vazio enquanto você experimenta a estrutura.
class Book:
pass
b1 = Book()
b2 = Book()
print(b1 is b2) # False
print(isinstance(b1, Book)) # True
Cada chamada Book() cria uma instância separada. Em um script, type(b1) mostra <class '__main__.Book'>. A instrução de classe deve ser executada antes que o código tente usar Book. Você também pode definir uma classe em um módulo e importá-la com from library import Book, depois criar instâncias no programa chamador.
Siga as convenções de nomenclatura do Python: Book, BankAccount e ShoppingCart usam CapWords, com cada palavra iniciada por maiúscula. Variáveis e métodos usam palavras minúsculas separadas por sublinhados, como book_count e add_item. Use quatro espaços para cada nível de indentação.
Armazene dados em cada instância
Um atributo é um valor nomeado acessado com um ponto. Atribuir um atributo o armazena; ler o mesmo nome recupera seu valor.
b1.title = "Dune"
b2.title = "Emma"
b1.pages = 412
print(b1.title) # Dune
print(b2.title) # Emma
print(b1.pages) # 412
Os dados pertencem à instância selecionada. Dar a b1 um atributo pages não dá um a b2. Ler b2.pages agora provoca AttributeError, pois esse objeto não tem um atributo chamado pages.
Atribuições podem criar novos nomes sem verificar sua intenção. Depois de b1.titel = "X", o b1.title original ainda armazena "Dune"; o objeto ganhou um segundo atributo com um nome escrito incorretamente. Se um valor parecer não mudar, compare a escrita no ponto em que ele foi atribuído e no ponto em que foi lido.
Mantenha a classe e suas instâncias distintas
| Expressão | Significado |
|---|---|
Book | O objeto de classe, que define o tipo |
Book() | Uma chamada que cria uma instância |
b1.title | O título armazenado neste livro |
Book.title | Um atributo solicitado na própria classe |
b = Book dá outro nome à classe. Isso não cria um livro. Se os títulos foram definidos apenas nas instâncias, pedir Book.title provoca AttributeError; não há um único título compartilhado pelo tipo.
Dê a todo objeto um início confiável
Definir atributos de fora é possível, mas deixa a configuração espalhada pelo programa. Um livro pode receber um título e uma contagem de páginas, enquanto outro recebe apenas um título. O código posterior não pode pressupor com segurança que ambos têm pages.
Um método de configuração chamado __init__ coloca as atribuições iniciais dentro da classe. Cada chamada de criação segue então o mesmo processo de configuração. A classe pode exigir um título e criar outros atributos com valores iniciais adequados, para que o código chamador não precise lembrar uma sequência separada de atribuições.
Principais conclusões
- Uma classe define um tipo; uma instância é um objeto criado a partir dela.
- Use
ClassName()para criar uma instância e a notação com ponto para acessar seus atributos. - Cada instância pode armazenar dados diferentes sob os mesmos nomes de atributos.
- Um atributo ausente provoca
AttributeError; uma atribuição com nome escrito incorretamente pode criar um novo atributo.
2Configure objetos com construtores e atributos
Um objeto precisa de um estado inicial confiável antes que seus métodos possam realizar tarefas úteis. A inicialização conecta os argumentos de uma chamada de classe aos atributos armazenados na nova instância. Escolha quais valores pertencem a um objeto e quais pertencem à classe, depois valide as entradas antes de aceitá-las. Rastrear buscas e falhas de configuração ajudará você a identificar compartilhamento acidental e dados ausentes.
2.1 Escreva um construtor com __init__ e self
Toda conta recém-criada precisa de um titular e de um saldo inicial. Colocar essa configuração em __init__ dá a cada objeto os atributos que os métodos posteriores esperam. O Python cria a instância primeiro e depois chama __init__ para inicializá-la.
Conecte argumentos a atributos
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
self.transactions = []
acct = BankAccount("Maya", 50)
other = BankAccount("Leo")
Na primeira chamada, o Python passa a nova conta como self, "Maya" como owner e 50 como balance. As atribuições fazem acct.owner ser igual a "Maya" e acct.balance ser igual a 50. A segunda chamada usa o saldo padrão, então other.balance é 0.
self é o parâmetro que recebe o objeto atual. É uma convenção, não uma palavra reservada do Python. Use esse nome para que os leitores reconheçam o objeto imediatamente. O código chamador o deixa de fora: BankAccount("Maya", 50) fornece dois argumentos, não três.
Mantenha nomes locais e dados armazenados separados
Em self.owner = owner, o nome à direita é um parâmetro local. O nome à esquerda é um atributo armazenado no objeto. Quando a inicialização termina, outros métodos ainda podem usar self.owner.
Escrever balance = balance apenas reatribui o nome local. Isso não cria um atributo, então ler acct.balance depois falha. Coloque self. antes de cada atributo que deve permanecer como parte do objeto.
Planeje a inicialização listando o que cada instância precisa. Valores obrigatórios tornam-se parâmetros após self; valores opcionais podem ter padrões. Valores que sempre começam da mesma forma podem ser atribuídos no corpo, como self.visits = 0. Uma lista criada por self.transactions = [] é criada novamente em cada chamada.
Evite uma lista padrão compartilhada
Um argumento padrão é avaliado quando o Python define o método. Com def __init__(self, items=[]), chamadas que omitem items recebem a mesma lista. Se o inicializador armazenar essa lista diretamente, alterar os itens de um objeto altera os itens vistos por outro.
Use None como padrão e crie uma nova lista durante cada chamada:
class Cart:
def __init__(self, items=None):
self.items = [] if items is None else list(items)
a = Cart()
b = Cart()
a.items.append("pen")
print(b.items) # []
list(items) também cria uma nova lista externa quando o código chamador fornece uma. Os objetos dentro dessa lista ainda são referências compartilhadas; criar a lista não recria cada item.
Leia erros de configuração
Em BankAccount() falta o argumento obrigatório owner, o que provoca TypeError. Compare a chamada com os parâmetros após self.
A grafia __init__ tem dois sublinhados de cada lado. _init_ é um nome de método comum e não realiza essa configuração automaticamente. __init__ deve retornar None, então normalmente deixe de fora uma instrução de retorno. Retornar um saldo provoca TypeError; a própria chamada da classe fornece a nova instância ao código chamador.
Principais conclusões
__init__inicializa a instância depois que o Python a cria.- O Python fornece
self; o código chamador fornece os argumentos restantes. self.name = namearmazena um parâmetro como atributo de instância.- Crie listas individuais das instâncias durante a inicialização; use
Noneem vez de um valor padrão mutável. __init__deve retornarNone.
2.2 Escolha entre atributos de instância e atributos de classe
Alguns valores descrevem um objeto; outros descrevem o tipo como um todo. O tamanho de uma pizza pertence àquela pizza. Um limite de ingredientes ou uma contagem de pizzas criadas pode pertencer à classe. O local de uma atribuição determina que tipo de atributo ela cria.
Coloque o valor no lugar certo
class Pizza:
MAX_TOPPINGS = 5
count = 0
def __init__(self, size):
self.size = size
self.toppings = []
Pizza.count += 1
p1 = Pizza("large")
p2 = Pizza("small")
size e toppings são atributos de instância, definidos em self. Cada pizza tem seus próprios valores. MAX_TOPPINGS e count são atributos de classe, atribuídos no corpo da classe fora de um método. Letras maiúsculas indicam um valor destinado a ser uma constante; elas não impedem a reatribuição.
Após essas chamadas, Pizza.count é 2. Cada inicializador atualiza o mesmo atributo de classe. p1.size é "large", enquanto p2.size é "small".
Rastreie a busca e o sombreamento
Para atributos de dados comuns como esses, a leitura de p1.MAX_TOPPINGS verifica primeiro a instância e depois a classe. Como nenhum valor está armazenado em p1, o Python encontra Pizza.MAX_TOPPINGS, que é 5.
Uma atribuição por meio de uma instância tem outro efeito:
p1.MAX_TOPPINGS = 8
Pizza.MAX_TOPPINGS = 6
print(p1.MAX_TOPPINGS) # 8
print(p2.MAX_TOPPINGS) # 6
print(Pizza.MAX_TOPPINGS) # 6
A primeira linha cria um atributo de instância em p1. Ele sombreia o valor de classe para esse objeto. Alterar o valor de classe depois alcança p2, que ainda lê da classe, mas não substitui o valor próprio de p1.
| Atribuição | O que muda |
|---|---|
self.size = size | Dados na instância atual |
Pizza.count += 1 | O contador compartilhado da classe |
p1.MAX_TOPPINGS = 8 | Um valor de instância que oculta o valor de classe |
Observe duas formas de compartilhamento acidental
Se o inicializador usasse self.count += 1, o Python leria o 0 da classe, somaria um e armazenaria um atributo de instância. Cada nova pizza receberia seu próprio count de 1, enquanto Pizza.count permaneceria em 0. Use o nome da classe ao atualizar um contador de toda a classe.
Uma lista no corpo da classe causa um problema diferente. Com toppings = [], as instâncias que não têm um atributo separado para ingredientes encontram todas a mesma lista. p1.toppings.append("olives") altera essa lista compartilhada; não atribui um novo atributo de instância. Coloque self.toppings = [] em __init__ quando cada pizza precisar de seus próprios ingredientes.
Inspecione os dados próprios de um objeto
Para a p2 original, vars(p2) fornece {'size': 'small', 'toppings': []}. Os valores de classe estão ausentes porque ficam em Pizza. Isso é útil ao depurar uma busca com resultado inesperado: verifique se a instância tem um valor próprio e depois inspecione o valor da classe. Uma configuração compartilhada pertence à classe; um nome, tamanho, saldo ou coleção individual pertence à instância.
Principais conclusões
- Atributos de instância armazenam dados de um objeto; atributos de classe armazenam configurações compartilhadas ou dados de toda a classe.
- Um atributo de dados de instância pode sombrear um atributo de classe com o mesmo nome.
- Atualize um contador compartilhado por meio do nome da classe.
- Alterar uma lista no nível da classe modifica a única lista compartilhada.
vars(obj)mostra os próprios atributos armazenados do objeto, não os atributos de classe que ele pode encontrar.
2.3 Mantenha objetos válidos desde o início
Um objeto deve começar em um estado que seus métodos possam usar. Um retângulo com largura negativa não pode representar a forma pretendida. Uma regra que deve permanecer verdadeira para todos os objetos de uma classe é uma invariante. A validação verifica essas regras antes de aceitar dados.
Verifique antes de armazenar
class Rectangle:
def __init__(self, width, height):
if width <= 0:
raise ValueError("width must be positive")
if height <= 0:
raise ValueError("height must be positive")
self.width = width
self.height = height
Rectangle(3, 4) passa pelas duas verificações e retorna um objeto inicializado. Rectangle(-2, 4) provoca ValueError na primeira verificação. As atribuições posteriores não são executadas. Se o programa não capturar essa exceção, a execução para nesse ponto.
Suponha que r já se refira a um retângulo válido. Em r = Rectangle(-2, 4), a chamada à direita falha antes da atribuição. r mantém seu valor anterior. Se r não tinha valor antes da chamada que falhou, a atribuição não cria um.
Escolha uma exceção útil
| Exceção | Problema que descreve |
|---|---|
ValueError | Uma entrada de tipo aceitável tem um valor inaceitável |
TypeError | A entrada tem o tipo errado para a operação |
Uma largura numérica negativa é um erro de valor. Um texto fornecido onde se exige um número é um erro de tipo. A comparação com 0 neste exemplo já provoca TypeError para texto. Uma classe também pode verificar um tipo explicitamente com isinstance quando precisa de uma mensagem mais clara.
Escreva mensagens que nomeiem a regra, como "width must be positive". Uma mensagem que diz apenas "bad input" deixa o código chamador sem saber qual valor precisa ser corrigido.
Deixe o código chamador tratar a recuperação
while True:
try:
width = float(input("Width: "))
room = Rectangle(width, 3)
break
except ValueError as error:
print("Try again:", error)
Digitar abc falha durante float; digitar -2 passa pela conversão, mas falha em Rectangle. Ambos provocam ValueError, então esse laço trata os dois casos. A classe estabelece sua regra de dados, enquanto o código chamador decide solicitar a entrada novamente.
Imprimir um aviso dentro de __init__ não rejeita a chamada. Se a execução continuar, o programa pode receber um objeto inválido e falhar mais tarde ao usá-lo. Lançar uma exceção interrompe a configuração malsucedida onde o problema ocorre.
Ajuste dados deliberadamente e mantenha a regra
Um ajuste documentado pode ser útil. self.name = name.strip() remove espaços das extremidades; valide o nome ajustado se nomes em branco forem proibidos. self.items = list(items) cria uma lista externa separada, então adicionar um item à lista do código chamador não o adiciona a esta lista. Alterar uma largura inválida para seu valor absoluto mudaria o significado pretendido pelo código chamador, então isso exige uma regra de projeto explícita.
As verificações de inicialização ocorrem no momento da criação. Uma atribuição comum como r.width = -5 ainda as ignora depois. Métodos que alteram uma largura devem verificá-la novamente. Uma propriedade pode colocar uma verificação na própria atribuição ao atributo, permitindo que a mesma regra seja executada durante a configuração e em atualizações posteriores.
Principais conclusões
- Uma invariante é uma regra que o estado válido de um objeto deve satisfazer.
- Valide antes de aceitar dados e lance uma exceção clara em caso de falha.
- Uma chamada de criação que falha não atribui um novo objeto ao nome do código chamador.
- As verificações do construtor também precisam ser aplicadas em métodos ou propriedades posteriores que alteram o estado.
3Dê comportamento aos objetos com métodos de instância
Métodos transformam dados armazenados em comportamento útil. Um retângulo pode calcular sua área, e uma conta pode atualizar seu saldo enquanto registra uma transação. Acompanhe como o Python passa o objeto receptor a cada método e depois distinga um resultado retornado de uma mudança de estado. Propriedades permitem que uma classe mantenha o acesso legível aos atributos enquanto verifica atribuições ou calcula valores sob demanda.
3.1 Defina e chame métodos de instância
Um método de instância é uma função definida dentro de uma classe que trabalha com o objeto passado como self. O objeto fornece seus dados armazenados; parâmetros extras fornecem as informações adicionais necessárias para a ação.
Leia atributos por meio de self
Adicione estes métodos dentro da classe Rectangle validada, no mesmo nível de indentação de __init__:
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
def is_square(self):
return self.width == self.height
Com r = Rectangle(3, 4), r.area() retorna 12, r.perimeter() retorna 14 e r.is_square() retorna False. Cada método lê os atributos do mesmo objeto. Um segundo retângulo usa as mesmas definições de método com sua própria largura e altura.
Dentro de um método, self.width nomeia um atributo. width sozinho nomeia uma variável local ou outra variável acessível; o Python não a procura automaticamente no objeto atual. Se essa variável não existir, return width * height provoca NameError. Escrever self. explicita a quem pertencem os dados pretendidos.
Acompanhe a chamada
Para essa classe, r.area() funciona como Rectangle.area(r). O Python encontra a função na classe e fornece r como seu primeiro argumento. Uma referência a método como r.area é um método vinculado: ela guarda a função e esse retângulo. Adicionar () realiza a chamada.
Se um método for definido como def resize(self, factor), chame-o como r.resize(2). r preenche self, e 2 preenche factor. Você não passa r novamente. Se um método de instância for escrito acidentalmente como def area():, uma chamada em r provoca TypeError porque o Python ainda fornece o objeto a uma função que não aceita argumentos.
Um método pode usar outro por meio de self:
def double_area(self):
return self.area() * 2
Aqui self.area() calcula usando o mesmo retângulo. Deixar self. de fora pediria uma função separada chamada area, não o método do objeto.
Retorne resultados ao código chamador
Um método de cálculo normalmente deve retornar seu resultado. O retorno dá ao código chamador um valor para armazenar, combinar, testar ou exibir:
r1 = Rectangle(3, 4)
r2 = Rectangle(2, 5)
total = r1.area() + r2.area()
print(total) # 22
Se area apenas imprimisse sua resposta, cada chamada retornaria None. A adição então falharia com TypeError, embora dois números tivessem aparecido na tela. Imprimir é uma ação; retornar fornece um valor à expressão que contém a chamada.
Use nomes de métodos que mostrem a tarefa. deposit e resize nomeiam ações; is_square e has_room sugerem verificações booleanas. Um método não precisa de parâmetros para dados já armazenados em seu objeto. Ele precisa de parâmetros para novas entradas, como um fator de redimensionamento ou um valor de depósito.
Principais conclusões
- Coloque
selfprimeiro em um método de instância; o Python fornece o objeto receptor. - Leia atributos e chame outros métodos por meio de
self.. - Parênteses executam um método vinculado.
- Retorne valores calculados para que o código chamador possa combiná-los, testá-los ou exibi-los.
3.2 Altere o estado de um objeto com métodos
O estado de um objeto é o conjunto atual de valores de seus atributos. Um método de acesso informa esse estado. Um método de alteração o modifica. Um método de alteração útil verifica suas entradas e mantém todos os atributos relacionados, para que o código chamador não precise coordenar várias atualizações.
Valide toda a alteração primeiro
Adicione estes métodos dentro da classe BankAccount, com seu titular, saldo e lista de transações:
def deposit(self, amount):
if amount <= 0:
raise ValueError("deposit must be positive")
self.balance += amount
self.transactions.append(("deposit", amount))
def withdraw(self, amount):
if amount <= 0:
raise ValueError("withdrawal must be positive")
if amount > self.balance:
raise ValueError("insufficient funds")
self.balance -= amount
self.transactions.append(("withdraw", amount))
Um depósito altera o saldo e registra o evento. Um saque verifica tanto o sinal do valor quanto o saldo disponível antes de subtrair. Essas verificações impedem que um saque rejeitado altere o saldo ou seu histórico.
Começando com BankAccount("Maya", 50), depositar 25 resulta em 75, e sacar 30 resulta em 45. Uma tentativa posterior de sacar 100 provoca ValueError; ela deixa o saldo em 45 e não adiciona nenhuma transação. Colocar a subtração antes da verificação de saldo alteraria o estado mesmo em caso de falha.
Distinga uma alteração de um valor retornado
Esses métodos de alteração não têm instrução de retorno, então retornam None. Depois de new_balance = acct.deposit(25), o depósito foi realizado, mas new_balance é None. Leia acct.balance depois para obter o número atualizado.
Uma classe pode oferecer outro tipo de método que retorna um novo objeto. resize sugere alterar um retângulo; resized pode ser escolhido para um método que retorna um novo retângulo e deixa o original intacto. Leia o contrato do método: o nome ajuda, mas sua definição determina o comportamento.
Rastreie referências compartilhadas
a = BankAccount("Maya", 50)
b = a
b.deposit(10)
print(a.balance) # 60
print(a is b) # True
A atribuição associa um nome a um objeto; ela não copia esse objeto. Ambos os nomes acessam a conta cujo saldo mudou. Passar a a uma função também permite acesso a esse objeto. Uma função que chama account.withdraw(5) pode, portanto, alterar a conta vista pelo código chamador.
Para uma conta independente com o mesmo titular e saldo, crie BankAccount(a.owner, a.balance). Esse construtor também fornece um novo histórico vazio. É uma nova conta, não uma cópia completa do histórico.
copy.copy(a) cria um novo objeto externo, mas mantém referências aos mesmos objetos internos, incluindo a lista de transações. copy.deepcopy(a) também copia objetos aninhados. Quando a independência importa, verifique os objetos dentro dos atributos, além da instância externa.
Atribuir diretamente acct.balance = -500 ignora as verificações dos dois métodos. Convenções para atributos internos e propriedades ajudam a deixar claro o caminho previsto para atualizações e a manter a validação próxima das mudanças de estado.
Principais conclusões
- Verifique uma alteração solicitada antes de atualizar atributos.
- Um método de alteração pode mudar o estado e retornar
None. - A atribuição e a passagem de argumentos preservam referências ao mesmo objeto.
- Uma cópia superficial ainda pode compartilhar objetos mutáveis aninhados.
- Mantenha atualizações de estado relacionadas juntas no método responsável por elas.
3.3 Proteja atributos com convenções de nomenclatura e propriedades
O código chamador precisa de uma forma clara de ler e alterar um objeto. O encapsulamento mantém as regras dos dados junto aos métodos que os gerenciam. O Python usa convenções e propriedades para expressar essa interface.
Marque o armazenamento interno
Um sublinhado inicial em _balance indica um atributo interno. O código chamador deve usar os métodos da conta, mas o Python ainda permite acesso direto. Não há uma palavra reservada private que bloqueie o acesso ao valor.
Um nome como __balance, com dois sublinhados iniciais e sem dois sublinhados finais, aciona a transformação de nome. Dentro de class Acc, self.__balance é armazenado como _Acc__balance. Fora da classe, obj.__balance falha, mas obj._Acc__balance ainda pode funcionar. A transformação evita conflitos de nomes; ela não protege dados sensíveis.
Execute um método pela sintaxe de atributo
Uma propriedade faz um método ser executado quando um atributo é lido. A linha @property é um decorador: ela altera como o Python disponibiliza o método. Uma propriedade sem método de definição permite a leitura, mas rejeita a atribuição.
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance
@property
def balance(self):
return self._balance
Depois de acct = Account("Maya", 50), leia acct.balance sem parênteses. Atribuir acct.balance = 10 provoca AttributeError porque essa propriedade não tem método de definição. Um método de depósito dentro da classe poderia atualizar _balance após suas verificações.
Verifique atribuições com um método de definição
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not 0 <= value <= 100:
raise ValueError("score must be between 0 and 100")
self._score = value
O método de leitura e o método de definição compartilham o nome score; o valor armazenado usa _score. Na criação, self.score = score executa o método de definição.
Para s = Student("Ana", 88), atribuir s.score = 92 armazena 92. Atribuir s.score = -1 provoca ValueError antes do armazenamento, então a nota continua sendo 92. Student("Ana", 105) falha durante a inicialização.
Dentro do método de definição, self.score = value chamaria esse método novamente, repetindo até ocorrer RecursionError. O método de leitura tem o mesmo risco se retornar self.score. Use o nome de armazenamento separado _score em ambos os corpos.
Calcule valores quando forem lidos
Uma propriedade pode calcular um valor a partir de outros atributos:
@property
def area(self):
return self.width * self.height
Colocada dentro de uma classe de retângulo, ela permite r.area. Para largura 3 e altura 4, o valor é 12. Alterar a largura para 5 faz a próxima leitura retornar 20. Armazenar uma área uma vez durante a inicialização deixaria um valor antigo após uma alteração da largura.
Comece com um atributo comum quando o armazenamento simples atender à necessidade.
Principais conclusões
- Um sublinhado inicial marca o armazenamento interno por convenção; ele não bloqueia o acesso.
- A transformação de nome altera o nome de um atributo para evitar conflitos.
- Uma propriedade executa um método de leitura por meio da sintaxe de atributo.
- Um método de definição pode validar a inicialização e atribuições posteriores em um único lugar.
- Use um atributo de armazenamento separado para evitar chamar a propriedade recursivamente.
- Uma propriedade calculada deriva seu valor quando é lida.
4Use métodos especiais para exibir e comparar objetos adequadamente
Um objeto útil deve se integrar naturalmente às expressões comuns do Python. Seus métodos especiais podem fornecer texto legível, igualdade de valores, uma ordenação, resultados aritméticos ou um comprimento. Aprenda qual método o Python solicita em cada situação e o que esse método deve retornar. Preste atenção especial à exibição dentro de contêineres, à estabilidade das chaves de dicionário e à diferença entre uma operação e sua forma refletida.
4.1 Dê aos objetos representações em string legíveis
Um objeto é mais fácil de inspecionar quando pode descrever seus próprios dados. Métodos especiais permitem que o Python solicite essa descrição por meio de ações familiares como print, str e repr. Seus nomes começam e terminam com dois sublinhados e são frequentemente chamados de nomes dunder.
Escolha textos para dois públicos
__str__ fornece texto legível para os usuários de um programa. __repr__ fornece uma descrição precisa para programadores. Ambos retornam strings; nenhum deles deve imprimir seu resultado em lugar de retorná-lo.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
def __repr__(self):
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p) # (3, 4)
print(repr(p)) # Point(3, 4)
str(p) retorna a string "(3, 4)". repr(p) retorna "Point(3, 4)". Quando possível, uma representação se parece com uma chamada de classe que recriaria o valor. Ela continua sendo texto: chamar repr não cria, por si só, outro ponto.
Sem uma representação personalizada, uma instância comum geralmente exibe um nome de classe e um identificador semelhante a um endereço. Isso ajuda a distinguir objetos, mas não mostra seus dados úteis. Você raramente chama esses métodos especiais diretamente; defina-os uma vez e use as operações comuns de exibição do Python.
Preveja o que um contêiner exibe
| Expressão | Representação solicitada |
|---|---|
print(p) ou str(p) | __str__ |
repr(p) | __repr__ |
f"{p}" | A forma usual em string para essa classe |
f"{p!r}" | __repr__ |
print([p]) | A exibição da lista, usando repr para seu item |
Com a classe acima, print([Point(3, 4), Point(0, 0)]) mostra [Point(3, 4), Point(0, 0)]. A lista usa as representações de seus elementos, embora cada elemento também tenha __str__.
Se você definir apenas __repr__, o __str__ padrão também o usará. Definir apenas __str__ não altera repr nem a exibição de contêineres. Portanto, ao adicionar apenas um método de exibição, __repr__ atende a mais contextos de inspeção.
Torne os campos de string inequívocos
Para um livro que já armazena title, author e year, estes métodos oferecem diferentes formas úteis de exibição:
def __str__(self):
return f"{self.title} by {self.author} ({self.year})"
def __repr__(self):
return f"Book({self.title!r}, {self.author!r}, {self.year})"
Para o livro com título "Dune", autor "Frank Herbert" e ano 1965, o primeiro método fornece "Dune by Frank Herbert (1965)". O segundo fornece "Book('Dune', 'Frank Herbert', 1965)". !r solicita as representações dos campos de string, incluindo aspas.
Um corpo que contém apenas print(self.x) retorna None, então str(p) falha com TypeError. Retornar um número inteiro também falha. Construa o texto necessário e depois retorne essa string.
Principais conclusões
__str__fornece texto para o usuário;__repr__fornece uma representação útil para o programador.- Contêineres exibem seus elementos com
repr. __repr__pode fornecer a forma padrão em string;__str__não substituirepr.- Ambos os métodos devem retornar strings.
- Use
!rem uma f-string para mostrar representações de campos de string entre aspas.
4.2 Compare e combine objetos com operadores
Métodos especiais conectam uma classe a operadores e funções embutidas. Defina apenas operações com significado claro para esse tipo: somar vetores é compreensível; adicionar um jogador a um time fica mais claro como team.add_player(player).
Compare valores e mantenha os hashes seguros
Duas instâncias comuns e separadas são consideradas diferentes por padrão. Acrescente igualdade de valores a uma classe de ponto com:
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
Agora dois pontos em (3, 4) são considerados iguais, embora suas identidades sejam diferentes. in, count, index e remove em listas podem encontrar esses valores iguais. O resultado usual de != decorre de __eq__.
NotImplemented é um valor de retorno que permite ao Python tentar o outro operando ou uma alternativa. Não é uma exceção a ser lançada. Quando nenhum dos operandos permite comparar valores, == recorre à identidade; um ponto e a string "3,4" são considerados diferentes.
Definir __eq__ sem __hash__ torna as instâncias não hasháveis. Assim, elas não podem ser elementos de conjuntos nem chaves de dicionários. Objetos iguais devem ter hashes iguais, e o hash de uma chave deve permanecer estável. Se os atributos comparados nunca mudarem, um hash correspondente pode retornar hash((self.x, self.y)). Mantenha objetos de valor mutáveis como não hasháveis quando seus campos de igualdade puderem mudar.
Defina uma ordenação
__lt__ fornece <. Uma classe de aluno pode comparar notas com return self.score < other.score. As notas 88, 72 e 95 são então ordenadas como 72, 88, 95. min escolhe a menor; max escolhe a maior usando > e sua comparação refletida <.
Com apenas __lt__, a > b pode usar b < a. O Python não infere <= ou >= dessa definição; eles precisam de seus próprios métodos. Se uma ordem for útil apenas para uma tarefa, passe uma função de chave:
def by_score(student):
return student.score
ordered = sorted(students, key=by_score)
Retorne novos resultados de operações aritméticas
Dentro de uma classe de vetor com atributos x e y:
def __add__(self, other):
if not isinstance(other, Vector):
return NotImplemented
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, factor):
if not isinstance(factor, (int, float)):
return NotImplemented
return Vector(self.x * factor, self.y * factor)
def __rmul__(self, factor):
return self * factor
Vector(1, 2) + Vector(3, 4) produz um novo vetor (4, 6). Multiplicar o primeiro vetor por 3 produz (3, 6), deixando-o inalterado. __mul__ trata o vetor à esquerda; __rmul__ aceita um número à esquerda. O Python não presume que as duas ordens tenham o mesmo significado.
Forneça um comprimento significativo
Para uma lista de reprodução que armazena self.songs, defina __len__ para retornar len(self.songs). O resultado deve ser um número inteiro não negativo. len(playlist) então conta as músicas. Nessa classe, comprimento zero também faz if playlist: ser falso; um __bool__ personalizado teria prioridade sobre o comprimento ao testar o valor lógico.
Principais conclusões
__eq__define igualdade de valores; retorneNotImplementedpara tipos de operando não aceitos.- Objetos hasháveis iguais precisam ter hashes iguais e estáveis.
__lt__permite a ordenação, mas não fornece<=ou>=.- Use uma função de chave para uma ordem específica de uma tarefa.
- Métodos aritméticos podem criar novos objetos sem alterar os operandos.
__rmul__permite a multiplicação com o objeto à direita.__len__retorna um número inteiro não negativo e pode fornecer o valor lógico em contexto quando não existe__bool__.
5Crie programas com objetos que trabalham juntos
Programas maiores conectam objetos com funções diferentes. Um carrinho pode pedir subtotais a itens; uma conta pode pedir a outra que receba um depósito. Rastreie as referências e a sequência de chamadas para ver qual estado muda e onde um erro interrompe a execução. Depois, use essas ideias para escolher um projeto claro, planejar uma classe pequena e testar seu comportamento público em etapas manejáveis.
5.1 Crie objetos que contenham outros objetos
Os atributos de um objeto podem se referir a outros objetos. Um carrinho contém itens, uma biblioteca contém livros e um curso tem alunos. A composição constrói um objeto maior a partir de objetos menores por meio dessa relação de posse.
Dê a cada objeto sua própria responsabilidade
class Item:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
def subtotal(self):
return self.price * self.quantity
class ShoppingCart:
def __init__(self):
self.items = []
def add(self, item):
if not isinstance(item, Item):
raise TypeError("a cart holds Item objects")
self.items.append(item)
def total(self):
total = 0
for item in self.items:
total += item.subtotal()
return total
O carrinho tem uma lista separada criada durante a inicialização. Seu método add verifica o objeto recebido antes de adicioná-lo. cart.add("pen") provoca TypeError em vez de armazenar texto que falhará quando um subtotal for solicitado.
Crie os itens antes ou durante as chamadas:
cart = ShoppingCart()
cart.add(Item("notebook", 2.50, 4))
cart.add(Item("pen", 1.25, 3))
print(cart.total()) # 13.75
print(cart.items[0].name) # notebook
Os subtotais são 10.0 e 3.75; o carrinho os soma para obter 13.75. A cadeia cart.items[0].name acessa primeiro a lista do carrinho, depois seu primeiro objeto e, por fim, o nome desse objeto.
Delegue o trabalho ao objeto que sabe realizá-lo
O carrinho pede subtotal() a cada item. Isso é delegação: um objeto chama o método de outro objeto para realizar parte de uma tarefa. Se um desconto por quantidade mudar a forma de calcular um subtotal, essa regra pertence a Item.subtotal. O carrinho pode continuar somando os subtotais retornados sem duplicar as regras de preço.
Passar Item em vez de Item(...) passa a classe, não um item comprado. A verificação de tipo rejeita esse objeto de classe. Faça todas as adições pelo caminho verificado; o acesso direto a cart.items.append(...) ignoraria add.
Busque um objeto
Adicione este método dentro de ShoppingCart:
def find(self, name):
for item in self.items:
if item.name == name:
return item
return None
A primeira correspondência retorna o item existente. Se não houver correspondência, retorna None. Verifique found is None antes de usar found.name; None não tem esse atributo. Um método __len__ que retorna len(self.items) também poderia fazer len(cart) contar os objetos de item armazenados, enquanto __str__ poderia unir as linhas dos itens em um recibo.
Acompanhe referências dentro de coleções
Uma lista armazena referências, então colocar o mesmo item em dois carrinhos não o copia. Atualizar o preço desse item afeta o próximo total calculado por ambos os carrinhos. Listas separadas para os carrinhos evitam o compartilhamento acidental da lista, mas não tornam independentes os objetos dentro delas. Crie itens separados quando os carrinhos precisarem armazenar dados independentes.
Principais conclusões
- A composição armazena objetos dentro de outro objeto.
- A delegação pede a um objeto contido que realize sua parte de uma tarefa.
- Verifique um objeto antes de armazená-lo quando métodos posteriores exigirem seu tipo.
- Uma busca pode retornar o objeto correspondente ou
None. - Contêineres separados ainda podem se referir ao mesmo objeto contido.
5.2 Faça objetos interagirem por meio de métodos
Objetos podem ser argumentos e valores de retorno de métodos, assim como números ou strings. Acompanhe separadamente o receptor, os argumentos e o resultado: um método pode alterar um objeto existente, retornar um novo objeto ou apenas informar um valor.
Use outro objeto como entrada
Dentro de uma classe de ponto com x e y, um método pode ler ambos os pontos:
def midpoint(self, other):
return Point((self.x + other.x) / 2,
(self.y + other.y) / 2)
Para p = Point(3, 4) e q = Point(1, 0), middle = p.midpoint(q) cria um terceiro ponto em (2.0, 2.0). Durante a chamada, self se refere a p e other se refere a q. O método calcula coordenadas e constrói um novo ponto; ele não atribui nada a nenhum dos originais.
Com import math, um método de distância pode retornar math.hypot(self.x - other.x, self.y - other.y). Point(0, 0).distance_to(Point(3, 4)) então fornece 5.0. Essa chamada retorna um número, enquanto midpoint retorna um objeto.
Deixe cada receptor gerenciar suas alterações
Dentro de uma classe de conta com métodos withdraw e deposit que fazem verificações:
def transfer_to(self, other, amount):
self.withdraw(amount)
other.deposit(amount)
Se Maya tem 100 e Leo tem 20, maya.transfer_to(leo, 30) primeiro saca da conta de Maya, deixando 70, e depois deposita na conta de Leo, resultando em 50. Na primeira chamada, self é a conta de Maya. Na chamada de depósito, seu próprio self é a conta de Leo.
Uma transferência posterior de 500 falha em withdraw porque Maya tem apenas 70. A execução para antes de deposit, então ambos os saldos mantêm seus valores anteriores. A ordem das chamadas importa. O Python não desfaz uma mudança de estado anterior se uma chamada posterior lançar uma exceção; esse método curto depende de a conta receptora poder aceitar o valor do depósito.
Chamar other.deposit(amount) executa as regras da conta receptora em um único lugar. Alterar diretamente other.balance as ignoraria.
Rastreie os objetos, não apenas os nomes das variáveis
Desenhe cada instância como uma caixa que contém seus atributos. Desenhe uma seta de cada variável até sua caixa. Em uma chamada, identifique qual caixa é recebida como self e quais caixas são passadas como argumentos. Atualize a caixa afetada após cada linha bem-sucedida que altera o estado. Duas setas para uma caixa significam que uma alteração por qualquer um dos nomes alcança o mesmo objeto.
Uma função comum também pode trabalhar com vários objetos. total_balance(accounts) pode percorrer contas e somar seus saldos. Esse cálculo sobre a lista inteira não precisa pertencer a uma única conta.
Represente uma relação ausente
Um livro pode começar com self.borrower = None e depois armazenar um objeto de membro. Antes de ler um atributo do membro, verifique a relação:
if book.borrower is not None:
print(book.borrower.name)
Caso contrário, book.borrower.name falha quando o livro não tem uma pessoa que o tomou emprestado. Classes podem ser definidas acima de uma função main() que cria e conecta os objetos. Chamar main() sob if __name__ == "__main__": impede que essas ações sejam executadas quando as classes são importadas.
Principais conclusões
- Identifique o receptor como
selfe o objeto passado como argumento em seu próprio parâmetro. - Um método pode retornar um novo objeto e deixar suas entradas inalteradas.
- As chamadas acontecem em ordem; uma exceção interrompe chamadas posteriores, mas não desfaz alterações anteriores.
- Use os métodos públicos de outro objeto para aplicar suas regras.
- Verifique se há
Noneantes de acessar uma relação opcional com outro objeto. - Uma função pode organizar cálculos que envolvem vários objetos.
5.3 Decida quando uma classe torna um programa mais claro
Uma classe justifica seu uso quando dados relacionados e operações repetidas ficam mais fáceis de entender juntos. Você não precisa transformar toda função ou registro em uma classe. Escolha a estrutura que deixa claras as responsabilidades do programa.
Procure dados e comportamentos que andam juntos
Classes ajudam quando várias funções recebem repetidamente o mesmo grupo de valores, muitos registros compartilham uma estrutura e mudanças de estado devem seguir regras comuns. Várias contas que aceitam depósitos e saques são um bom caso. Um único cálculo pode continuar sendo uma função. Um registro fixo e somente leitura pode continuar sendo uma tupla ou um dicionário.
Uma classe com apenas configuração e uma operação única muitas vezes acrescenta mais formalidade do que estrutura útil. Pergunte o que uma instância representa e quais ações repetidas pertencem a ela. Se você não conseguir responder a essas perguntas de forma simples, reconsidere o projeto.
Mova uma operação para junto de seus dados
Uma conta baseada em dicionário pode começar assim:
account = {"owner": "Maya", "balance": 50}
def deposit(account, amount):
account["balance"] += amount
A versão com classe pode colocar a mesma operação ao lado de seu estado e de suas regras:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("deposit must be positive")
self.balance += amount
def __repr__(self):
return f"BankAccount({self.owner!r}, {self.balance})"
Depois de acct = BankAccount("Maya", 50) e acct.deposit(25), sua representação é BankAccount('Maya', 75). A regra de depósito positivo agora é executada sempre que o código chamador usa esse método. Ler account["balence"] provocaria KeyError; ler acct.balence provoca AttributeError. Uma classe não elimina erros de escrita, mas dá aos dados e a suas operações um lugar com nome.
Planeje a partir de uma breve descrição
Para “Uma biblioteca empresta livros a seus membros. Um membro pode pegar emprestados no máximo 3 livros”, os substantivos sugerem Book, Member e Library. Os verbos sugerem métodos de empréstimo e devolução.
- Liste o que cada instância sabe: título, autor e pessoa que tomou o livro emprestado; nome e livros emprestados de um membro; livros e membros de uma biblioteca.
- Identifique regras: um livro não pode já estar emprestado, e um membro não pode exceder
MAX_LOANS = 3. - Coloque cada regra na operação que altera a relação, como
Library.check_out(book, member). - Escreva a inicialização e uma representação útil, depois adicione e teste uma ação por vez.
Títulos diferentes precisam de instâncias diferentes de Book, não de classes separadas com o nome de cada título. Use substantivos no singular para objetos individuais, como Book; nomeie uma coleção de acordo com a coleção, como Library. Mantenha a função de cada classe clara o bastante para ser descrita em uma frase.
Teste o comportamento observável
acct = BankAccount("Maya", 50)
acct.deposit(25)
assert acct.balance == 75
assert provoca AssertionError se sua condição for falsa. Teste também ações rejeitadas: capture a exceção esperada e verifique se o estado não mudou. Use validação explícita com raise para entradas do código chamador; asserções são verificações durante o desenvolvimento e podem ser desativadas quando o Python é executado com otimização.
Principais conclusões
- Escolha uma classe quando estado relacionado e operações repetidas se beneficiarem de um lugar comum.
- Mantenha um cálculo simples como função quando não for necessário um estado duradouro de objeto.
- Planeje atributos a partir dos dados e métodos a partir das ações e regras.
- Modele valores de dados diferentes como instâncias de uma mesma classe.
- Teste tanto atualizações bem-sucedidas quanto alterações rejeitadas.
Exercícios resolvidos de Programação orientada a objetos em Python
1De valores familiares à sua primeira classe
11 passos
- 1IntroduçãoComece com objetos que você conhece
Uma lista, uma string e um número são todos objetos. Seus tipos determinam quais operações eles aceitam, e cada valor tem sua própria identidade.
Comece acompanhando um método de string e um método de lista. Depois, use as mesmas ideias para criar uma classe simples cujas instâncias armazenam dados diferentes. Continue fazendo duas perguntas: a qual objeto este nome se refere e o que esta chamada retorna?
- 2ExemploConsulte o tipo de um valor
O Python pode informar que tipo de objeto é um valor.
text = "river" values = [4, 2] print(type(text)) # <class 'str'> print(isinstance(values, list)) # TrueA string e a lista oferecem métodos diferentes porque têm tipos diferentes. Você pode usar
dir(values)para inspecionar os nomes disponíveis na lista, incluindo métodos comuns e métodos especiais. - 3ExemploAcompanhe uma string retornada
Um método de string pode produzir um novo valor sem substituir o original.
name = "robin" result = name.title() print(result) # Robin print(name) # robintitle()retorna uma nova string. A atribuição armazena esse resultado emresult, enquantonameainda se refere a"robin". Escrevername = name.title()farianamese referir à string retornada. - 4ExemploAcompanhe uma alteração na própria lista
Compare a chamada de string com uma ordenação de lista.
values = [4, 2] result = values.sort() print(values) # [2, 4] print(result) # NoneA própria lista muda, e o valor de retorno é
None. Atribuir a chamada de volta avaluessubstituiria a referência à lista desse nome porNone. Usevalues.sort()sozinho quando quiser alterar a lista existente. - 5DesafioOnde aparece o item adicionado?
Preveja as duas listas impressas.
a = [7] b = a c = [7] b.append(2) print(a, c)---reveal---
A saída é
[7, 2] [7].aebse referem a uma mesma lista, então adicionar um item por meio debaltera a lista vista por meio dea.carmazena uma lista separada. As listas eram inicialmente iguais, masa is cera falso. - 6DicaDesenhe referências antes de rastrear alterações
Desenhe uma caixa para cada lista criada separadamente. Aponte tanto
aquantobpara a primeira caixa e apontecpara a segunda. Adicionar um item altera a caixa; uma atribuição altera para onde um nome aponta.Distinga também um método de sua chamada:
name.titlefornece um objeto de método, enquantoname.title()o executa. Os parênteses podem fazer a diferença entre armazenar um comportamento e obter seu resultado. - 7AnalogiaUm formulário, várias cópias preenchidas
Pense em uma classe como um formulário em branco que descreve as informações armazenadas por um tipo de objeto. Uma instância é uma cópia preenchida com seus próprios dados.
Uma classe
Badgepode representar todos os crachás de um programa. Uma instância armazena o nome de um visitante; outra armazena um nome diferente. A classe descreve o tipo de objeto compartilhado. Você não precisa de uma nova classe para cada valor escrito no formulário. - 8ExemploDefina o tipo e crie duas instâncias
Use uma classe mínima enquanto aprende como as instâncias funcionam.
class Badge: pass first = Badge() second = Badge() first.name = "Rae" second.name = "Ivo"passfornece um corpo vazio. Cada chamada de classe cria uma instância, e as atribuições com ponto armazenam dados no objeto selecionado.first is secondé falso.first = Badgedaria outro nome à classe sem criar uma instância. - 9DesafioEncontre um atributo escrito incorretamente
Continue com os dois crachás:
first.nmae = "Tess" print(first.name, second.name)O que aparece?
---reveal---
A saída é
Rae Ivo. A atribuição cria um atributo separado chamadonmae; ela não alteraname. Ler um atributo que não existe provocaAttributeError, mas atribuir um novo nome é permitido. Confira a escrita nos dois pontos quando uma leitura produzir um resultado inesperado. - 10DesafioCombine instâncias e referências alternativas
Continue com
firsteseconddo exemplo dos crachás:copy_name = first copy_name.name = "Noor" print(first.name, second.name)---reveal---
A saída é
Noor Ivo.copy_nameé uma referência alternativa para o primeiro crachá, então a atribuição altera esse objeto. O segundo crachá permanece separado. Criar instâncias controla quantos objetos existem; atribuir nomes controla quais objetos esses nomes acessam. - 11RecapitulaçãoRastreie mais um programa no papel
Experimente um programa curto com duas chamadas de classe e um terceiro nome atribuído à primeira instância. Dê atributos diferentes aos objetos e depois altere um deles por meio da referência alternativa.
Antes de executá-lo, desenhe as caixas dos objetos e preveja cada leitura. Se uma previsão diferir da saída, inspecione a escrita dos atributos e as setas dos nomes para os objetos. Isso distingue um erro de configuração de um erro de referência.
2Crie objetos com dados iniciais confiáveis
14 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoConfigure uma coleção de tarefas
- 2ExplicaçãoForneça um inicializador ao Python
- 3ExemploRelacione uma chamada a seus parâmetros
- 4DesafioIdentifique o atributo ausente
- 5ExemploAceite uma lista inicial opcional
- 6DicaVerifique o alcance da cópia
- 7ExplicaçãoAdicione dados sobre a classe
- 8ExemploAcompanhe uma atribuição que causa sombreamento
- 9DesafioCorrija o contador compartilhado
- 10ExplicaçãoRejeite um limite que não pode funcionar
- 11ExemploEscolha o erro e o caminho de recuperação
- 12DesafioImprimir rejeita a configuração?
- 13DesafioMantenha o objeto anterior em caso de falha
- 14RecapitulaçãoVerifique a configuração como código chamador
3Controle o estado com métodos e propriedades
16 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoTorne um contador de estoque útil
- 2ExemploComece com a quantidade armazenada
- 3ExplicaçãoDeixe o receptor fornecer self
- 4DesafioTorne um resultado reutilizável
- 5ExemploAdicione estoque após verificar a quantidade
- 6ExemploRejeite uma retirada antes da subtração
- 7DesafioRastreie uma alteração por uma referência alternativa
- 8ConexãoCopie o nível adequado do estado
- 9ExplicaçãoMarque o armazenamento interno
- 10ExemploLeia por meio de uma propriedade
- 11ExemploPermita atribuição pública com verificação
- 12DesafioEvite um método de definição recursivo
- 13Ideia-chaveCalcule um valor quando ele for lido
- 14DesafioCombine um método de definição com uma referência alternativa
- 15DicaLeia a definição e a chamada juntas
- 16RecapitulaçãoTeste uma operação por vez
4Faça objetos funcionarem em expressões Python
17 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoEscolha o que um objeto deve representar
- 2ExemploComece com um ponto
- 3ExemploAdicione texto para inspeção
- 4DesafioPreveja a exibição de uma lista
- 5DicaRetorne texto nos dois métodos de exibição
- 6ExemploCompare valores de coordenadas
- 7Ideia-chaveDeixe comparações não aceitas para o Python
- 8DesafioPares iguais podem entrar em um conjunto?
- 9ExemploEscolha uma ordenação de coordenadas
- 10ConexãoUma ordem pode pertencer a uma tarefa
- 11ExemploSome sem alterar os operandos
- 12ExemploPermita ambas as ordens de multiplicação
- 13DesafioDistinga um novo resultado de uma referência alternativa
- 14ExplicaçãoUse comprimento para uma coleção
- 15DesafioPreveja o ramo para a fila vazia
- 16DicaMantenha o significado visível
- 17RecapitulaçãoVerifique cada expressão separadamente
5Conecte objetos com funções claras
15 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoConstrua um pedido a partir de partes menores
- 2ExemploDê a uma linha seu próprio cálculo
- 3ExemploArmazene linhas em um pedido
- 4ExemploDelegue cada cálculo de custo
- 5DesafioRastreie uma linha compartilhada por dois pedidos
- 6DicaVerifique um resultado de busca ausente
- 7ExplicaçãoPasse um objeto para outro método
- 8ExemploAcompanhe o receptor e o resultado
- 9DesafioOnde uma combinação malsucedida para?
- 10ConexãoRastreie chamadas que alteram dois objetos
- 11ExplicaçãoDecida quais comportamentos pertencem uns aos outros
- 12DesafioEvite uma classe para cada produto
- 13ExemploTeste o ponto de entrada público com verificação
- 14DesafioEscolha um teste para o projeto combinado
- 15RecapitulaçãoPlaneje sua própria interação entre objetos
Questões de Programação orientada a objetos em Python
Conjunto 1: Objetos, referências e configuração confiável10 Questões de Prática
Questão 1 de 10
O que este código imprime?
label = "cedar"
label.upper()
print(label)
Mostrar respostaOcultar resposta
upper() retorna uma nova string, mas essa chamada não armazena o resultado. O nome label ainda se refere à string original, então a saída é cedar. Esperar CEDAR trata o método de string como uma atualização no próprio objeto; strings são imutáveis.Questão 2 de 10
O que este código imprime?
a = [6, 2]
b = a
a = sorted(a)
b.append(9)
print(a, b)
Mostrar respostaOcultar resposta
sorted(a) cria uma nova lista ordenada, e a atribuição faz a se referir a ela. b ainda se refere à lista original, então a adição altera essa lista para [6, 2, 9]. Manter ambos os nomes na mesma lista ignora a reatribuição de a.Questão 3 de 10
O que first.name contém ao final?
class Badge:
pass
first = Badge()
second = Badge()
first.name = "Rae"
second.name = "Ivo"
first.nmae = "Sol"
Mostrar respostaOcultar resposta
"Rae" a first.name, e ele nunca recebe outra atribuição. O nome escrito incorretamente nmae cria um atributo separado em first, enquanto second.name pertence a outro objeto. A atribuição de um novo atributo é permitida, então o erro de escrita não provoca um erro por si só.Questão 4 de 10
Mostrar respostaOcultar resposta
Questão 5 de 10
O que este código imprime?
class Counter:
def __init__(self, start=4):
self.value = start
c = Counter(9)
print(c.value)
Mostrar respostaOcultar resposta
self e passa 9 como start. O inicializador armazena esse valor em self.value, então a saída é 9. O valor padrão 4 é usado somente quando o código chamador omite start; ele não substitui um argumento explícito.Questão 6 de 10
Por que a última linha falha?
class Lamp:
def __init__(self, brightness):
brightness = brightness
lamp = Lamp(7)
print(lamp.brightness)
Mostrar respostaOcultar resposta
brightness = brightness reatribui o parâmetro local e nunca cria um atributo na lâmpada. Portanto, a leitura provoca AttributeError; a configuração deve armazenar self.brightness = brightness. Retornar o número de __init__ causaria outro TypeError, não criaria o atributo.Questão 7 de 10
O que este código imprime?
class Folder:
def __init__(self, tags=[]):
self.tags = tags
a = Folder()
b = Folder()
a.tags.append("urgent")
a.tags = []
print(b.tags, a.tags)
Mostrar respostaOcultar resposta
"urgent" nessa lista compartilhada; a atribuição posterior dá apenas a a uma nova lista vazia. Esperar duas listas vazias confunde substituir a referência de um atributo com esvaziar o objeto original compartilhado.Questão 8 de 10
O que este código imprime?
class Ticket:
fee = 3
x = Ticket()
y = Ticket()
x.fee = 8
Ticket.fee = 5
print(x.fee, y.fee)
Mostrar respostaOcultar resposta
x.fee cria um atributo de instância que sombreia o valor da classe. y não tem uma taxa própria, então, após a atualização da classe, encontra 5 em Ticket. Esperar 5 5 ignora o valor separado armazenado em x, que a atribuição à classe não substitui.Questão 9 de 10
O que este código imprime?
class Job:
count = 0
def __init__(self):
self.count += 1
a = Job()
Job.count = 10
b = Job()
print(a.count, b.count, Job.count)
Mostrar respostaOcultar resposta
a lê a contagem de classe 0 e armazena a contagem de instância 1. Depois que a classe muda para 10, criar b armazena seu próprio 11; nenhum dos inicializadores atualiza Job.count. O resultado 1 11 11 trata a atribuição aumentada na instância como uma atualização do contador de classe.Questão 10 de 10
O que este código imprime?
class Batch:
def __init__(self, size):
if size <= 0:
raise ValueError("size must be positive")
self.size = size
batch = Batch(6)
try:
batch = Batch(0)
except ValueError:
pass
print(batch.size)
Mostrar respostaOcultar resposta
Batch(0) lança uma exceção antes de retornar, então a atribuição a batch nunca acontece. A exceção é capturada, e batch ainda se refere ao objeto válido anterior, com tamanho 6. Uma chamada de criação que falha não substitui a referência existente do código chamador por um resultado parcial.Conjunto 2: Métodos, mudanças de estado e propriedades10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
self quando o programa chama panel.area()?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Qual alteração permite que o código chamador calcule double?
class Pace:
def __init__(self, minutes):
self.minutes = minutes
def seconds(self):
print(self.minutes * 60)
p = Pace(3)
double = p.seconds() * 2
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
"12,14"?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
O que este código imprime?
class Tank:
def __init__(self):
self.level = 5
def add(self, amount):
self.level += amount
a = Tank()
b = a
result = b.add(4)
print(a.level, result)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
O que este código imprime?
import copy
class Log:
def __init__(self):
self.entries = []
a = Log()
b = copy.copy(a)
b.entries.append("open")
b.entries = ["closed"]
print(a.entries, b.entries, a is b)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
name?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Por que atribuir a reading.value chama repetidamente este método de definição?
class Reading:
@property
def value(self):
return self._value
@value.setter
def value(self, number):
self.value = number
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
remove(n) deve rejeitar quantidades não positivas e retiradas maiores que o valor atual. Qual sequência deixa o estado inalterado em qualquer uma das rejeições?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
O que este código imprime?
class Dial:
def __init__(self, value):
self.value = value
@property
def value(self):
return self._value
@value.setter
def value(self, number):
if not 0 <= number <= 9:
raise ValueError("out of range")
self._value = number
d = Dial(4)
try:
d.value = 12
except ValueError:
pass
print(d.value)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
area com uma propriedade somente leitura a partir de width e height. Um objeto tem largura 6 e altura 2; depois, é atribuído 8 à sua largura. O que a leitura de obj.area retorna?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 3: Exibições legíveis e operadores úteis10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
__str__ quanto __repr__. Qual método fornece o texto de uma instância quando ela aparece dentro de uma lista impressa?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
O que este código imprime?
class Tag:
def __init__(self, text):
self.text = text
def __repr__(self):
return f"Tag({self.text!r})"
t = Tag("ok")
print(t)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
str(marker) provoca TypeError quando seu método __str__ apenas chama print(self.code)?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Label define igualdade pelo texto e não define __hash__. Duas etiquetas contêm o mesmo texto. O que acontece quando são colocadas em um conjunto?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Mark define apenas __lt__, comparando notas numéricas, e nenhuma outra comparação personalizada. Para a com nota 2 e b com nota 7, o que acontece?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Vector define __mul__ para vector * number, mas não tem um método de multiplicação refletida. Qual método deve ser adicionado para permitir também number * vector?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
__eq__ usando code e __hash__ como hash(self.code). Seus objetos são usados como chaves de dicionário. Qual alteração de projeto torna confiável o comportamento das chaves?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Queue define __len__ como o número de tarefas pendentes e não define __bool__. Sem tarefas pendentes, quais são os valores de len(q) e bool(q)?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
O que a última linha imprime?
class Offset:
def __init__(self, value):
self.value = value
def __add__(self, other):
return Offset(self.value + other.value)
a = Offset(6)
b = a
a = a + Offset(4)
print(a.value, b.value, a is b)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Rank.__lt__ ordena registros por prioridade. Um relatório deve ordenar esses registros por momento de criação sem mudar sua ordem usual. Qual abordagem é adequada?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 4: Objetos que colaboram e projetos claros10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Workshop armazena objetos Tool em self.tools. O que workshop.tools[0].label lê?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
line.cost() em cada linha armazenada. Um desconto por quantidade muda a forma de calcular o custo de cada linha. Onde essa regra deve ficar?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
Qual total o código imprime?
class Line:
def __init__(self, rate, count):
self.rate = rate
self.count = count
def cost(self):
return self.rate * self.count
x = Line(4, 3)
a = [x]
b = [x, Line(2, 5)]
a[0].count = 6
print(sum(line.cost() for line in b))
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
find(name) de uma coleção retorna um objeto em caso de sucesso e None em caso de falha. Qual código chamador trata ambos os casos antes de ler result.name?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Position.midpoint(other) retorna uma nova posição cujas coordenadas são as médias. Se a está em (2, 8) e b em (10, 4), qual é o resultado de c = a.midpoint(b)?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
send_to(other, n) chama self.remove(n) e depois other.add(n). remove rejeita uma quantidade maior que o estoque do remetente antes de alterar qualquer coisa; add aceita quantidades positivas. Começando com estoque 9 no remetente e 4 no destinatário, um envio de 3 é bem-sucedido, depois tenta-se enviar 8 e a exceção é capturada. Quais estoques restam?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
add do destinatário. O destinatário rejeita a quantidade antes de alterar seu próprio estoque. Não há código de reversão, e o código chamador captura a exceção. Qual estado permanece?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
A estante deve rejeitar um terceiro livro e manter seus dois livros existentes. Após o erro capturado abaixo, qual asserção revela a implementação defeituosa?
class Shelf:
def __init__(self):
self.limit = 2
self.books = []
def add(self, title):
self.books.append(title)
if len(self.books) > self.limit:
raise ValueError("shelf full")
shelf = Shelf()
shelf.add("Atlas")
shelf.add("Birch")
try:
shelf.add("Cove")
except ValueError:
pass
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 5: Aplique as ideias em novas situações10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
items, o que isinstance(items, list) retorna?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
O que este código imprime?
class Tray:
labels = []
a = Tray()
b = Tray()
a.labels.append("red")
b.labels = ["blue"]
Tray.labels.append("green")
print(a.labels, b.labels)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
O que este código imprime?
class Kit:
def __init__(self, parts=None):
self.parts = [] if parts is None else list(parts)
source = [[1]]
k = Kit(source)
source.append([2])
source[0].append(3)
print(k.parts)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
_reading. Seu inicializador atribui diretamente a self._reading, então Meter(-2) funciona. Qual alteração faz a criação usar a mesma verificação das atribuições públicas posteriores?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Key compara igualdade apenas por name, e seu hash também usa name. Duas instâncias diferentes começam com o nome "north"; uma se torna chave de dicionário. Por que o nome dessa chave deve permanecer estável?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
members separada, mas ambas as listas contêm a mesma instância de Member. Um clube altera o nome desse membro. Agora os clubes precisam de nomes de membros independentes. Qual alteração é necessária?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
__str__ útil, mas uma lista impressa de mensagens ainda mostra descrições padrão de objetos. Qual adição melhora essas entradas da lista?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
a.combine(b) deve deixar ambas as entradas inalteradas. Seu corpo chama self.parts.extend(other.parts) e depois retorna self. Qual comportamento essa implementação realmente tem?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
class Vault, a configuração atribui self.__code = "x". O que explica por que vault.__code falha enquanto vault._Vault__code pode funcionar?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
take de uma classe usa assert n > 0 como única verificação da entrada do código chamador. A regra deve valer mesmo quando o Python é executado com otimização ativada. Qual alteração é necessária?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Travou em uma questão sua? Ajuda com Tarefas
Termos-Chave
A
Argumento padrão
balance=0 no inicializador, Account("Rae") começa com zero sem fornecer um argumento de saldo.Asserção
AssertionError se sua condição for falsa; o Python pode omiti-la na execução otimizada.assert acct.balance == 75 verifica o comportamento; entradas rejeitadas do código chamador ainda precisam de validação explícita.Atributo
book.title = "Emma" armazena um título, que pode ser lido avaliando book.title.Atributo de armazenamento
score lê _score; armazenar em score dentro de seu próprio método de definição o chamaria repetidamente.Atributo de classe
MAX_TOPPINGS de toda a classe pode fornecer o limite padrão lido por meio de vários objetos de pizza.Atributo de instância
size diferente e uma lista de ingredientes separada por meio de atribuições em self.Atributo interno
balance, enquanto os próprios métodos da classe gerenciam o _balance armazenado.B
Busca de atributo
p não tiver um limit próprio, ler p.limit pode encontrar o valor compartilhado limit definido em sua classe.C
Classe
Book pode criar muitos livros, cada um armazenando um título diferente e compartilhando as definições de métodos.Composição
Condição de execução principal
main() sob if __name__ == "__main__": para que outro programa possa importar as classes sem iniciá-lo.Contêiner
cart.items[0] alcança seu primeiro item armazenado.Cópia profunda
copy.deepcopy(account) também copia essa lista, então adicionar um item ao histórico da cópia deixa o original intacto.Cópia superficial
copy.copy(account) ainda pode compartilhar essa lista com a original.D
Delegação
E
Encapsulamento
Estado
F
Função de chave
sorted(records, key=by_date) sem alterar o método usual de comparação da classe de registro.H
Hashabilidade
__eq__ sem __hash__ torna-se não hashável, mesmo que suas instâncias funcionem em uma lista.I
Identidade
is testa se duas referências acessam esse mesmo objeto.a == b enquanto a is b é falso, pois suas identidades diferem.Igualdade de valores
__eq__, em vez de exigir a mesma identidade de objeto.Inicialização
Instância
Book() e Book() criam duas instâncias de livro separadas, embora ambas tenham o mesmo tipo.Invariante
0 e 100 durante a configuração e em atribuições posteriores.M
Método
"cedar".upper() executa um método de string, enquanto scores.append(7) executa um método em uma lista.Método de acesso
area() de um retângulo lê sua largura e altura e retorna um número sem redimensioná-lo.Método de alteração
Método de definição
score que rejeita 105 antes de atribuir a _score deixa uma nota anteriormente válida inalterada.Método de instância
self.r.area(), o Python fornece r ao método para que ele possa multiplicar a largura e a altura desse retângulo.Método especial
__str__ ao converter um objeto em sua forma legível como string e __len__ para seu comprimento.Método vinculado
r.area obtém um método vinculado; adicionar parênteses, como em r.area(), executa-o e retorna a área calculada.Mutabilidade
upper() a uma string retorna uma nova string.N
None
None é o valor único do Python para um resultado ausente ou indisponível, também útil para uma relação à qual nenhum objeto foi atribuído ainda.borrower = None até que um membro o tome emprestado, então o código verifica antes de ler o nome dessa pessoa.Notação com ponto
cart.items, o nome antes do ponto identifica o objeto e o nome depois dele seleciona seu atributo de itens.NotImplemented
NotImplemented é um valor de retorno especial que indica que um método de comparação ou numérico não aceita os operandos fornecidos.NotImplemented para uma string, deixando o Python lidar com o par não aceito.O
Objeto
"hello" e a lista [2, 5] são objetos, embora seus tipos ofereçam operações diferentes.Objeto passado como argumento
other em p.midpoint(q) se refere a q, cujas coordenadas o método lê para calcular seu resultado.Operação refletida
3 * vector, o Python pode usar o __rmul__ do vetor quando a multiplicação de inteiros não consegue lidar com esse vetor.P
Projeto de classe
Propriedade
student.score pode chamar um método de leitura, e atribuir student.score = 90 pode chamar um método de definição que valida o valor.R
Receptor
self do método.sender.transfer_to(receiver, 5), sender recebe a chamada de transferência; o argumento de conta é o destino.Referência
Referência alternativa
backup = entries, adicionar um item por meio de backup também altera a lista acessada por meio de entries.Representação alternativa
__repr__ personalizado quando uma classe não define um __str__ personalizado.__repr__ pode melhorar tanto print(point) quanto a aparência do ponto dentro de uma lista impressa.Representação em string
__str__, normalmente destinado aos usuários do programa."(3, 4)" quando impresso diretamente, deixando seus atributos numéricos de coordenadas inalterados.Representação para o programador
__repr__, usado para inspeção e dentro de exibições de contêineres."Book('Emma', 'Jane Austen', 1815)", incluindo campos de texto entre aspas.Responsabilidade
Resultado da busca
None, indicando que nenhuma correspondência foi encontrada.found is not None antes de ler found.name de uma busca de item no carrinho.S
self
self recebe, por convenção, a instância atual, permitindo que um método leia ou altere os atributos desse objeto.self.owner = owner, o lado esquerdo armazena dados na instância e o lado direito lê um parâmetro local.Sobrecarga de operadores
__add__ de um vetor pode fazer a + b produzir um novo vetor formado pela soma de suas coordenadas correspondentes.Sombreamento
p.limit = 8, alterar Pizza.limit não substitui o limite separado já armazenado em p.T
Teste de comportamento
Tipo
type([2, 5]) retorna a classe list, e isinstance([2, 5], list) confirma que o valor é uma lista.Transformação de nome
Acc, self.__balance torna-se _Acc__balance, que continua acessível pelo nome transformado.TypeError
TypeError informa que uma operação recebeu um tipo inadequado ou foi chamada com argumentos que sua definição não aceita.TypeError porque essa comparação não pode ordenar texto e zero.V
Validação
Valor de retorno
r1.area() + r2.area() some resultados, enquanto apenas imprimir deixa None como cada resultado.Valor lógico em contexto
__bool__, um comprimento definido como zero o torna falso.__len__ e sem __bool__ personalizado faz if playlist: ignorar seu corpo.Valor padrão mutável
items=[] for armazenado diretamente, dois objetos criados sem esse argumento podem se referir à mesma lista.ValueError
ValueError informa que um argumento tem um tipo aceitável, mas seu valor está fora do que a operação aceita.-2 pode provocar ValueError com a mensagem "width must be positive".#
__init__
__init__ inicializa uma instância depois que o Python a cria e deve retornar None quando a inicialização termina.Counter(5) passa a nova instância e 5 ao inicializador antes de retornar o contador configurado.__lt__
__lt__ implementa a comparação menor que, fornecendo uma ordenação que operações como sorted podem usar.__lt__ baseado em notas permite que uma lista de objetos de alunos seja ordenada da menor para a maior nota.Sobre esta aula
Crie seus próprios Materiais de Estudo
Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.