← Base: Python e matemática

Aula 1 de 6
  1. 1Python para quem vem de C# e TypeScript
  2. 2NumPy: pensar em arrays, não em laços
  3. 3Gráficos com matplotlib
  4. 4Álgebra linear: vetores, produto escalar e matrizes
  5. 5Cálculo: derivada, derivada parcial e gradiente
  6. 6Probabilidade e estatística: média, variância e distribuição normal

Python para quem vem de C# e TypeScript

Objetivo: ficar à vontade com a sintaxe do Python usando o que você já sabe de C# e TS. Nada de “o que é uma variável”: o foco é o que muda.

1. Primeiro contato

O que muda logo de cara:

C# / TS Python
; no fim da linha nada
{ } delimitam blocos indentação (4 espaços) delimita blocos
var, let, const, tipo só o nome: x = 1
// comentário # comentário
Main() obrigatório o arquivo roda de cima pra baixo
print("Olá, Python!")

nome = "Ronaldo"    # sem var/let e sem tipo
ano = 2026
print(nome, ano)    # print aceita vários valores, separados por espaço
Olá, Python!
Ronaldo 2026

2. Tipagem dinâmica, mas forte

Como no JS, a variável não tem tipo fixo: o valor é que tem. Mas, ao contrário do JS, o Python não converte tipos sozinho.

x = 42
print(type(x))

x = "agora sou texto"   # a mesma variável pode apontar pra outro tipo
print(type(x))
<class 'int'>
<class 'str'>
# Em JS, "1" + 1 dá "11". Em Python dá erro:
try:
    "1" + 1
except TypeError as erro:           # try/except = try/catch
    print("Erro:", erro)

print("1" + str(1))   # conversão explícita pra texto -> "11"
print(int("1") + 1)   # conversão explícita pra número -> 2
Erro: can only concatenate str (not "int") to str
11
2

Dicas de tipo (type hints) parecem as anotações do TypeScript, mas o Python não verifica na execução. Quem verifica é o editor (o Pylance, no VS Code). Servem como documentação.

def dobro(n: int) -> int:
    return n * 2

print(dobro(21))
print(dobro("ha"))   # roda mesmo assim! "ha" * 2 == "haha"
42
haha

3. Números e operadores

Atenção principalmente à divisão: em C#, 7 / 2 entre inteiros dá 3. Em Python dá 3.5.

print(7 / 2)     # 3.5  -> divisão "normal" sempre dá decimal (float)
print(7 // 2)    # 3    -> divisão inteira
print(7 % 2)     # 1    -> resto
print(2 ** 10)   # 1024 -> potência (em C#: Math.Pow)
print(2 ** 100)  # inteiros não estouram: o tamanho é ilimitado
print(0.1 + 0.2) # igual a C# e JS: float não é exato
3.5
3
1
1024
1267650600228229401496703205376
0.30000000000000004

Não existe ++ nem --. Use x += 1.

4. Condicionais

  • &&, ||, ! viram and, or, not
  • else if vira elif
  • null vira None; true/false viram True/False (com maiúscula)
temperatura = 28

if temperatura > 30:
    print("quente")
elif temperatura > 20 and temperatura <= 30:
    print("agradável")
else:
    print("frio")

# comparação encadeada, igual na matemática:
if 20 < temperatura <= 30:
    print("agradável (versão pythônica)")
agradável
agradável (versão pythônica)

Valores “falsos”: 0, "", [], {} e None contam como falso num if, como no JS. Então if not lista: significa “se a lista está vazia”.

tarefas = []
if not tarefas:
    print("nenhuma tarefa")

resultado = None
print(resultado is None)   # para comparar com None, use "is"

idade = 17
status = "maior" if idade >= 18 else "menor"   # ternário: idade >= 18 ? "maior" : "menor"
print(status)
nenhuma tarefa
True
menor

5. Strings

As f-strings equivalem a $"..." no C# e a `${...}` no TS.

nome = "Ronaldo"
qtd = 2
print(f"{nome} já domina {qtd} linguagens")

pi = 3.14159265
print(f"pi com 2 casas: {pi:.2f}")   # formatação depois do ":" (C#: {pi:F2})

frase = "aprendendo machine learning"
print(frase.upper())
print(frase.split())          # quebra em lista de palavras
print(len(frase))             # tamanho: len(x), não x.Length / x.length
print("learning" in frase)    # "contém?" -> operador in
Ronaldo já domina 2 linguagens
pi com 2 casas: 3.14
APRENDENDO MACHINE LEARNING
['aprendendo', 'machine', 'learning']
27
True

6. Listas

Equivalem ao List<T> do C# e ao array do TS, e podem misturar tipos.

notas = [7.5, 8.0, 6.5, 9.0]

notas.append(10.0)       # C#: Add / TS: push
print(notas)
print(len(notas))
print(notas[0])          # primeiro elemento
print(notas[-1])         # último! índice negativo conta a partir do fim
print(sum(notas), min(notas), max(notas))
[7.5, 8.0, 6.5, 9.0, 10.0]
5
7.5
10.0
41.0 6.5 10.0

Fatiamento (slicing)

lista[inicio:fim] devolve um pedaço da lista, e o fim não entra. Você vai usar isso o tempo todo em ML: imagem[0:100, 0:200] recorta um pedaço de uma imagem, por exemplo.

numeros = [0, 10, 20, 30, 40, 50]

print(numeros[1:4])   # [10, 20, 30]  (índices 1, 2 e 3)
print(numeros[:3])    # os 3 primeiros
print(numeros[3:])    # do índice 3 até o fim
print(numeros[-2:])   # os 2 últimos
print(numeros[::2])   # de 2 em 2
print(numeros[::-1])  # invertida
[10, 20, 30]
[0, 10, 20]
[30, 40, 50]
[40, 50]
[0, 20, 40]
[50, 40, 30, 20, 10, 0]

7. Tuplas e desempacotamento

Uma tupla é uma lista imutável: (3, 4). Desempacotar é o var (x, y) = ... do C# ou o const [x, y] = ... do TS.

Um exemplo comum em visão computacional: a linha ok, quadro = camera.read() faz exatamente isso, porque a função devolve uma tupla com dois valores.

ponto = (3, 4)
x, y = ponto
print(x, y)

a, b = 1, 2
a, b = b, a     # troca os valores sem variável auxiliar
print(a, b)
3 4
2 1

8. Dicionários

É o Dictionary<K, V> do C#, ou um objeto/Map do TS.

pessoa = {"nome": "Ronaldo", "linguagens": ["C#", "TypeScript"]}

print(pessoa["nome"])
pessoa["linguagens"].append("Python")
pessoa["estudando"] = "ML"        # adiciona uma chave nova
print(pessoa)

print(pessoa.get("idade"))                     # chave que não existe: get devolve None ([] daria KeyError)
print(pessoa.get("idade", "não informada"))    # ... ou um valor padrão

for chave, valor in pessoa.items():            # percorre pares chave/valor
    print(chave, "->", valor)
Ronaldo
{'nome': 'Ronaldo', 'linguagens': ['C#', 'TypeScript', 'Python'], 'estudando': 'ML'}
None
não informada
nome -> Ronaldo
linguagens -> ['C#', 'TypeScript', 'Python']
estudando -> ML

9. Laços

O for do Python é sempre um foreach. Para o resto, existem três ajudantes:

  • range(n): gera 0, 1, …, n-1 (o for (int i = 0; i < n; i++))
  • enumerate(lista): devolve o índice e o valor
  • zip(a, b): percorre duas listas lado a lado
frutas = ["maçã", "banana", "uva"]
precos = [3.0, 5.5, 12.0]

for fruta in frutas:
    print(fruta)

for i in range(3):
    print(i)

for i, fruta in enumerate(frutas):
    print(i, fruta)

for fruta, preco in zip(frutas, precos):
    print(f"{fruta}: R$ {preco:.2f}")
maçã
banana
uva
0
1
2
0 maçã
1 banana
2 uva
maçã: R$ 3.00
banana: R$ 5.50
uva: R$ 12.00

while também existe e funciona como você espera. range aceita início, fim e passo: range(10, 0, -2) gera 10, 8, 6, 4, 2.

10. List comprehensions (o “LINQ” do Python)

Cria uma lista nova a partir de outra, numa linha só:

[expressão for item in lista if condição]

LINQ (C#) TS Python
nums.Select(n => n * n) nums.map(n => n * n) [n * n for n in nums]
nums.Where(n => n > 2) nums.filter(n => n > 2) [n for n in nums if n > 2]
numeros = [1, 2, 3, 4, 5, 6]

quadrados = [n ** 2 for n in numeros]
pares = [n for n in numeros if n % 2 == 0]
quadrados_dos_pares = [n ** 2 for n in numeros if n % 2 == 0]

print(quadrados)
print(pares)
print(quadrados_dos_pares)

# também funciona para dicionários:
tamanhos = {palavra: len(palavra) for palavra in ["ml", "python", "gpu"]}
print(tamanhos)
[1, 4, 9, 16, 25, 36]
[2, 4, 6]
[4, 16, 36]
{'ml': 2, 'python': 6, 'gpu': 3}

11. Funções

  • def nome(parametros): e o corpo indentado
  • parâmetros com valor padrão e argumentos nomeados, como no C#. Uma chamada como modelo(quadro, device=0, verbose=False) usa argumentos nomeados.
  • dá pra “retornar vários valores”: na verdade é uma tupla
  • lambda é a arrow function de uma linha só
def saudacao(nome, pontuacao="!"):
    return f"Olá, {nome}{pontuacao}"

print(saudacao("Ronaldo"))
print(saudacao("Ronaldo", pontuacao="?!"))


def min_max(valores):
    return min(valores), max(valores)

menor, maior = min_max([4, 1, 9])
print(menor, maior)


dobro = lambda n: n * 2          # TS: const dobro = (n) => n * 2
print(dobro(5))

# lambda aparece muito como "critério", por exemplo pra ordenar:
print(sorted(["banana", "kiwi", "maçã"], key=lambda p: len(p)))
Olá, Ronaldo!
Olá, Ronaldo?!
1 9
10
['kiwi', 'maçã', 'banana']

12. Classes

Você vai ver classes no PyTorch (class MinhaRede(nn.Module): ...). O que muda em relação ao C#:

  • o construtor é __init__
  • o this se chama self e é o primeiro parâmetro explícito de todo método
  • os atributos nascem dentro do construtor (self.valor = ...), sem declarar antes
  • não existe new, nem public/private (por convenção, _nome significa “uso interno”)
  • herança: class Filha(Mae):, e super() faz o papel do base
class Contador:
    def __init__(self, inicio=0):
        self.valor = inicio

    def incrementar(self, passo=1):
        self.valor += passo
        return self.valor


class ContadorDeDois(Contador):          # C#: class ContadorDeDois : Contador
    def incrementar(self):
        return super().incrementar(2)    # C#: base.Incrementar(2)


c = Contador()
c.incrementar()
c.incrementar(5)
print(c.valor)

d = ContadorDeDois(10)
d.incrementar()
print(d.valor)
6
12

13. Módulos e bibliotecas

import equivale ao using do C# e ao import do TS. Para instalar uma biblioteca nova no projeto, o comando no terminal é uv add nome (como npm install ou dotnet add package).

import math                    # importa o módulo inteiro
from statistics import mean    # importa só um nome de dentro do módulo
import numpy as np             # com apelido: todo mundo usa "np"

print(math.sqrt(16))
print(mean([1, 2, 3]))

# spoiler da próxima aula: o NumPy faz contas na lista inteira, sem laço
print(np.array([1, 2, 3]) * 2)
4.0
2
[2 4 6]

14. Armadilhas comuns para quem vem de C#/TS

Armadilha O que acontece
Misturar tab e espaço, ou errar a indentação IndentationError. Use sempre 4 espaços.
7 / 2 dá 3.5. Para divisão inteira, use //
x++ não existe. Use x += 1
true, null o certo é True, None
b = a com listas não copia: as duas variáveis apontam pra mesma lista (igual no C#/JS). Para copiar, use b = a.copy()
x == None funciona, mas o certo é x is None
a = [1, 2, 3]
b = a            # mesma lista!
b.append(4)
print(a)         # [1, 2, 3, 4] -- "a" mudou junto

c = a.copy()     # cópia de verdade
c.append(5)
print(a, c)
[1, 2, 3, 4]
[1, 2, 3, 4] [1, 2, 3, 4, 5]

Exercícios

Complete cada função no lugar do ... e rode a célula. A função confere avisa se está certo.

Os exercícios não foram escolhidos por acaso: todos são peças que você vai reusar em ML.

Código de apoio dos exercícios
import math

def _parecidos(a, b):
    # números: compara com tolerância, porque float não é exato
    if isinstance(a, (int, float)) and isinstance(b, (int, float)):
        return math.isclose(a, b, rel_tol=1e-9, abs_tol=1e-9)
    # listas/tuplas: compara item a item
    if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)):
        return len(a) == len(b) and all(_parecidos(x, y) for x, y in zip(a, b))
    return a == b

def confere(obtido, esperado):
    if obtido is None:
        print("⏳ ainda não implementado")
    elif _parecidos(obtido, esperado):
        print("✅ certo!")
    else:
        print(f"❌ esperado {esperado!r}, mas veio {obtido!r}")

Exercício 1 · Média

Escreva media(valores), que devolve a média de uma lista de números. Não vale usar statistics.mean!

def media(valores):
    ...  # seu código aqui


confere(media([7, 8, 9]), 8)
confere(media([1, 2]), 1.5)
Dica

sum() e len() resolvem.

Gabarito
def media(valores):
    return sum(valores) / len(valores)

Exercício 2 · Erro quadrático médio

Um modelo tentou prever valores. Para medir o quanto ele errou:

  1. para cada par, calcule erro = real - previsto
  2. eleve cada erro ao quadrado (assim erro negativo não cancela erro positivo)
  3. tire a média desses quadrados

Esse é o erro quadrático médio (MSE), a função de custo que você vai minimizar na disciplina de Fundamentos de ML.

def erro_quadratico_medio(reais, previstos):
    ...  # seu código aqui


# erros: 1, 0, -2  ->  quadrados: 1, 0, 4  ->  média: 5/3
confere(erro_quadratico_medio([3, 5, 7], [2, 5, 9]), 5 / 3)
confere(erro_quadratico_medio([1, 2, 3], [1, 2, 3]), 0)
Dica

zip(reais, previstos) percorre as duas listas juntas. Com uma list comprehension, você monta a lista dos quadrados e depois reaproveita a sua media.

Gabarito
def erro_quadratico_medio(reais, previstos):
    quadrados = [(r - p) ** 2 for r, p in zip(reais, previstos)]
    return media(quadrados)

Exercício 3 · Normalização min-max

Transforme uma lista de números para que o menor vire 0, o maior vire 1 e o resto fique proporcional entre os dois:

xnovo=x−min⁡max⁡−min⁡x_{novo} = \frac{x - \min}{\max - \min}

Em ML isso é essencial. Imagine uma coluna “idade” (0 a 100) e outra “salário” (0 a 50.000): sem normalizar, o salário “grita” mais alto só porque os números são maiores.

def normalizar(valores):
    ...  # seu código aqui


confere(normalizar([10, 20, 30]), [0.0, 0.5, 1.0])
confere(normalizar([5, 0, 10, 2.5]), [0.5, 0.0, 1.0, 0.25])
Dica

Calcule min e max uma vez só, antes da list comprehension, em vez de recalcular para cada item.

Gabarito
def normalizar(valores):
    menor, maior = min(valores), max(valores)
    return [(v - menor) / (maior - menor) for v in valores]

Exercício 4 · Contar palavras

Escreva contar_palavras(texto), que devolve um dicionário {palavra: quantidade}. É o primeiro passo de muita coisa em processamento de texto.

def contar_palavras(texto):
    ...  # seu código aqui


confere(contar_palavras("o gato viu o rato"), {"o": 2, "gato": 1, "viu": 1, "rato": 1})
Dica

texto.split() quebra em palavras. Use contagem.get(palavra, 0) + 1 para somar mesmo quando a palavra ainda não existe no dicionário.

Gabarito
def contar_palavras(texto):
    contagem = {}
    for palavra in texto.split():
        contagem[palavra] = contagem.get(palavra, 0) + 1
    return contagem

Existe um atalho pronto na biblioteca padrão: from collections import Counter e depois Counter(texto.split()).

Exercício 5 (desafio) · Vizinho mais próximo

Dado um ponto (x, y) e uma lista de pontos, devolva o ponto da lista mais perto dele. A distância entre dois pontos é:

d=(x1−x2)2+(y1−y2)2d = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}

Parabéns: isso é praticamente o algoritmo k-NN (com k = 1), que vai aparecer na disciplina de Fundamentos de ML.

def mais_proximo(ponto, pontos):
    ...  # seu código aqui


confere(mais_proximo((0, 0), [(5, 5), (1, 2), (-3, 0)]), (1, 2))
confere(mais_proximo((10, 10), [(0, 0), (9, 12), (20, 20)]), (9, 12))
Dica

Crie uma função distancia(a, b) e use min(pontos, key=...) com um lambda, como no sorted da seção 11.

Gabarito
def distancia(a, b):
    return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)

def mais_proximo(ponto, pontos):
    return min(pontos, key=lambda p: distancia(ponto, p))

A biblioteca padrão também tem essa distância pronta: math.dist(a, b).


Cola rápida

C# TypeScript Python
variável var x = 1; let x = 1; x = 1
nulo null null / undefined None
texto formatado $"oi {x}" `oi ${x}` f"oi {x}"
lista new List<int>{1,2} [1, 2] [1, 2]
tamanho lista.Count arr.length len(lista)
dicionário new Dictionary<..>() {} / new Map() {}
foreach foreach (var x in xs) for (const x of xs) for x in xs:
for com índice for (int i=0; i<n; i++) for (let i=0; i<n; i++) for i in range(n):
map / Select xs.Select(x => x*2) xs.map(x => x*2) [x*2 for x in xs]
filter / Where xs.Where(x => x>0) xs.filter(x => x>0) [x for x in xs if x>0]
lambda x => x * 2 x => x * 2 lambda x: x * 2
e / ou / não && || ! && || ! and or not
ternário c ? a : b c ? a : b a if c else b
this this this self (explícito)
construtor public Classe() constructor() def __init__(self):