P1. Python básico¶
Nesta aula você vai aprender
- Guardar números e textos em variáveis e saber o tipo de cada um.
- Organizar dados em listas (períodos) e dicionários (parâmetros de uma estrela).
- Repetir contas com laços
fore decidir comif. - Escrever funções que calculam profundidade de trânsito e raio do planeta.
- Separar seu código em módulos e importá-los.
Antes de começar, prepare o computador como explicado na página da trilha. Crie cada exemplo como um arquivo .py na pasta estudos-exoplanetas e rode com uv run python nome_do_arquivo.py.
Variáveis e tipos¶
Uma variável é um nome que aponta para um valor. Pense numa etiqueta colada numa caixa: a etiqueta é o nome, o conteúdo é o valor.
periodo_dias = 3.7 # número com casas decimais (float)
n_transitos = 7 # número inteiro (int)
nome_estrela = "Pi Mensae" # texto (str, de "string")
tem_transito = True # verdadeiro ou falso (bool)
print(periodo_dias, n_transitos, nome_estrela, tem_transito)
print(type(periodo_dias)) # <class 'float'>
O sinal = não é "igual" da matemática. Ele quer dizer "guarde o valor da direita no nome da esquerda". Tudo depois de # é comentário: o Python ignora, serve para você.
Regras práticas para nomes: só letras sem acento, números e _; não comece com número; use nomes que digam a unidade. raio_rsun é melhor que r. O PlanetHunter segue essa regra: period_days, depth_ppm, duration_hours.
Contas¶
raio_sol_km = 696_000 # o _ só separa os milhares para facilitar a leitura
raio_terra_km = 6_371
razao = raio_terra_km / raio_sol_km # divisão
profundidade = razao ** 2 # ** é potência
print(profundidade) # 8.379...e-05
O resultado 8.379e-05 é notação científica: \(8{,}379 \times 10^{-5}\). É a fração da luz do Sol que a Terra bloqueia. Isso vem da regra da aula B2:
onde \(\delta\) é a profundidade, \(R_p\) o raio do planeta e \(R_\star\) o raio da estrela.
Converter para ppm e por cento¶
ppm quer dizer partes por milhão. Para passar de fração para ppm, multiplique por um milhão. Para por cento, por cem.
profundidade_ppm = profundidade * 1e6 # 1e6 = 1 000 000
profundidade_pct = profundidade * 100
print(f"Terra: {profundidade_ppm:.0f} ppm = {profundidade_pct:.4f} %")
# Terra: 84 ppm = 0.0084 %
O f antes das aspas cria uma f-string: o que está entre chaves é calculado e inserido no texto. O :.0f diz "mostre com zero casas decimais".
Armadilha: vírgula decimal
Em Python, 3,7 não é o número três vírgula sete. É um par de números, 3 e 7. Sempre use ponto: 3.7.
Listas¶
Uma lista guarda vários valores em ordem, entre colchetes.
periodos_dias = [0.94, 3.7, 6.27, 11.4]
print(len(periodos_dias)) # 4 elementos
print(periodos_dias[0]) # 0.94 (a contagem começa em ZERO)
print(periodos_dias[-1]) # 11.4 (índice -1 é o último)
print(periodos_dias[1:3]) # [3.7, 6.27] (fatia: do 1 até antes do 3)
periodos_dias.append(25.0) # acrescenta no fim
print(min(periodos_dias), max(periodos_dias), sum(periodos_dias))
print(sorted(periodos_dias, reverse=True))
Começar a contar do zero parece estranho no início. Pense no índice como "quantos passos andar a partir do começo".
Dicionários¶
Um dicionário guarda pares chave e valor, entre chaves. É ótimo para descrever uma coisa com vários atributos, como uma estrela.
estrela = {
"nome": "WASP-18",
"tic_id": 100100827,
"raio_rsun": 1.35, # raio em raios solares
"tmag": 8.83, # brilho na banda do TESS (menor = mais brilhante)
}
print(estrela["raio_rsun"]) # 1.35
estrela["teff_k"] = 6226 # acrescenta uma chave nova
for chave, valor in estrela.items():
print(chave, "=", valor)
Os valores de WASP-18 vêm do arquivo que o PlanetHunter gravou para o setor 69. Você vai abrir esse arquivo na aula P3.
Decisões com if¶
rp_rearth = 15.1 # raio do planeta em raios terrestres
if rp_rearth < 4:
classe = "rochoso a mini-Netuno"
elif rp_rearth < 8:
classe = "tamanho de Netuno"
elif rp_rearth <= 20:
classe = "gigante"
else:
classe = "grande demais: provavelmente não é planeta"
print(classe)
Repare na indentação: os 4 espaços no começo das linhas dizem ao Python o que está "dentro" de cada if. Em Python, indentação não é enfeite, é regra. As faixas de tamanho seguem a tabela de leitura de candidatos do guia do projeto.
Laços for¶
Um laço repete um bloco para cada elemento de uma lista.
raio_sol_km = 696_000
planetas_km = {"Terra": 6_371, "Netuno": 24_622, "Júpiter": 69_911}
for nome, raio_km in planetas_km.items():
prof_ppm = (raio_km / raio_sol_km) ** 2 * 1e6
print(f"{nome:8s} {prof_ppm:8.0f} ppm")
Saída:
Compare com a tabela da aula B2 (84, ~1 300 e ~10 000 ppm). O guia arredonda Netuno para 1 300.
Para repetir um número fixo de vezes, use range:
periodo = 0.9416 # dias
t0 = 3182.758 # instante do primeiro trânsito, em BTJD
for n in range(5): # n = 0, 1, 2, 3, 4
print(f"trânsito {n}: BTJD {t0 + n * periodo:.3f}")
BTJD é a contagem de dias que o TESS usa (dias desde uma data de referência). Esse cálculo é uma efeméride: a previsão de quando os próximos trânsitos acontecem.
Funções¶
Uma função é uma receita com nome. Você define uma vez e usa quantas vezes quiser. Ela recebe parâmetros (entradas) e devolve um resultado com return.
RSUN_EM_REARTH = 109.1 # um raio solar vale 109,1 raios terrestres
def profundidade_ppm(rp_rearth: float, rs_rsun: float) -> float:
"""Profundidade de trânsito em ppm. Rp em R_terra, R* em R_sol."""
razao = rp_rearth / (rs_rsun * RSUN_EM_REARTH)
return razao**2 * 1e6
def raio_planeta(prof_ppm: float, rs_rsun: float) -> float:
"""Raio do planeta em R_terra a partir da profundidade (ppm) e de R* (R_sol)."""
return (prof_ppm / 1e6) ** 0.5 * rs_rsun * RSUN_EM_REARTH
print(profundidade_ppm(1.0, 1.0)) # Terra no Sol: ~84 ppm
print(raio_planeta(84, 1.0)) # volta para ~1 R_terra
print(raio_planeta(84, 0.2)) # mesma queda numa anã vermelha: ~0,2 R_terra
Detalhes:
rp_rearth: floaté uma anotação de tipo. Avisa quem lê que se espera um número. O Python não obriga, mas o PlanetHunter usa em todas as funções.- O texto entre
"""logo abaixo dodefé a docstring: explica o que a função faz e as unidades. raio_planetaé a conta inversa deprofundidade_ppm: raiz quadrada da profundidade (** 0.5) vezes o raio da estrela.
A última linha mostra uma ideia importante do básico: a mesma queda de 84 ppm numa estrela cinco vezes menor corresponde a um planeta cinco vezes menor. Por isso é mais fácil achar planetas pequenos em estrelas pequenas.
Na ferramenta
O PlanetHunter faz exatamente a conta de raio_planeta para mostrar a coluna rp_rearth na lista de candidatos. Está em src/planethunter/pipeline.py, na função candidate_table, escrita em SQL: sqrt(fit_depth_ppm * 1e-6) * radius_rsun * 109.076. Outro exemplo: em src/planethunter/cli.py, a função _parse_ints transforma o texto "1,4,8" da opção --sectors na lista [1, 4, 8], usando split(",") e um laço compacto.
Módulos¶
Um módulo é um arquivo .py cujas funções você reaproveita em outros arquivos com import.
O Python já vem com muitos módulos. O math tem raiz quadrada, pi e outras funções:
Você também pode criar o seu. Salve as duas funções acima num arquivo transito.py. Em outro arquivo, na mesma pasta:
from transito import raio_planeta
rp = raio_planeta(10_583, 1.3466)
print(f"WASP-18 b: {rp:.1f} raios terrestres") # 15.1
Os números são reais: 10 583 ppm é a profundidade que o PlanetHunter mediu para WASP-18 b no setor 69, e 1,3466 R☉ é o raio da estrela no catálogo do TESS.
Bibliotecas como NumPy e Lightkurve são módulos feitos por outras pessoas. Você as instala com uv add e importa do mesmo jeito.
Erros: leia a última linha¶
Errar faz parte. Quando o Python encontra um problema, ele mostra um traceback. A informação mais útil está na última linha:
| Mensagem | Causa mais comum |
|---|---|
NameError: name 'periodo' is not defined |
Nome digitado errado ou variável criada depois de usada |
IndentationError |
Espaços do começo da linha desalinhados |
TypeError: can't multiply sequence by non-int of type 'float' |
Tentou multiplicar uma lista por um número (isso só funciona com NumPy, aula P2) |
KeyError: 'raio' |
Chave que não existe no dicionário |
IndexError: list index out of range |
Pediu um elemento além do fim da lista |
Exercícios¶
Exercício 1. Conversões
O PlanetHunter mediu 10 583 ppm para WASP-18 b. Escreva um script que mostre esse valor como fração e como porcentagem.
Exercício 2. Função de classificação
Escreva a função classifica(prof_ppm, rs_rsun) que use raio_planeta e devolva o texto da classe de tamanho (use o if da seção "Decisões"). Teste com WASP-18 b (10 583 ppm, 1,3466 R☉) e com uma queda de 40 000 ppm numa estrela de 1,5 R☉.
Ver resposta
from transito import raio_planeta
def classifica(prof_ppm: float, rs_rsun: float) -> str:
"""Classe de tamanho a partir da profundidade (ppm) e de R* (R_sol)."""
rp = raio_planeta(prof_ppm, rs_rsun)
if rp < 4:
return f"{rp:.1f} R_terra: rochoso a mini-Netuno"
elif rp < 8:
return f"{rp:.1f} R_terra: tamanho de Netuno"
elif rp <= 20:
return f"{rp:.1f} R_terra: gigante"
return f"{rp:.1f} R_terra: grande demais, desconfie de binária"
print(classifica(10_583, 1.3466)) # 15.1 R_terra: gigante
print(classifica(40_000, 1.5)) # 32.7 R_terra: grande demais...
radius do vetting desconfia: provavelmente uma estrela pequena eclipsando outra (aula B4).
Exercício 3. Caçando aliases
Uma busca devolveu estes períodos para a mesma estrela: [0.9416, 1.8832, 0.4708, 2.8248]. Use um laço para dividir cada um pelo primeiro e diga quais são aliases (múltiplos ou frações do período verdadeiro).
Ver resposta
periodos = [0.9416, 1.8832, 0.4708, 2.8248]
base = periodos[0]
for p in periodos:
razao = p / base
print(f"{p:.4f} d -> {razao:.2f} x o primeiro")
Checklist da aula¶
- Criei variáveis de cada tipo e conferi com
type() - Converti uma profundidade entre fração, ppm e por cento
- Usei lista e dicionário com dados de uma estrela
- Escrevi um laço que calcula profundidades de vários planetas
- Escrevi as funções
profundidade_ppmeraio_planetacom docstring e unidades - Importei minhas funções de um módulo
transito.py - Resolvi os três exercícios
Para ir além¶
- Curso em Vídeo — Python, mundos 1 e 2 (Gustavo Guanabara). Cobre com calma tudo desta aula, com exercícios corrigidos em vídeo.
- Tutorial oficial do Python, que tem tradução para o português no site docs.python.org. Bom para consultar um assunto específico, como dicionários.
- Seção sobre o método de trânsito no site da NASA (science.nasa.gov/exoplanets). Para revisar a física por trás das contas que você programou.