Skip to content

Instantly share code, notes, and snippets.

@oleoprado
Last active April 26, 2023 16:29
Show Gist options
  • Select an option

  • Save oleoprado/0b7761957a4523da7db9877dadf243be to your computer and use it in GitHub Desktop.

Select an option

Save oleoprado/0b7761957a4523da7db9877dadf243be to your computer and use it in GitHub Desktop.
Introdução a Python

Info uteis

  • Padrão no python é de 4 espaços!

  • Anota aí ✏️: O método type(operando) corresponde ao operador typeof operando do JavaScript.

a = 5;
type(a) #<class 'int'>
  • Podemos digitar help() dentro da linha de comandos do Python que ele nos dará detalhes do comando passado por parâmetro.
help(list)
  • O comando help() também pode ser utilizado em cláusulas if ou for, desde que colocado entre aspas e para sair de dentro do comando, basta apertar a tecla q.
help("if")
  • 👀 Funções e variáveis devem ser nomeadas com letras minúsculas e, caso tenham mais de uma palavra, com underscore: minha_variavel.

  • Em Python, precisamos colocar a chave do objeto entre aspas:

info = {
"personagem": "Margarida",
"origem": "Pato Donald",
"nota": "Namorada do personagem principal nos quadrinhos do Pato Donald",
}
  • Template literals:

print(f'{index} - {language}'). A letra f usada dentro do print é chamada de f-string. Ela fornece uma maneira de incorporar expressões dentro de strings literais, usando uma sintaxe mínima

lista = [1, 2, 3]

 for index, num in enumerate(lista):
 print(f"{index} - {num}")
 # 0 - 1
 # 1 - 2
 # 2 - 3
  • Todo arquivo com extensão .py é considerado um módulo.

  • Observação:

 PI = 3.14  # PI é uma "constante" em nosso módulo


def square(side):
   '''Calculate area of square.'''
   return side * side


def rectangle(length, width):
   '''Calculate area of rectangle.'''
   return length * width


def circle(radius):
   '''Calculate area of circle.'''
   return PI * radius * radius
  • Entre cada função dar um espaço de 2 linhas;
  • As funções são declaradas com nomes em letras minúsculas;
  • A constante PI é definida em letras maiúsculas;
  • ''' Comentario em bloco ''' envolver algo dentro de 3 aspas.

⚠️Aviso: Existe uma convenção de declarar valores considerados constantes com letras maiúsculas, e o respeito por outros programadores de não alterarem aquele valor.

  • Anota aí ✏️: O import (import area) é utilizado para termos todas as funções do módulo disponíveis em outro arquivo. Uma outra maneira de utilizarmos é escrevendo from area import rectangle, por exemplo, se quisermos importar apenas rectangle a partir de area. Porém, tome cuidado com conflitos de nomes caso use essa segunda maneira.

  • Acrescentar uma condicional ao módulo para somente exibir esses valores de teste quando o módulo for executado como script.

A variável __name__ é utilizada pelo interpretador Python para identificar o arquivo que esta sendo executado e seu valor será "__main__" quando invocamos um módulo como script.

# ...

if __name__ == "__main__":
    print("Área do quadrado:", square(10))
    print("Área do retângulo:", rectangle(2, 2))
    print("Área do círculo:", circle(3))

Terminal Interativo REPL


As distribuições do sistema operacional Linux e Mac, normalmente, já vem com uma versão Python instalada, pois utilizam a linguagem em diversos programas essenciais.

Para verificar se está instalado, digitar python3 no terminal e a saída deve ser semelhante a esta:

Python 3.8.2 (default, Jun  2 2020, 13:51:17)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
  • Para acessar o terminal interativo REPL digitar python3

Anota aí ✏️: A fim de padronizar códigos escritos em Python, foi lançado um guia de estilo conhecido como PEP 8 ou Python Enhancement Proposal 8. A PEP 8 é um documento desenvolvido pela comunidade pythônica que visa aprimorar a legibilidade dos códigos.

Operações básicas

De olho na dica👀: O símbolo # marca um comentário e deste simbolo em diante (na linha) o código não será executado.

2 * 3  # saída: 6
2 + 3  # saída: 5
3 / 2  # saída: 1.5

Para atribuir esses valores a um nome, basta utilizar o operador de atribuição =

square_root = 25 ** (1/2)  # raiz quadrada de 25. O operador `**` significa "elevado a"

print(square_root + 1)  # saída: 6.0

⚠️ Aviso: Não é necessário a utilização de let, var ou const nas atribuições.

  • INCREMENTAR
# original
counter = counter + 1

# simplificado
counter += 1
  • Operador // realiza a divisão e arredonda o resultado para baixo.
3 // 2  # saída: 1

3 / 2  # saída: 1.5
  • Operadores lógicos and e or

Quando queremos fazer operações lógicas, como verificar se uma temperatura está entre dois valores, utilizamos o operador and. Ou seja, para verificar se uma temperatura é menor que 25 graus e maior que 18 graus, podemos fazer algo como temperatura < 25 and temperatura > 18. Embora uma maneira mais pythonica de se escrever esta operação seja 18 < temperatura < 25.

Operador or, Por exemplo, se em um parque pessoas com idade menor ou igual a 5 e maiores de 65 anos não pagam, poderíamos escrever uma validação da seguinte maneira idade <= 5 or idade >= 65.

Tipos de dados Embutidos

Booleanos (bool)

Os valores booleanos True e False pertencem ao tipo embutido bool.

De olho na dica👀: Aqui devemos ter atenção ao início maiúsculo dessas palavras reservadas.

Números inteiros (int)

O primeiro dos tipos numéricos é o int, ele representa um número inteiro, ou seja, é escrito sem parte fracionária.

a = 5;
type(a) #<class 'int'>

Números fracionários (float)

O segundo tipo numérico é o float, também conhecido por ponto flutuante, ele representa um número decimal ou fracionário.

a = 1.5;
type(a) #<class 'float'>

Strings (str)

Ele representa uma cadeia de caracteres ou, como popularmente conhecida, uma string. As strings são definidas envolvendo um valor com aspas simples ou duplas

Outras estruturas do tipo:

  • sequência(list, tuple, range);
  • conjuntos(set, frozenset);
  • mapeamento(dict);
  • sequências binárias(bytes, bytearray, memoryview).

Listas (list)

Uma lista é uma sequência mutável e ordenada de elementos. Ela pode armazenar elementos heterogêneos, ter seu tamanho variável e crescer à medida que itens são adicionados.

Armazena entidades diferentes dentro de uma relacão(entidades relacionadas). Ex: Os diferentes ingredientes de uma lista de supermercado(pão, manteiga, leite, etc)

fruits = ["laranja", "maçã", "uva", "abacaxi"]  # elementos são definidos separados por vírgula, envolvidos por colchetes

fruits[0]  # o acesso é feito por índices iniciados em 0

fruits[-1]  # o acesso também pode ser negativo

fruits.append("banana")  # adicionando uma nova fruta

fruits.remove("abacaxi")  # removendo uma fruta

fruits.extend(["pera", "melão", "kiwi"])  # acrescenta uma lista de frutas a lista original

fruits.index("maçã")  # retorna o índice onde a fruta está localizada, neste caso, 1

fruits.sort()  # ordena a lista de frutas

Tuplas (tuple)

São similares a listas, porém não podem ser modificados durante a execução do programa(imutável).

Quando quer informações de uma mesma entidade(unica entidade).

user = ("Will", "Marcondes", 42)  # elementos são definidos separados por vírgula, envolvidos por parênteses

user[0]  # acesso também por índices

Conjuntos (set)

Um conjunto é uma coleção de elementos únicos e não ordenados. Conjuntos implementam operações de união, intersecção e outras.

permissions = {"member", "group"}  # elementos separados por vírgula, envolvidos por chaves

permissions.add("root")  # adiciona um novo elemento ao conjunto

permissions.add("member")  # como o elemento já existe, nenhum novo item é adicionado ao conjunto

permissions.union({"user"})  # retorna um conjunto resultado da união

permissions.intersection({"user", "member"})  # retorna um conjunto resultante da intersecção dos conjuntos

permissions.difference({"user"})  # retorna a diferença entre os dois conjuntos

Um conjunto ou set pode ser inicializado utilizando-se também o método set():

var = set()
var.add('leonardo')
var #{'leonardo'}

Conjuntos imutáveis (frozenset)

É uma variação do set, porém imutável, ou seja, seus elementos não podem ser modificados durante a execução do programa.

permissions = frozenset(["member", "group"])  # assim como o set, qualquer estrutura iterável pode ser utilizada para criar um frozenset

permissions.union({"user"})  # novos conjuntos imutáveis podem ser criados à partir do original, mas o mesmo não pode ser modificado

permissions.intersection({"user", "member"})  # retorna um conjunto resultante da intersecção dos conjuntos

permissions.difference({"user"})  # retorna a diferença entre os dois conjuntos

Dicionários (dict)

Estrutura que associa uma chave a um determinado valor. É a representação do tão famoso objeto que utilizamos em JavaScript.

Pode representar uma entidade ou uma lista desde que queira fazer uma associação de chave e valor.(entidades diferentes ou mesma entidade)

A tupla pode ser usada como chave do dict.

people_by_id = {1: "Maria", 2: "Fernanda", 3: "Felipe"}  # elementos no formato "chave: valor" separados por vírgula, envolvidos por chaves

people_by_name = {"Maria": 1, "Fernanda": 2, "Felipe": 3}  # outro exemplo, dessa vez usando strings como chaves. As aspas são necessárias para que o Python não ache que `Maria`, `Fernanda` e `Felipe` sejam variáveis.

# elementos são acessados por suas chaves
people_by_id[1]  # saída: Maria

# elementos podem ser removidos com a palavra chave del
del people_by_id[1]
people_by_id.items()  # dict_items([(2, "Fernanda"), (3, "Felipe")])
# é retornada uma coleção iterável de tuplas contendo chaves e valores

# adicionando chave e valor
info["recorrente"] = "sim"

Range (range)

Estrutura capaz de gerar uma sequência numérica de um valor inicial até um valor final, modificando seu valor de acordo com o passo (step) definido. Pode ser declarado como range( [start], [stop], [step] ), em que start e step podem ser omitidos, possuindo valores iniciais iguais a 0 e 1 respectivamente.

O stop não é incluído na sequência, portanto, caso queira uma sequência de 1 até 10 a chamada deverá ser range(1, 11)

Seus valores são criados à medida que esta sequência é percorrida.

# vamos converter o range em uma lista para ajudar na visualização

# definimos somente o valor de parada
list(range(5))  # saída: [0, 1, 2, 3, 4]

# definimos o valor inicial e o de parada
list(range(1, 6))  # saída: [1, 2, 3, 4, 5]

# definimos valor inicial, de parada e modificamos o passo para 2
list(range(1, 11, 2))  # saída: [1, 3, 5, 7, 9]

# podemos utilizar valores negativos para as entradas também
list(range(10, 0, -1))  # saída: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Além dos tipos básicos, temos outros como datas, tuplas nomeadas, arrays, enumerações e outros, mas estes têm de ser importados de seus respectivos módulos.

Estruturas condicionais

Para fazer um agrupamento por essa classificação de nível de experiência, precisamos criar uma nova coluna que será baseada no salário:
position = ""
if salary <= 2000:
    position = "estagiário"
elif 2000 < salary <= 5800:
    position = "júnior"
elif 5800 < salary <= 7500:
    position = "pleno"
elif 7500 < salary <= 10500:
    position = "senior"
else:
    position = "líder"

A indentação do código deve ser feita com 4 espaços em vez de tabs.

Note que if e elif são seguidos de uma expressão que se avaliada como verdadeira, o trecho de código será executado. Um outro detalhe é a ausência de chaves para definir o bloco. Utilizamos o caractere : para indicar abertura de um bloco e somente indentação para indicar o término.

Estrutura de repetição

For

Imagine um sistema que faça a listagem de restaurantes. Estes restaurantes possuem uma nota proveniente da avaliação dos seus clientes.

restaurants = [
  {"name": "Restaurante A", "nota": 4.5},
  {"name": "Restaurante B", "nota": 3.0},
  {"name": "Restaurante C", "nota": 4.2},
  {"name": "Restaurante D", "nota": 2.3},
]

Filtrar o resultado de acordo com a nota:

filtered_restaurants = []
min_rating = 3.0
for restaurant in restaurants:
    if restaurant["nota"] > min_rating:
        filtered_restaurants.append(restaurant)
print(filtered_restaurants)  # imprime a lista de restaurantes, sem o B e D

Os criadores do Python decidiram que o for each seria o laço de repetição principal na linguagem.

Em alguns casos, podemos ainda querer percorrer uma sequência numérica, e para isto iteramos sobre a estrutura de dados range.

for index in range(5):
  print(index)

Além de listas, várias outras estruturas são iteráveis, como strings (str), tuplas (tuple), conjuntos (set), dicionários (dict) e até mesmo arquivos.

Compreensão de lista (list comprehension)

A compreensão de listas em Python possui uma sintaxe fácil e compacta para criação de listas, seja a partir de uma string ou de outra lista. É uma maneira concisa de criação que executa uma operação em cada item da lista já existente.

Quando uma nova lista é criada como resultado de uma iteração, podemos simplificar utilizando compreensão de listas.

min_rating = 3.0
filtered_restaurants = [
    restaurant
    for restaurant in restaurants
    if restaurant["nota"] > min_rating
]
print(filtered_restaurants)  # imprime a lista de restaurantes, sem o B e D

De olho na dica👀: É possível filtrar esses elementos utilizando o if.

A compreensão de listas também funciona com listas de strings. A seguinte cria uma nova lista de strings com os nomes que contém a letra ‘a’.

names_list = ['Duda', 'Rafa', 'Cris', 'Yuri']
new_names_list = [name for name in names_list if 'a' in name]

# Aqui o for percorre cada nome em "names_list", verifica se existe a letra "a" nele,
# o adiciona à variável "name", e então gera nossa nova lista "new_names_list"
print(new_names_list)

# Saída
['Duda', 'Rafa']

Criar uma lista com o quadrado dos números entre 1 e 10:

quadrados = [x*x for x in range(11)]
print(quadrados)

# Saída
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Isto é equivalente às operações de map e filter em JavaScript.

ratings = [6, 8, 5, 9, 10]
new_ratings = [10 * rating for rating in ratings]
new_ratings # [60, 80, 50, 90, 100]

While

Com o while nós podemos executar um conjunto de declarações enquanto a condição for verdadeira.

No código abaixo mostramos uma implementação da Sequência de Fibonacci, presente em diversas formas na natureza. Ela é uma sequência numérica começando por 0 e 1, e cada termo subsequente corresponde à soma dos dois anteriores.

n = 10
last, next = 0, 1
while last < n:
  print(last)
  last, next = next, last + next

Enumerate

Em Python, um loop for geralmente é escrito como um loop sobre um objeto iterável. Isso significa que você não precisa de uma variável de contagem para acessar itens no iterável. Porém, às vezes, pode acontecer de você querer uma variável que muda em cada iteração do loop. Em vez de criar e incrementar uma variável você mesmo, você pode usar enumerate() do Python para obter um contador e o valor do iterável ao mesmo tempo!

languages = ['Python', 'Java', 'JavaScript']

enumerate_prime = enumerate(languages)

# converte um objeto enumerate em uma lista
print(list(enumerate_prime))

# Saída: [(0, 'Python'), (1, 'Java'), (2, 'JavaScript')]

Você também pode desestruturar (unpack) os itens da lista ou tupla:

languages = ['Python', 'Java', 'JavaScript']

for index, language in enumerate(['Python', 'Java']):
  print(f'{index} - {language}')
# Saída:
0 - Python
1 - Java

print(f'{index} - {language}'). A letra f usada dentro do print é chamada de f-string. Ela fornece uma maneira de incorporar expressões dentro de strings literais, usando uma sintaxe mínima

Funções

Funções são definidas através da palavra reservada `def`, seguida por um nome e os parâmetros entre parênteses. Como todo bloco de código em Python, o caractere `:` define o início do bloco, e a indentação define seu fim.

Os parâmetros podem ser passados de forma:

  • posicional:são aqueles definidos por meio da posição em que cada um é passado;
  • nomeada: são definidos por meio de seus nomes
def soma(x, y):
return x + y

soma(2, 2)  # os parâmetros aqui são posicionais

soma(x=2, y=2)  # aqui estamos nomeando os parâmetros

Anota aí ✏️: Parâmetros posicionais variádicos são acessados como uma tupla no interior de uma função, e parâmetros nomeados variádicos como um dicionário.

def concat(*strings):
  # Equivalente a um ", ".join(strings), que concatena os elementos de um iterável em uma string utilizando um separador
  # Nesse caso a string resultante estaria separada por vírgula
  final_string = ""
  for string in strings:
      final_string += string
      if not string == strings[-1]:
          final_string += ', '
  return final_string

# pode ser chamado com 2 parâmetros
concat("Carlos", "Cristina")  # saída: "Carlos, Cristina"

# pode ser chamado com um número n de parâmetros
concat("Carlos", "Cristina", "Maria")  # saída: "Carlos, Cristina, Maria"

# dict é uma função que já vem embutida no python
dict(nome="Felipe", sobrenome="Silva", idade=25)  # cria um dicionário utilizando as chaves passadas

dict(nome="Ana", sobrenome="Souza", idade=21, turma=1)  # o número de parâmetros passados para a função pode variar

As variáveis definidas dentro das funções tem escopo local. Porém, quando uma função não encontra um nome no escopo local, ela irá procurar no espaço de nomes global.

Em alguns casos, podemos querer limitar um parâmetro em nomeado ou posicional para evitar ambiguidades e/ou aumentar legibilidade.

len([1, 2, 3, 4])  # função len não aceita argumentos nomeados

len(obj=[1, 2, 3, 4])  # este código irá falhar

print("Coin", "Rodrigo", ", ")  # imprime Coin Rodrigo ,

print("Coin", "Rodrigo", sep=", ")  # nomeando o terceiro parâmetro, agora temos a saída: Coin, Rodrigo

PEP 257 - Convenções Docstring

O objetivo deste PEP é padronizar a estrutura de alto nível das docstrings: o que elas devem conter e como dizê-lo (sem tocar em nenhuma sintaxe de marcação dentro das docstrings). O PEP contém convenções, não leis ou sintaxe.

O que é uma Docstring?

As docstrings do Python são os literais de string que aparecem logo após a definição de uma função, método, classe ou módulo.

 def quadrado(n):
 '''Recebe um número n, retorna o quadrado de n''' # Literal de string
 return n**2

Atributo __doc__ do Python

As docstrings do Python são strings usadas logo após a definição de uma função, método, classe ou módulo (como no exemplo anterior). Eles são usados para documentar nosso código.

Podemos acessar essas docstrings usando o atributo __doc__:

def quadrado(n):
  '''Recebe um número n, retorna o quadrado de n''' # Literal de string
  return n**2
print(quadrado.__doc__)
# Saída
Recebe um número n, retorna o quadrado de n

Docstrings para a função print() integrada

print(print.__doc__)

# Saída
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Imprime os valores em um fluxo, or em sys.stdout por padrão.
Argumentos de palavras-chave opcionais:
file: um objeto semelhante a um arquivo (fluxo); o padrão é o sys.stdout atual.
sep: string inserida entre valores, o padrão é o espaço.
end: string anexada após o último valor, o padrão é uma nova linha.
flush: se deve forçar a descarga do fluxo.  

Testes

  • Testes Automatizados com a lib pytests:
  python3 -m pip install pytest

Verificar a versão:

  python3 -m pytest --version

📝 Exemplo:

codigo.py

def is_odd(number):
'Retorna True se um número é ímpar, senão False.'
return number % 2 != 0

test_codigo.py

from codigo import is_odd


def test_is_odd_when_number_is_odd_returns_true():
    'Para um número ímpar a função deve retornar o valor True'
    assert is_odd(3) is True


def test_is_odd_when_number_is_even_returns_false():
    'Para um número par a função deve retornar o valor False'
    assert is_odd(2) is False
  • nome do arquivo de testes possui o prefixo test_
  • O comando assert funciona da seguinte maneira: caso a expressão recebida seja verdadeira (avaliada como True), nada acontece. Porém, caso seja falsa (avaliada como False), uma exceção do tipo AssertionError é lançada. A pytest captura este erro e tenta apresentar uma comparação entre o esperado e o recebido da melhor maneira possível.

Para rodar o teste:

python3 -m pytest

Testando Falhas

codigo.py

# ...

def divide(a_number, other_number):
  "Retorna a divisão de a_number por other_number"
  return a_number / other_number
*test_codigo.py*
import pytest
from codigo import is_odd, divide

# ...

def test_divide_when_other_number_is_zero_raises_an_exception():
    with pytest.raises(ZeroDivisionError, match="division by zero"):
        divide(2, 0)

Utilizamos a função raises da pytest para verificar se a exceção ocorreu. Caso contrário, ela lança um AssertionError, indicando que o teste não passou. Podemos verificar também se o texto retornado na exceção é o esperado através do parâmetro match, que pode receber uma expressão regular. No exemplo, temos uma divisão por zero, que lança a exceção esperada e o teste passa com sucesso.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment