Unidade 7 · a prateleira

A prateleira

Na prateleira tem o que outra pessoa (ou você, noutro arquivo) já escreveu. import, random, statistics, sys.argv, fatias, pip, JSON — e o módulo da casa.

Nesta unidade Se você copia função de um projeto para o outro, dá para faturar isso num arquivo e carregar. A biblioteca padrão já traz sorteio e média. Argumentos no comando evitam o input a cada vez. Pacote de fora se instala com pip.

Não copie o mesmo arquivo de novo

Biblioteca é código que outra pessoa (ou você, noutro dia) já escreveu. Módulo, nesta linguagem, é isso em um arquivo: uma ou mais funções (e outros recursos) com nome. O ponto é reúso. Copiar-colar o mesmo bloco em três projetos vira três cópias para consertar. Fatore: um arquivo, vários programas carregam.

print e input já estão na memória. Outras funções ficam num arquivo no disco — depois que o interpretador foi instalado, existe um random.py em algum lugar. Para usar, você importa de propósito.

A documentação oficial descreve cada módulo: o que existe, o que cada função espera. Não invente a matemática do sorteio se alguém já resolveu.

Cara ou coroa

Arquivo sorteio.py. Primeira linha (ou quase): import random. Isso libera as funções daquele módulo. A docs descreve random.choice(seq): seq é sequência — lista, ou coisa de lista. Devolve um item, probabilidade igual para cada um. Dois itens = 50/50; três = cerca de um terço cada.

import random

moeda = random.choice(["cara", "coroa"])
print(moeda)

Lista: colchetes, vírgulas, strings entre aspas. Os parênteses de fora são da função. O ponto: random.choice — de qual módulo vem esta choice.

Rode três vezes. Cara, cara, coroa não é bug: é pouca amostra. No infinito, aproxima 50/50.

7.A · import

Uma linha que importe um módulo (ou um nome com from).

import random
Ou: from random import choice
Solução: import random

O nome sozinho, ou com o módulo

import random traz o módulo inteiro. Aí você escreve random.choice sempre. Alternativa: from random import choice — o nome choice entra no vocabulário deste arquivo. Dá para chamar choice(["cara", "coroa"]) sem o prefixo.

Quando o prefixo ajuda: você já tem uma variável ou função chamada choice. O módulo guarda os nomes no próprio escopo; não colidem. Quando o prefixo cansa: a mesma chamada dezenas de vezes. Não há um único certo. Programa curto, os dois valem; em projeto maior, o prefixo deixa claro de onde veio.

Inteiro entre A e B, inclusive

random.randint(1, 10) devolve um inteiro de 1 a 10 incluindo os dois — cerca de 10% cada. Dado, senha da fila, personagem de jogo que não é previsível.

import random

n = random.randint(1, 10)
print(n)

Embaralhar no lugar

random.shuffle(lista) mexe na lista que você passou — como baralho. Não devolve um baralho novo: devolve None. Por isso cartas = random.shuffle(cartas) esvazia a gaveta.

import random

cartas = ["valete", "dama", "rei"]
random.shuffle(cartas)
for c in cartas:
    print(c)

Três cartas, poucas ordens: repetir a mesma sequência umas vezes é chance, não prova de que está quebrado. choice devolve um item e deixa a lista intacta. shuffle altera.

7.B · shuffle

Por que não fazer cartas = random.shuffle(cartas)?

choice devolve um valor. shuffle não.
No lugar = a lista original é quem muda.
Solução: devolve None; não atribua o retorno.

Média sem reinventar

Outro arquivo da instalação: statistics. mean é média. Conta da mesa, duas notas — você não precisa somar e dividir na mão se o módulo já faz.

import statistics

precos = [8.5, 5.0]
print(statistics.mean(precos))

Há mediana, moda, e o resto na docs. Mesma ideia: import, depois modulo.funcao.

Argumentos no comando

Até agora o dado entra com input, depois que o programa já rodou. Dá para passar na hora do comando: python cracha.py Ana. Isso é argumento de linha de comando — não só desta linguagem.

Módulo sys (sistema). Variável sys.argv: argument vector, lista das palavras digitadas no prompt. Índice 0 é o nome do arquivo. 1 em diante são o que veio depois. Tudo string.

import sys

print("Crachá:", sys.argv[1])

python cracha.py Ana imprime o nome. sys.argv[0] é cracha.py — pouco interessante, mas é o contrato. O interpretador python em si não entra nessa lista.

7.C · argv

Em python cracha.py Ana, o nome Ana está em que índice de sys.argv?

A lista começa pelo próprio script.
O primeiro argumento do usuário é o segundo item.
Solução: índice 1.

Quando [1] não existe

python cracha.py sem nome: a lista tem um item só. Pedir [1] levanta IndexErrorlist index out of range. Erro clássico de lista em qualquer linguagem: foi longe demais para a direita (ou para a esquerda).

Trocar para [0] imprime o nome do arquivo no crachá. Não é o que você quer. Unidade 6: try / except IndexError e um recado “faltou o nome”. Ou, mais fino, conferir o tamanho antes e dizer se foi pouco ou demais.

import sys

if len(sys.argv) < 2:
    print("faltou o nome")
elif len(sys.argv) > 2:
    print("nome demais")
else:
    print("Crachá:", sys.argv[1])

Dois argumentos no total: arquivo + um nome. Nome composto no comando: aspas em volta — python cracha.py "Ana Silva" — senão cada palavra vira um índice. else só um; vários elif no meio.

Aspas esquecida no print continua sendo SyntaxError: o programa nem arranca. Condicional não pega isso. Fecha a aspas e rode de novo (unidade 6).

7.D · índice

python cracha.py sem nome, e o código faz print(sys.argv[1]). O que acontece?

Sem palavra extra, a lista tem um item.
Índice 1 está fora.
Solução: IndexError.

Checar erro em cima, trabalho embaixo

O crachá no else funciona, mas esconde o que o programa é. Melhor: tratar o caso ruim no topo e, se não dá para seguir, sair. sys.exit("faltou o nome") imprime o recado e encerra. Aí a linha do print do crachá fica alinhada à esquerda, depois de todos os testes — você já pode confiar que [1] existe.

import sys

if len(sys.argv) < 2:
    sys.exit("faltou o nome")
if len(sys.argv) > 2:
    sys.exit("nome demais")

print("Crachá:", sys.argv[1])

Sem o exit, o print de baixo roda mesmo depois de “faltou o nome” e cai no IndexError. O arquivo já ia acabar sozinho no fim; exit é para sair antes. break sai de loop, não do programa (unidade 3).

Quem importa este arquivo como biblioteca não quer que o programa inteiro morra no meio: aí é raise (unidade 6), não sys.exit.

7.E · exit

Um trecho que leia sys.argv ou chame sys.exit.

import sys no topo.
sys.argv[1] ou sys.exit("faltou o nome")
Exemplo:
import sys
sys.exit("faltou o nome")

Vários nomes, sem o nome do arquivo

Vários crachás: python cracha.py Ana Bia Leo. Não há “nome demais”. Percorra a lista. Bug: for arg in sys.argv inclui o .py — um crachá a mais, para o programa.

Fatia: pedaço da lista. sys.argv[1:] começa no 1 e vai até o fim (o segundo número omitido). O : aqui não é o da f-string :.2f — mesmo símbolo, outro contexto, poucas teclas no teclado.

import sys

if len(sys.argv) < 2:
    sys.exit("faltou o nome")

for nome in sys.argv[1:]:
    print("Crachá:", nome)

Número negativo conta do fim: [1:-1] larga o último. "Bia"[1:] é ia — a mesma ideia em string.

7.F · fatia

O que "Bia"[1:] devolve? (sem aspas)

Índice 0 é B. A fatia começa no 1.
Do segundo caractere até o fim.
Solução: ia

O que não veio na caixa

Pacote, na prática: biblioteca de terceiros. Às vezes é um módulo numa pasta, não só um arquivo. O índice público se chama PyPI. Instalador: pip, que costuma vir com o Python. pip install nome baixa e deixa o import funcionar.

random e sys já estavam lá. Pedido HTTP, gráfico, planilha — outra história. Leia o nome do pacote: um quase igual pode ser outra coisa. ModuleNotFoundError: não instalou neste interpretador, ou o nome do import não é o do pip.

Argumento no comando é menos amigável para quem não programa. Para quem programa, é mais rápido: uma linha só, histórico da seta para cima, automação. Por isso python arquivo.py em vez de o interpretador perguntar o nome do arquivo toda vez.

7.G · pip

Quando você precisa do pip install?

random já vem com o Python.
pip é a loja do que falta.
Solução: o que não veio instalado.

Dados de outro computador

API (interface de programação) não é só desta linguagem: serviço — muitas vezes na internet — que o seu código consulta como se fosse um navegador. Pacote comum para isso: requests (pip install requests). requests.get(url) devolve a resposta.

O texto que chega costuma ser JSON: chaves e valores, chaves { }, listas [ ], aspas. Parece dicionário desta linguagem de propósito. As chaves o servidor escolhe; você não as renomeia na origem — só guarda o valor numa variável sua.

# o servidor mandou algo neste formato:
o = {
    "quantidade": 1,
    "itens": [
        {"nome": "café", "preco": 8.5}
    ],
}
for item in o["itens"]:
    print(item["nome"])

No programa de verdade: resposta = requests.get(url), depois o = resposta.json(), o mesmo for. Módulo json da biblioteca padrão formata o blob para leitura (json.dumps(..., indent=2)) enquanto você descobre as chaves. Sem rede, o dicionário acima já treina o acesso.

O arquivo que os outros importam

Você também fatura função repetida. recados.py:

def ola(nome):
    print(f"olá, {nome}")

def tchau(nome):
    print(f"tchau, {nome}")

def main():
    ola("fila")
    tchau("fila")

if __name__ == "__main__":
    main()

Noutro arquivo, na mesma pasta: from recados import ola. O Python lê recados.py de cima a baixo. Se o main() estiver solto no fim, o teste “olá, fila” roda no import — misturado com o programa que só queria ola.

__name__ vale "__main__" quando você roda python recados.py. Quando outro arquivo importa, o nome é o do módulo, não __main__, e o if não chama main. Por isso o disparo condicional da unidade 4: não é enfeite.

7.H · __name__

Por que o main de teste em recados.py precisa do if __name__ == "__main__"?

from recados import ola lê o arquivo inteiro.
A última linha, se for main() nu, executa.
Solução: o import dispararia o teste.

Oficina · sorteio

Problema da unidade Sorteie um item de uma lista (nomes da fila, cara/coroa, sucos) com random e imprima. Arquivo: sorteio.py. Opcional: ler o nome no comando com sys.argv em vez de input.
Oficina 7

Cole um programa com random e print.

import random
print(random.choice(["cara", "coroa"]))
Modelo:
import random
print(random.choice(["Ana", "Bia", "Leo"]))