Apaixonando-se por Python

Quer baixar o jupyter notebook? Clique aqui!

In [2]:
palestrante = {
    "assunto": "Apaixonando-se por Python!",
    "autor": "Bernardo Fon- ops, Luciano Ratamero",
    "empresa": "Simple Fractal",
    "github": "lucianoratamero",
    "twitter": "lucianoratamero",
    "todos os lugares": "lucianoratamero"
}

Motivo nº 0

In [3]:
import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Motivo nº 1:

Os tipos built-in

Vamos ver como funcionam 3 tipos básicos de Python:

  • strings
  • dicionários
  • listas
In [4]:
output = "Palestra: {assunto}\n\tAutor: {autor}\n\tgithub.com/{github}\n\t@{twitter}".format(**palestrante)
In [5]:
print(output)
Palestra: Apaixonando-se por Python!
	Autor: Bernardo Fon- ops, Luciano Ratamero
	github.com/lucianoratamero
	@lucianoratamero
In [6]:
output = f"""
Palestra: {palestrante["assunto"]}
   Autor: {palestrante["autor"]}
          github.com/{palestrante["github"]}
          @{palestrante["twitter"]}"""
print(output)
Palestra: Apaixonando-se por Python!
   Autor: Bernardo Fon- ops, Luciano Ratamero
          github.com/lucianoratamero
          @lucianoratamero
In [7]:
### Dicionários

print(palestrante['assunto'])
print()

for chave, valor in palestrante.items():
    print("{} --> {}".format(chave, valor))
Apaixonando-se por Python!

assunto --> Apaixonando-se por Python!
autor --> Bernardo Fon- ops, Luciano Ratamero
empresa --> Simple Fractal
github --> lucianoratamero
twitter --> lucianoratamero
todos os lugares --> lucianoratamero
In [8]:
### KeyError
palestrante['gênero']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-8-5de21d912861> in <module>()
      1 ### KeyError
----> 2 palestrante['gênero']

KeyError: 'gênero'
In [9]:
palestrante.get('gênero', 'não-binário')
Out[9]:
'não-binário'
In [10]:
### Manipulando strings

texto = 'este é um texto qualquer'

print("Upper: ", texto.upper())
print("Title: ", texto.title())
print("Só tem caracter: ", texto.isalpha())
print("É número: ", "42".isdigit())
Upper:  ESTE É UM TEXTO QUALQUER
Title:  Este É Um Texto Qualquer
Só tem caracter:  False
É número:  True
In [11]:
### Substrings
manchete = "Banda de hardcore não paga engenheiro de som e ganha versão dance de sua música. Grupo Altitudes se defendeu alegando que não estava financeiramente estável"

do_primeiro_ao_10 = manchete[:10]
do_10_ao_35 = manchete[10:35]
os_20_utimos = manchete[-20:]

print("Primeiro caracter\n\t{}".format(manchete[0]))
print("\n10 primeiros:\n\t{}".format(do_primeiro_ao_10))
print("\nDo 10º ao 35º caracter:\n\t{}".format(do_10_ao_35))
print("\nOs 20 útlimos:\n\t{}".format(os_20_utimos))
Primeiro caracter
	B

10 primeiros:
	Banda de h

Do 10º ao 35º caracter:
	ardcore não paga engenhei

Os 20 útlimos:
	anceiramente estável
In [12]:
### Substrings
print("Dance? ", "versão dance" in manchete)
print("E eletro?", "versão eletro" in manchete)
Dance?  True
E eletro? False
In [13]:
### Pegar todas as palavras com letras maiúsculas

palavras = manchete.split(' ')

maiusculas = []
for palavra in palavras:
    if palavra[0].isupper():
        maiusculas.append(palavra)

print("Nº de palavras: ", len(palavras))
print("Nº de palavras com letra maiúscula: ", len(maiusculas))
for palavra in maiusculas:
    print('\t{}'.format(palavra))
Nº de palavras:  25
Nº de palavras com letra maiúscula:  3
	Banda
	Grupo
	Altitudes
In [14]:
### List comprehension

def comeca_com_maiuscula(palavra):
    return palavra[0].isupper()

palavras = manchete.split(' ')
maiusculas = [p for p in palavras if comeca_com_maiuscula(p)]

print("Nº de palavras com letra maiúscula: ", len(maiusculas))
for palavra in maiusculas:
    print('\t{}'.format(palavra))
Nº de palavras com letra maiúscula:  3
	Banda
	Grupo
	Altitudes

Motivo nº 2:

Built functions

Toda tarefa essencial já está na tua mão! Todas as funções

In [15]:
numeros = range(100)

print("Min", min(numeros))
print("Max", max(numeros))
print("Somatória", sum(numeros))
Min 0
Max 99
Somatória 4950
In [16]:
numeros = [2, 5, 1, 3, 9, 6]
print(numeros)
print()
print("Ordem", sorted(numeros))
print("Ordem reversa", sorted(numeros, reverse=True))
[2, 5, 1, 3, 9, 6]

Ordem [1, 2, 3, 5, 6, 9]
Ordem reversa [9, 6, 5, 3, 2, 1]
In [17]:
numeros = [2, 5, 1, 3, 9, 6]

numeros.append(9)
numeros.append(2)

print(sorted(numeros))
print()
conj = set(numeros)
sorted_conj = sorted(conj)

print(type(conj))
print(conj)
print(type(sorted_conj))
print(sorted_conj)
[1, 2, 2, 3, 5, 6, 9, 9]

<class 'set'>
{1, 2, 3, 5, 6, 9}
<class 'list'>
[1, 2, 3, 5, 6, 9]
In [18]:
print(sorted(numeros))
print(numeros)
numeros.sort()
print(numeros)
[1, 2, 2, 3, 5, 6, 9, 9]
[2, 5, 1, 3, 9, 6, 9, 2]
[1, 2, 2, 3, 5, 6, 9, 9]

Motivo nº 3 :

Standard Library

  • random
  • datetime
  • collections.namedtuple
In [19]:
import random

numeros = list(range(100))

print('Aleatórios:')
for i in range(3):
    print('    {}'.format(random.choice(numeros)))

random.shuffle(numeros)
print('Nova sequência:')
for numero in numeros[:10]:
    print('    {}'.format(numero))
Aleatórios:
    16
    44
    13
Nova sequência:
    85
    68
    20
    93
    62
    32
    52
    95
    71
    81
In [20]:
from datetime import datetime, timedelta

agora = datetime.now()
print(agora)
print(agora.date())

amanha = agora + timedelta(days=1)
print()
print("Amanhã: ", amanha.date())

ontem = agora + timedelta(days=-1)
print()
print("Ontem: ", ontem.date())
2017-12-18 13:35:15.765837
2017-12-18

Amanhã:  2017-12-19

Ontem:  2017-12-17
In [21]:
pessoas = ['Luciano', 'Maria', 'José']
sobrenome = ['A', 'B', 'C']
idades = [28, 31, 40]
In [22]:
pessoas_com_idades = zip(pessoas, sobrenome, idades)
for dado in pessoas_com_idades:
    print(type(dado))
    print(dado[0], dado[1], dado[2])
    print()
<class 'tuple'>
Luciano A 28

<class 'tuple'>
Maria B 31

<class 'tuple'>
José C 40

In [23]:
from collections import namedtuple

Pessoa = namedtuple("Pessoa", ["nome", "idade"])

pessoas_com_idades = zip(pessoas, idades)
for dado in pessoas_com_idades:
    pessoa = Pessoa(*dado)
    print(pessoa.nome, pessoa.idade)
    print()
Luciano 28

Maria 31

José 40

Motivo nº4: API Coerente #ducktyping

  • Python Data Model
  • Qual o tamanho das coisas?
  • Objeto está contido?
In [24]:
lista = range(10)
print("Tamanho da lista: ", len(lista))

texto = 'Olar amigos'
print("Tamanho da texto: ", len(texto))

dicionario = {'chave': 'valor'}
print("Tamanho da dicionario: ", len(dicionario))

tupla = (0, 1, 2)
print("Tamanho da tupla: ", len(tupla))
Tamanho da lista:  10
Tamanho da texto:  11
Tamanho da dicionario:  1
Tamanho da tupla:  3
In [25]:
print(3 in lista)
print('python' in texto)
print('chave' in dicionario)
print(4 in tupla)
True
False
True
False

Proposta

Ter um objeto que represente uma turma e que tenha um nome e uma lista com nomes de alunos.

In [26]:
class Turma():

    def __init__(self, nome, alunos):
        self.nome = nome
        self.alunos = alunos
In [27]:
alunos = ['Luciano', 'Maria', 'José']
turma = Turma('A', alunos)
print(turma.nome)
print(turma.alunos)

print("Tamanho da turma:", len(turma))
print("Luciano presente?", "Luciano" in turma)
print("Fernanda presente?", "Fernanda" in turma)
A
['Luciano', 'Maria', 'José']
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-27-54ac5292eda2> in <module>()
      4 print(turma.alunos)
      5
----> 6 print("Tamanho da turma:", len(turma))
      7 print("Luciano presente?", "Luciano" in turma)
      8 print("Fernanda presente?", "Fernanda" in turma)

TypeError: object of type 'Turma' has no len()
In [28]:
from collections import Iterable

class Turma(Iterable):

    def __init__(self, nome, alunos):
        self.nome = nome
        self.alunos = alunos

    def __len__(self):
        return len(self.alunos)

    def __iter__(self):
        return iter(self.alunos)

alunos = ['Luciano', 'Maria', 'José']
turma = Turma('A', alunos)

print("Nome da turma:", turma.nome)
print("Tamanho da turma:", len(turma))
print("Luciano presente?", "Luciano" in turma)
print("Fernanda presente?", "Fernanda" in turma)
Nome da turma: A
Tamanho da turma: 3
Luciano presente? True
Fernanda presente? False

Motivo nº 5: Encapsulamento via properties

Respeitar estado de maneira transparente pro usuário

Exemplo: pessoa não pode ter idade negativa e a class que já existe é a seguinte:

class Pessoa():

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade
In [29]:
class Pessoa():

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

    @property
    def idade(self):
        return self.__idade

    @idade.setter
    def idade(self, idade):
        if idade <= 0:
            raise ValueError('Tem que ser maior ou igual a 0')
        self.__idade = idade

    def __repr__(self):
        return f'{self.nome} - {self.idade}'


luciano =  Pessoa('Luciano', 28)
print(luciano)
print(luciano.idade)

raul = Pessoa('Raul', -10000)
Luciano - 28
28
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-29-241b55d80423> in <module>()
     23 print(luciano.idade)
     24
---> 25 raul = Pessoa('Raul', -10000)

<ipython-input-29-241b55d80423> in __init__(self, nome, idade)
      3     def __init__(self, nome, idade):
      4         self.nome = nome
----> 5         self.idade = idade
      6
      7     @property

<ipython-input-29-241b55d80423> in idade(self, idade)
     12     def idade(self, idade):
     13         if idade <= 0:
---> 14             raise ValueError('Tem que ser maior ou igual a 0')
     15         self.__idade = idade
     16

ValueError: Tem que ser maior ou igual a 0

Motivo nº 6: Uso de blocos

Adicionar controle de contexto de execução de código.

Exemplo: monitorar o tempo de execução de uma função

In [30]:
import time
import random
from contextlib import contextmanager
from datetime import datetime

def funcao_com_preguica():
    segundos = random.choice(range(1, 3))
    time.sleep(segundos)
    return segundos

@contextmanager
def cronometro():
    start = datetime.now()
    yield
    end = datetime.now()
    print("Demorei: ", end - start)

with cronometro():
    segundos = funcao_com_preguica()
    print(f"Acordei! Dormi por {segundos} segundos")
Acordei! Dormi por 2 segundos
Demorei:  0:00:02.002333

Motivo nº 7: we, the people

pybr.jpg