Python - Parte 2
Uso de listas e strings, outras coleções e classes
Roteiro
Mais sobre listas e Strings
Métodos úteis para esses dois tipos de dados
- Listas: ordenação, sublistas e inserção
- Strings: Formatação, maiúsculas, …
Listas - operações úteis
lista = ["Alice","Bob","Carol","Bob","Débora"]
lista.sort() #ordena a lista
listaConcat = lista[1:5] #retorna uma lista a partir da posição 1 até a posição 4
listaConcat = lista[:5] #retona uma lista da posição 0 até a posição 4
listaConcat = lista[2:] #retorna a lista sem as psições 0 e 1
lista.insert(0,"Carlos") #adiciona 'Carlos' no inicio da lista
- sort: os tipos devem ser compatíveis para ordenação
- Clique aqui para ver documentação completa
Strings - operações úteis
x = "({ddd}) {telprefixo}-{telfinal}".format(ddd=31,telprefixo=555,telfinal=9875)#x = '(31) 555-9875'
y = "uma frase de impacto"
termos = y.split(" ") #termos = ['uma','frase','de','impacto']
z = "casa".replace("a","x") #z = 'cxsx'
z = "casa".upper() #z = "CASA"
#strings podem ser tratadas como uma lista de caracteres
w = y[0] #w= 'u'
w = y[4:] #w = 'frase de impacto'
frutas = ", ".join(["pera","uva","banana"]) #frutas = "pera, uva, banana"
Strings - alternativa ao format
ddd = 31
telprefixo = 555
telfinal=9875
x = f"({ddd}) {telprefixo}-{telfinal}"
Mais coleções
Outras coleções e seus métodos/funções úteis
- Conjuntos
- Tuplas
- Dicionários
- Funções/métodos úteis
Tuplas
- Similar à listas, porém imutável
- Instanciação (duas formas):
x = (1,4,5)
x = 1,4,5
- Caso haja apenas um elemento, deveremos colocar uma virgula no final ex:
x = 'casa',
oux=('casa',)
- Útil para atribuições e para retornar, em uma função, mais de um valor
def exemplo():
return "casa",2948
x,y = 1,5# x = 1 e y = 5
nome, num = exemplo() #nome = 'casa' e num = 2948
Conjuntos
- Conjunto: coleção não ordenada de elementos únicos
- Cada elemento deve ser
hashable
, ou seja:- Imutável
- Implementa os métodos:
__hash__()
e__eq__()
- Exemplos: string, inteiro, float, tuplas
- Uso:
frutas = {"pera","uva","banana","banana"} #instanciação
print(frutas)
for fruta in frutas: #percorrendo valores
print(fruta)
Operações com conjuntos
- Interseção:
&
- União:
|
- Diferença:
-
- Pertence:
in
- adicionar um elemento:
add
cesta1 = {"pera","uva","banana"}
cesta2 = {"pera","abacaxi"}
x = cesta1 & cesta2 #x = {"pera"}
x = cesta1 | cesta2 #x = {"pera","uva","banana","abacaxi"}
x = cesta1 - cesta2 #x = {"banana","uva"}
cesta1.add("cebola")#cesta1={"pera","uva","banana","cebola"}
print("abacaxi" in cesta1) #Imprime: False
print("abacaxi" in cesta2) #Imprime: True
Função set
- Inicializa um conjunto como conjunto vazio
- Converte uma elemento iterável em conjunto
- Elemento iterável é qualquer tipo de variável que podemos iterar (usando for, por exemplo):
- Exemplo: string, conjuntos e listas
- Para criarmos um conjunto vazio, executamos
set()
(e não{}
)
x = set([1,5,6,9]) #x = {1,5,6,9}
x = set("casa") #x = {'c', 'a', 's', 'a'}
x = set() #x = conjunto vazio
Dicionários (1/2)
- Mapeia uma chave a um valor
- As chaves são
hashable
- Os valores podem ser qualquer tipo de dado
- As chaves são
- Uso:
x = {} #inicia um dicionário vazio
x['Alice'] = 3
x[23] = 5
x[32,32] = 10# x = {(32, 32): 10, 'Alice': 3, 23: 5}
idc_remissivo = {'casa':{1,3},'verde':{3,5,6}}
idc_remissivo['casa'].add(7) #idc_remissivo = {'casa':{1,3,7},'verde':{3,5,6}}
Dicionários (1/2)
from datetime import datetime #inclusão do módulo datetime
voo = {
'companhia': 'Gol',
'numero': 815,
'decolagem': {
'IATA': 'SYD',
'horario': datetime(2005, 7, 14, 12, 30),#
'cidade': 'Sydney'
},
'chegada': {
'IATA': 'LAX',
'horario': datetime(2005, 7, 14, 15, 30),
'cidade': 'Los Angeles'
}
}
#imprimirá: 2005-07-14 12:30:00
print(voo['decolagem']['horario'])
Dicionários - erros e funções úteis (1/2)
- Erro ao tentar acessar uma chave inexistente:
x = {"Alice":16, "Bob":19, "Carol": 20}
print(x["Débora"])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Débora'
Dicionários - erros e funções úteis (2/2)
in
: Verifica se um chave existe:keys()
: Retorna a lista de chavesvalues()
: Retorna a lista de valoresitems()
: Retorna a lista de itens (Tupla(chave,valor)
) ``
x = {"Alice":16, "Bob":19, "Carol": 20, "Débora":21}
if "Débora" in x:
print(f"A chave 'Débora' possui o seguinte valor: {x['Débora']}")
y = x.keys() #y = ['Débora', 'Alice','Bob','Carol']
y = x.values() #y = [19, 16, 20, 21]
y = x.items() #y = [('Débora',21), ('Alice',16),('Bob',19),('Carol', 20)]
Dicionários - Navegando nos elementos
-
Pela chave:
x = {"nome":"hasan", "altura":1.77, "cidade":"Belo Horizonte"} for chave in x.keys(): print(chave)
cidade
nome
altura -
Pelo valor:
x = {"nome":"hasan", "altura":1.77, "cidade":"Belo Horizonte"} for valor in x.values(): print(valor)
hasan
1.77
Belo Horizonte -
Pela chave e valor
x = {"nome":"hasan", "altura":1.77, "cidade":"Belo Horizonte"} for ch,val in x.items(): print(ch+": "+str(val))
cidade: Belo Horizonte
altura: 1.77
nome: hasan -
O dicionário não é ordenado
Estruturas heterogêneas - Exemplo
profs_web = [{"nome":"Hasan","cidade":"Belo Horizonte"},
{"nome":"Coutinho","cidade":"Belo Horizonte"}]
for prof in profs_web:
print(f"Professor: {prof['nome']} Cidade: {prof['cidade']}")
Professor: Hasan Cidade: Belo Horizonte
Professor: Coutinho Cidade: Belo Horizonte
Classes
Uso de Programação Orientada a Objetos
- Declaração
- Construtor e Instanciação
- Atributos estáticos e não estáticos
- Anotação
@property
Declaração
from datetime import date
class Pessoa():
#construtor possui o nome __init__
def __init__(self, nome):
self.nome = nome
self.telefones = []
#método simples
def adiciona_telefone(self,tel):
self.telefones.append(tel)
#transforma o objeto numa string ao executar str(objeto)
def __str__(self):
return f"{self.nome} - {self.telefones}"
def __repr__(self):
return str(self)
self
: representa o objeto corrente- Atributos: devem ser criados no contrutor, atribuindo um valor a ele
- Métodos: Similar às funções porém, o primeiro argumento deve ser o objeto corrente (
self
)
Instanciação
jose = Pessoa("José")
jose.adiciona_telefone("31-5555-5555")
jose.nome = "José Pereira"
print(jose.telefones) #imprime ["31-5555-5555"]
print(jose.nome) #imprime 'José Pereira'
print(jose) #imprime "José Pereira - 17/10/2018 - ['31-5555-5555']"
- Os atributos são públicos.
- Colocamos com prefixo
_
atributos/métodos para informarmos que são privados- Python não possui atributos que sejam verdadeiramente privados
- O prefixo
__
é apenas para indicar que o método/atributo não será sobreposto pelas subclasses- Se criarmos um atributo
__a
, ainda podemos acessá-lo de maneira pública usando_Nome-da-classe__a()
- Se fizermos
__a__
, isso não ocorre! Duplo underscore no prefixo e no sufixo indica atributos/metodos/variáveis especiais do python
- Se criarmos um atributo
Anotação @property
e o Encapsulamento
- Vamos supor que temos nossa classe Pessoa
class Pessoa():
def __init__(self,nome,data_nascimento=date.today()):
self.nome = nome
- Desejamos, agora, alterar o atributo
nome
paraprim_nome
esobrenome
. - Como fazer isso sem alterar os locais em que o atributo
nome
foi chamado? Por exemplo:
joao = Pessoa("João")
joao.nome = "João da Silva"
Anotação @property - Usada para sobrecarregar a atribuição e obtenção de um atributo
-
Atributos calculados:
class Funcionario(): def __init__(self,nome,salario): self.nome = nome self.salario = salario @property def salario_liquido(self): return self.salario*0.8
-
Encapsulamento:
class Funcionario(): def __init__(self,nome,salario): self.nome = nome self.salario = salario @property def salario(self): return self._salario @salario.setter def salario(self,val): if(val<0): raise ValueError("Erro: não é possível salário negativo") self._salario = val
Atributo @property - Acesso ao atributo
joao = Funcionario('João',234)
print(joao.salario_liquido)
joao.salario = 345
print(joao.salario)
joao.salario_liquido = 45 #erro 'AttributeError: can't set attribute'
Alteração do atributo nome
da classe Pessoa
class Pessoa():
def __init__(self,nome,data_nascimento=date.today()):
self.nome = nome
@property
def nome(self):
return f"{self.prim_nome} {self.sobrenome}"
@nome.setter
def nome(self,val):
arr_nomes = val.split(" ")
self.prim_nome = arr_nomes[0] if len(arr_nomes)>0 else ""
self.sobrenome = " ".join(arr_nomes[1:])
- Assim, o código abaixo irá funcionar, sem ser modificado:
joao = Pessoa("João")
joao.nome = "João da Silva"
Atributos estáticos
- São criados dentro da classe
import datetime date
class Pessoa():
pessoas_criadas = 0
def __init__(self,nome,data_nascimento=date.today()):
self.nome = nome
self.data_nascimento = data_nascimento
self.telefones = []
Pessoa.pessoas_criadas += 1
jose = Pessoa("José")
maria = Pessoa("Maria")
print(Pessoa.pessoas_criadas) #Imprime 2
Implementando comparadores
class Pessoa():
pessoas_criadas = 0
def __init__(self,cpf,nome):
self.cpf = cpf
self.nome = nome
def __eq__(self,outro):
return self.cpf == outro.cpf
-
Podemos implementar:
__lt__
(para<
);__gt__
(para>
)__ne__
(para!=
)__ge__
(para>=
);__le__
(para<=
)
-
Mesmo implementando
__eq__
você deve implementar o__ne__
. Para evitar isso, use a anotaçãototal_ordering
saiba mais
Objetos que podem ser chamados: método __call__
- Objetivo: queremos calcular o resultado de um polinômio de grau n no formato cn xnn+…+c1 x1^1+ c0n.
- Por exemplo, queremos que seja calculado o resultado do polinomio de grau dois: 3x2+2x+4 que, para x=10 o resultado será 324.
from typing import List
class Polinomio:
def __init__(self, coeficientes:List):
self.coeficientes = coeficientes
def __call__(self, x):
somatorio = 0
for expoente_i,coef_i in enumerate(self.coeficientes):
somatorio += coef_i* x**expoente_i
return somatorio
polinomio_1 = Polinomio([4,2,3])
print(f"x = 10: {polinomio_1(10)}") #x = 10: 324
print(f"x = 13: {polinomio_1(13)}") #x = 13: 537
Referência: python-course.eu
Convenção de nomenclatura
- Nomes de atributos, métodos e funções: tudo_minuscula_separando_por_underscores
- Classes: DeveSerCapitalizado
- Constantes: MAISCULAS_SEPARANDO_POR_UNDERSCORES Veja mais aqui
Classes
Herança, Métodos abstratos e estáticos
- Heraça
@classmethod
e@staticmethod
- import
Herança
class Pessoa():
def __init__(self, nome):
self.nome = nome
def __str__(self):
return "Nome: "+self.nome
def __repr__(self):
return str(self)
class Funcionario(Pessoa):
def __init__(self,nome,salario):
super().__init__(nome)
self.salario = salario
def __str__(self):
return f"{super().__str__()} Salario R$ {self.salario}"
Métodos estáticos e de classe
class Pessoa():
@staticmethod
def x():
print("Oi")
@classmethod
def y(cls):
print(str(cls))
class Funcionario(Pessoa):
pass
- cls: classe que foi invocada em tempo de execução:
>>> Funcionario.y()
<class '__main__.Funcionario'>
>>> Pessoa.y()
<class '__main__.Pessoa'>
class Pessoa():
def __init__(self,nome):
self.nome = nome
@classmethod
def instancia_pessoas(cls,n):
pessoas = []
for i in range(n):
pessoas.append(cls("Pessoa "+str(i)))
return pessoas
class Funcionario(Pessoa):
pass
- Instancia pessoas ou funcionarios, dependendo de qual classe chamada:
>>> Funcionario.instancia_pessoas(2)
[<__main__.Funcionario object at 0x7fe7f773ac88>, <__main__.Funcionario object at 0x7fe7f773acc0>]
>>> Pessoa.instancia_pessoas(2)
[<__main__.Pessoa object at 0x7fe7f773aba8>, <__main__.Pessoa object at 0x7fe7f773add8>]
Prática
Uso de Programação Orientada a Objetos
- Declaração
- Construtor e Instanciação
- Atributos estáticos e não estáticos
- Anotação
@property
Para esta prática, use Jupyter crie uma classe em cada célula. Logo após, crie uma célula com os testes de toda a implementação.
Classe Autor
Uma biblioteca possui livros e autores. Livro, autor e biblioteca serão classes que você deverá criar da seguinte forma:
- Neste código use a convenção de nomenclatura correta (veja slide)
- Autor: Possui o nome representado por três atributos: primeiro nome, nome do meio e último nome além da data de nascimento (você pode usar a classe pessoa e adaptá-la). Todos esses atributos devem ser fornecidos no construtor, porém, o nome do meio é opcional (valor default = ‘’).
- O autor possuirá o atributo calculado
nome_como_citado
que irá retornar o último nome maiúculo e a primeira letra do primeiro nome e, logo após, um ponto. Exemplo: “DALIP D.” sendo que Dalip é o último nome de Daniel é o primeiro nome. Nesse atributo, o nome do meio não será usado.
- O autor possuirá o atributo calculado
Classe Livro e Biblioteca
- Livro: Possui os atributos: titulo, ano e uma lista de autores
- O título não poderá ser vazio, caso seja, você irá lançar uma exceção ValueError. Use a anotação
@property
para isso (veja slide). - No construtor, a lista de autores pode ser omitida (sendo uma lista vazia
[]
por padrão)
- O título não poderá ser vazio, caso seja, você irá lançar uma exceção ValueError. Use a anotação
- Biblioteca: possui uma lista de livros. Ela deve possuir um atributo calculado
livros_por_autor
que utilizará a lista de livros para retornar um dicionário onde cada chave será o nome de um autor e, cada valor, será a lista de livros deste autor.
Para cada uma das classes implementadas, faça o método __str__
e o método __repr__
.