Escolar Documentos
Profissional Documentos
Cultura Documentos
------------------------------------------------------------------------------------------------------------------------------
Vamos estudar?
Se você já trabalhou com Python ou qualquer outra linguagem, este livro ainda pode ser útil
para você como uma referência aos fundamentos do Python e para fornecer uma ampla gama
de considerações e sugestões.
Conteúdos
1 Por que você deve aprender a escrever programas?
1.12 Glossário
1.13 Exercícios
2 Variáveis, expressões e instruções
2.2 Variáveis
2.4 Declarações
2.6 Expressões
2.11 Comentários
2.13 Depuração
2.14 Glossário
2.15 Exercícios
3 Execução condicional
3.9 Depuração
3.10 Glossário
3.11 Exercícios
4 Funções
4.12 Depuração
4.13 Glossário
4.14 Exercícios
5 Iteração
5.8 Depuração
5.9 Glossário
5.10 Exercícios
6 Cordas 67
6.7 O operador in
6.12 Depuração
6.13 Glossário
6.14 Exercícios
7 Arquivos
7.1 Persistência
7.9 Depuração
7.10 Glossário
7.11 Exercícios
8 Listas
8.12 Alias
8.14 Depuração
8.15 Glossário
8.16 Exercícios
9 Dicionários
9.5 Depuração
9.6 Glossário
9.7 Exercícios
10 Tuplas
10.9 Depuração
10.10Glossário
10.11 Exercícios
11 Expressões regulares
11.5 Resumo
11.7 Depuração
11.8 Glossário
11.9 Exercícios
12 programas em rede
12.9 Glossário
12.10 Exercícios
13.9 Glossário
13.10 Exercícios
14.2 Iniciando
14.3 Usando Objetos
14.10 Herança
14.11 Resumo
14.12 Glossário
15.11 Resumo
15.12 Depuração
15.13Glossário
16 Visualizando dados
Estamos cercados em nossas vidas diárias por computadores que variam de laptops a
celulares. Podemos pensar nesses computadores como nossos “assistentes pessoais” que
podem assumir e cuidar de muitas coisas em nosso nome. O hardware em nossos
computadores atuais é essencialmente construído para nos fazer continuamente a pergunta:
“O que você gostaria que eu faça a seguir?”
Nossos computadores são rápidos e têm grande quantidade de memória e podem ser muito
úteis para nós, se apenas soubéssemos a língua para falar para explicar ao computador o que
gostaria de “fazer a seguir”. Se soubéssemos esta linguagem, poderíamos dizer ao computador
para fazer tarefas em nosso nome que eram repetitivas. Curiosamente, os tipos de coisas que
computadores podem fazer melhor são muitas vezes os tipos de coisas que nós, humanos,
achamos chatos e cansativas.
Por exemplo, olhe para os três primeiros parágrafos deste capítulo e diga-me a palavra mais
comumente usada e quantas vezes a palavra é usada. contá-las é quase doloroso porque não é
o tipo de problema que as mentes humanas são projetadas para resolver.
Seu computador ou Personal Digital Assistant (PDA) geralmente contém muitos programas
diferentes de muitos grupos diferentes de programadores, cada um competindo por sua
atenção e interesse. Eles tentam o seu melhor para atender às suas necessidades e dar-lhe
uma ótima experiência do usuário no processo. Em algumas situações, quando você escolhe
uma peça de software, os programadores são diretamente compensados por sua escolha. Se
pensarmos em programas como a produção criativa de grupos de programadores, talvez a
figura a seguir é uma versão mais sensata do nosso PDA
Por enquanto, nossa principal motivação não é ganhar dinheiro ou agradar os usuários finais,
mas em vez disso, para sermos mais produtivos no manuseio dos dados e informações que
encontraremos em nossas vidas. Quando você começar, você será o programador e o usuário
final de seus programas. À medida que você ganha habilidade como programador e sua
gramática parecer mais criativa para você, seus pensamentos podem se voltar para o
desenvolvimento de programas para outros.
• A Memória Principal RAM é usada para armazenar informações que a CPU precisa. A
memória principal é quase tão rápida quanto a CPU. Mas as informações armazenadas na
memória principal desaparecem quando o computador é desligado.
• A Memória Secundária também é usada para armazenar informações, mas é muito mais
lenta que a memória principal. A vantagem da memória secundária é que ele pode
armazenar informações mesmo quando não há energia no computador. Exemplos de
memória secundária são unidades de disco ou memória flash (normalmente encontrados em
pendrives e tocadores de música portáteis).
• Atualmente, a maioria dos computadores também possui uma conexão de rede para
recuperar informação através de uma rede. Podemos pensar na rede como uma rede muito
lenta. lugar para armazenar e recuperar dados que podem nem sempre estar “ativos”.
Então, em certo sentido, a rede é uma forma mais lenta e às vezes não confiável de memória
secundária.
Embora a maior parte dos detalhes de como esses componentes funcionam seja melhor deixar
para os construtores de computadores, isso irá ajuda a ter alguma noção para podermos falar
sobre essas diferentes partes enquanto escrevemos nossos programas.
Como programador, seu trabalho é usar e orquestrar cada um desses recursos para resolver os
problemas que você precisa resolver, e analise os dados que você obtém da solução. Como
programador, você estará “conversando” principalmente com a CPU e dizendo o que fazer a
seguir. Às vezes, você dirá à CPU para usar a memória principal, memória secundária, rede ou
dispositivos de entrada/saída.
Você precisa ser a pessoa que responde à pergunta "E agora?". Mas isso seria muito
desconfortável encolhê-lo para 5 mm de altura e inseri-lo em um computador apenas para que
você pudesse emitir um comando três bilhões de vezes por segundo. Então em vez disso, você
deve anotar suas instruções com antecedência.
• Segundo - você precisa “contar uma história”. Ao escrever uma história, você combina
palavras e frases para transmitir uma ideia ao leitor. Há habilidade e arte em construção da
história, e a habilidade na escrita da história é melhorada fazendo algumas escrever e obter
algum feedback. Na programação, nosso programa é a “história” e o problema que você está
tentando resolver é a “ideia”.
Depois de aprender uma linguagem de programação como Python, você descobrirá que é
muito mais fácil aprender uma segunda linguagem de programação, como JavaScript ou C++.
Quando treinamos um cachorro, usamos palavras especiais como “senta”, “fica” e “busca”.
Quando você fala com um cachorro e não usa nenhuma das palavras reservadas, eles apenas
olham para você com um olhar interrogativo no rosto até você dizer uma palavra reservada.
Por exemplo, se você diz: “Gostaria que mais pessoas caminhassem para melhorar sua saúde
geral”, o que a maioria dos cães provavelmente ouve é "blá, blá, blá, ande, blá, blá, blá, blá".
Isso é porque “andar” é uma palavra reservada na linguagem canina. Muitos podem sugerir
que a linguagem entre humanos e gatos não tem palavras reservadas.
as elif if or yield
Aprenderemos essas palavras reservadas e como elas são usadas oportunamente, mas para
agora vamos nos concentrar no equivalente Python de “falar” (na linguagem de humano para
cachorro). O bom de dizer ao Python para falar é que podemos até dizer a ele o que dizer
dando-lhe uma mensagem entre aspas:
E até escrevemos nossa primeira sentença Python sintaticamente correta. Nossa frase começa
com a função print seguida por uma string de texto de nossa escolha entre aspas simples.
1.5 Conversando com Python
Agora que temos uma palavra e uma frase simples que conhecemos em Python, precisamos
saber como iniciar uma conversa com Python para testar nossas novas habilidades de
linguagem.
Antes de poder conversar com Python, você deve primeiro instalar o software Python3 em seu
computador e aprenda como iniciar o Python em seu computador. Isso e muitos detalhes para
este capítulo, então sugiro que você consulte https://python.org.br/instalacao-windows/ onde
Tem as instruções detalhadas de como configurar e iniciar o Python em Sistemas Windows
(baixe de acordo com seu sistema operacional). Em algum momento, você estará em um
terminal ou janela de comando e você digitará python e o interpretador Python será iniciado
executando o modo interativo e aparecem mais ou menos como isso:
>>>
O prompt >>> é a maneira do interpretador Python perguntar a você: “O que você quer que eu
faça a seguir?”
O Python está pronto para conversar com você. Tudo o que tens que saber é como falar a
linguagem Python.
Digamos, por exemplo, que você não conhece nem a linguagem Python e as mais simples
palavras ou frases. Você pode querer usar a linha padrão que os astronautas usam quando eles
pousam em um planeta distante e tentam falar com os habitantes do planeta:
>>>
Isso não está correto. A menos que você pense em algo rapidamente, os habitantes do planeta
provavelmente irão apunhalá-lo com suas armas extraterrestres, colocá-lo em um espeto, e
assá-lo sobre uma fogueira de chama verde, e usá-lo para o jantar.
Felizmente, você trouxe uma cópia deste livro em suas viagens e folheia esta página e tente
novamente:
Agora Isso está parecendo muito melhor, e correto, então você tenta se comunicar um pouco
mais:
>>> print('Nossa lenda diz que vocês nem existiam, e que são cabeçudos’)
Nossa lenda diz que vocês nem existiam, e que são cabeçudos
A conversa estava indo tão bem por um tempo e então você fez o menor erro usando a
linguagem Python e Python trouxe o jantar deles de volta.
Neste ponto, você também deve perceber que, embora o Python seja incrivelmente complexo
e poderoso e muito exigente quanto à sintaxe que você usa para se comunicar com ele, o
Python não é inteligente. Você está apenas tendo uma conversa consigo mesmo, mas usando a
sintaxe adequada.
De certo modo, quando você usa um programa escrito por outra pessoa, a conversa é entre
você e os outros programadores com Python atuando como intermediário. Python é uma
maneira de os criadores de programas expressarem como a conversa é e deveria prosseguir. E
em apenas mais alguns capítulos, você será um daqueles programadores usando Python para
conversar com os usuários do seu programa.
>>> quit()
Você notará que o erro é diferente nas duas primeiras tentativas incorretas. O segundo erro é
diferente porque if é uma palavra reservada e o Python viu o reservado da palavra e pensou
que estávamos tentando dizer algo, mas entendeu a sintaxe da frase errada.
A maneira correta de dizer “adeus” ao Python é inserir quit() no divisa >>> prompt.
Provavelmente você levaria um bom tempo para adivinhar que ter um livro em mãos
provavelmente seria útil para conversar com extraterrestres.
1.6 Terminologia: interpretador e compilador
Python é uma linguagem de alto nível destinada a ser relativamente simples para humanos.
Para o homem ler e escrever e para os computadores ler e processar. Outros de alto nível de
linguagens incluem Java, C++, PHP, Ruby, Basic, Perl, JavaScript e muito mais.
O hardware real dentro da Unidade Central de Processamento (CPU) não suporta qualquer
uma dessas linguagens de alto nível.
001010001110100100101010000001111
11100110000011101010010101101101
...
A linguagem de máquina parece bastante simples na superfície, dado que existem apenas
zeros e uns, mas sua sintaxe é ainda mais complexa do que Python. Portanto, muito poucos
programadores escrevem linguagem de máquina. Em vez disso, construímos vários tradutores
para permitir que os programadores escrevam em linguagens de alto nível como Python ou
JavaScript, e esses tradutores convertem os programas em linguagem de máquina para
execução real pela CPU.
1- Interpretadores
2- Compiladores
Algumas das linhas de comando dizem ao Python que você deseja que ele se lembre de algum
valor para mais tarde utilizar. Precisamos escolher um nome para esse valor ser lembrado e
podemos usar esse nome simbólico para recuperar o valor mais tarde. Usamos o termo
variável para nos referir aos rótulos que usamos para nos referir a esses dados armazenados.
>>> x = 6
>>> print(x)
>>> y = x * 7
>>> print(y)
42
>>>
Neste exemplo, pedimos ao Python para lembrar o valor seis e usar o rótulo x para podermos
recuperar o valor mais tarde. Verificamos que o Python realmente se lembrou do valor usando
print.
Então pedimos ao Python para recuperar x e multiplicá-lo por sete e colocar o novo valor
calculado em y. Em seguida, pedimos ao Python para imprimir o valor atualmente em y.
Mesmo que estejamos digitando esses comandos no Python uma linha por vez, o Python está
tratando-os como uma sequência ordenada de declarações com declarações posteriores
capazes para recuperar dados criados em instruções anteriores. Estamos escrevendo nosso
primeiro simples parágrafo com quatro frases em uma ordem lógica e significativa.
É da natureza de um intérprete ser capaz de ter uma conversa interativa como mostrado
acima. Um compilador precisa receber todo o programa em um arquivo, e, em seguida,
executa um processo para traduzir o código-fonte de alto nível em linguagem de máquina e,
em seguida, o compilador coloca a linguagem de máquina resultante em um arquivo para
posterior execução.
^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@\xa0\x82
^D^H4^@^@^@\x90^]^@^@^@^@^@^@4^@ ^@^G^@(^@$^@!^@^F^@
^@^@4^@^@^@4\x80^D^H4\x80^D^H\xe0^@^@^@\xe0^@^@^@^E
^@^@^@^D^@^@^@^C^@^@^@^T^A^@^@^T\x81^D^H^T\x81^D^H^S
^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A\^D^HQVhT\x83^D^H\xe8
....
Não é fácil ler ou escrever linguagem de máquina, por isso é bom termos inter-preters e
compiladores que nos permitem escrever em linguagens de alto nível como Python ou C.
Agora, neste ponto de nossa discussão sobre compiladores e interpretadores, você deve estar
pensando um pouco sobre o próprio interpretador Python. Em que língua está escrito em?
Está escrito em uma linguagem compilada? Quando digitamos em “python”, o que exatamente
está acontecendo?
O interpretador Python é escrito em uma linguagem de alto nível chamada “C”. Você pode
olhar no código-fonte real do interpretador Python acessando www.python.org e trabalhando
seu caminho para o código-fonte. Então Python é um programa em si e é compilado em código
de máquina. Quando você instalou o Python em seu computador, você copiou uma cópia do
código de máquina do Python traduzindo o programa em seu sistema. No Windows, o código
de máquina executável para Python em si provavelmente está em um arquivo com um nome
como:
C:\Python35\python.exe
Isso é mais do que você realmente precisa saber para ser um programador Python, mas às
vezes vale a pena responder a essas pequenas perguntas incômodas logo no início.
Quando queremos escrever um programa, usamos um editor de texto para escrever o Python
instruções em um arquivo, que é chamado de script. Por convenção, os scripts Python têm
nomes que terminam com .py.
Para executar o script, você deve informar ao interpretador Python o nome do arquivo. Em
uma janela de comando Unix ou Windows, você digitaria python hello.py como segue:
print('Hello world!')
Hello world!
csev$
O “csev$” é o prompt do sistema operacional e o “cat hello.py” está nos mostrando que o
arquivo “hello.py” tem um programa Python de uma linha para imprimir uma string.
Chamamos o interpretador Python e dizemos para ele ler seu código-fonte do arquivo
“hello.py” em vez de nos solicitar linhas de código Python interativamente. Você notará que
não havia necessidade de ter quit () no final do Python programado no arquivo.
Quando o Python está lendo seu código-fonte de um arquivo, ele sabe parar quando chegar
ao final do arquivo.
1.8 O que é um programa?
A definição de um programa em sua forma mais básica é uma sequência de instruções Python
que foram criados para fazer algo. Mesmo nosso script hello.py simples é um programa. É um
programa de uma linha e não é particularmente útil, mas no mais estrito definição, é um
programa Python.
Pode ser mais fácil entender o que é um programa pensando em um problema que um
programa pode ser construído para resolver e, em seguida, olhando para um programa que
resolver esse problema.
Digamos que você esteja fazendo uma pesquisa de Computação Social em postagens do
Facebook e esteja interessado na palavra mais usada em uma série de postagens. Você
poderia imprimir o fluxo de postagens do Facebook e se debruçar sobre o texto procurando o
mais comum palavra, mas isso levaria muito tempo e seria muito propenso a erros. Você seria
inteligente para escrever um programa Python para lidar com a tarefa com rapidez e precisão
para que você poça passar o fim de semana fazendo algo divertido.
Por exemplo, observe o seguinte texto sobre um palhaço e um carro. olha o texto e descubra a
palavra mais comum e quantas vezes ela ocorre.
Então imagine que você está fazendo esta tarefa olhando para milhões de linhas de texto.
Francamente, seria mais rápido para você aprender Python e escrever um programa Python
para contar as palavras do que escanea-las manualmente.
A notícia ainda melhor é que já criei um programa simples para encontrar a palavra mais
comum em um arquivo de texto. Escrevi, testei e agora estou dando para você usar para que
você possa economizar algum tempo.
text = handle.read()
words = text.split()
counts = dict()
counts[word] = counts.get(word, 0) + 1
bigcount = None
bigword = None
for word, count in list(counts.items()):
bigword = word
bigcount = count
# Código: http://www.pythonlearn.com/code3/words.py
Você nem precisa saber Python para usar este programa. Você vai precisar leia o Capítulo 10
deste livro para entender completamente o incrível mundo Python e as técnicas que foram
usadas para fazer o programa. Você é o usuário final, basta usar o programa e maravilhe-se
com sua inteligência e como ele economizou seu tempo e seus esforços. Você simplesmente
digita o código em um arquivo chamado words.py e o executa ou você baixe o código-fonte
em http://www.pythonlearn.com/code3/ e execute-o.
Este é um bom exemplo de como o Python e a linguagem Python estão agindo como um
intermediário entre você (o usuário final) e eu (deex). Python é uma maneira de trocarmos
sequências de instruções úteis (ou seja, programas) em uma linguagem que pode ser usada
por qualquer pessoa que instale o Python em seu computador. Então nenhum de nós estamos
falando com Python, em vez disso, estamos nos comunicando um com o outro através do
Python.
Input - Obtenha dados do “mundo exterior”. Isso pode estar lendo dados de uma arquivo, ou
mesmo algum tipo de sensor como um microfone ou GPS. Em nossos programas iniciais, nossa
entrada virá dos dados digitados pelo usuário no teclado.
sequential execution - Executa instruções uma após a outra na ordem em que são
encontrados no script.
Reuse - Escreva um conjunto de instruções uma vez e dê um nome a elas e depois reutilize-as
instruções conforme necessário ao longo de seu programa.
Parece quase simples demais para ser verdade e, claro, nunca é tão simples. É como dizemos
que andar é simplesmente “colocar um pé na frente do outro”. A arte de escrever um
programa é compor e entrelaçar esses elementos básicos muitas vezes para produzir algo que
seja útil para seus usuários. O programa de contagem de palavras acima usa diretamente
todos esses padrões, exceto um.
Os programadores iniciantes geralmente consideram o fato de que o Python não deixa espaço
para erros como evidência de que Python é mesquinho, odioso e cruel. Enquanto Python
parece gostar de todos os outros, Python os conhecem pessoalmente e guarda rancor contra
eles.
Por causa desse rancor, o Python pega nossos programas perfeitamente escritos e rejeita
como “incapazes” apenas para nos atormentar. (Acho que exagerei um pouco, mas vamos la)
Há pouco a ganhar discutindo com Python. É apenas uma ferramenta. Não tem emoções e está
feliz e pronto para atendê-lo sempre que precisar. Seus erros nas mensagens parecem duras,
mas são apenas um pedido de ajuda do Python. Ele olhou para o que você digitou e
simplesmente não consegue entender o que você digitou.
Python é muito mais parecido com um cachorro, amando você incondicionalmente, tendo
algumas palavras-chave que ele entenda, olhando para você com um olhar doce em seu rosto
(>>>), e esperando para você dizer algo que entenda. Quando o Python diz SyntaxError:
invalid syntax
ele está simplesmente abanando o rabo e dizendo: “Parece que você disse algo mas eu
simplesmente não entendo o que você quis dizer, mas por favor continue falando comigo
(>>>).
À medida que seus programas se tornam cada vez mais sofisticados, você encontrará três
vários tipos de erros:
Syntax erros - Esses são os primeiros erros que você cometerá a ver e os mais fáceis de
corrigir. Erro de sintaxe significa que você violou as regras de “gramática” do Python. O Python
faz o possível para apontar diretamente para a linha e o caractere onde notou esta confuso. A
única parte complicada dos erros de sintaxe é que às vezes o erro que precisa ser consertado
é, na verdade, mais cedo no programa do que onde o Python percebeu que estava confuso.
Portanto, a linha e o caractere que o Python indica em um erro de sintaxe pode ser apenas um
ponto de partida para sua investigação.
Logic erros - Um erro de lógica é quando seu programa tem uma boa sintaxe, mas há um erro
na ordem das declarações ou talvez um erro na forma como a declarações se relacionam entre
si. Um bom exemplo de um erro de lógica pode ser:
“Tomar um gole na sua garrafinha de água, colocar na mochila, caminhar até a biblioteca e, em
seguida, coloque a tampa de volta na garrafa”.
Semantic erros - Um erro semântico é quando sua descrição das etapas a serem seguidas é
sintaticamente perfeito e na ordem certa, mas há simplesmente um erro no programa. O
programa está perfeitamente correto, mas não faz o que você destinou a fazê-lo. Um exemplo
simples seria se você estivesse dando a uma pessoa instruções para um restaurante e disse: “. .
. ao chegar ao cruzamento com o posto de gasolina, vire à esquerda e ande uns metros e o
restaurante é um prédio vermelho à sua esquerda." Seu amigo está muito atrasado e liga para
você para dizer que eles estão em uma fazenda e andando atrás de um celeiro, sem sinal de
restaurante. Então você diz "você virou à esquerda ou à direita no posto de gasolina?" e eles
dizem: “Eu segui suas instruções perfeitamente, eu as escrevi, diz vire à esquerda e percorrer
alguns metros do posto de gasolina. Então você diz: “Sinto muito, porque embora minhas
instruções estivessem sintaticamente corretas, infelizmente continham um pequeno erro
semântico não detectado.”.
Novamente em todos os três tipos de erros, o Python está apenas tentando ao máximo fazer
exatamente o que você perguntou.
E tudo bem se levasse seis meses para você passar do vocabulário simples para as frases
simples e levou mais 5-6 anos para passar de frases para parágrafos, e mais alguns anos para
poder escrever um conto interessante e completo sobre você próprio.
Quero que você aprenda Python muito mais rapidamente, então ensinamos tudo ao mesmo
tempo nos próximos capítulos. Mas é como aprender um novo idioma que leva tempo para
absorver e entender antes que pareça natural. Isso leva a alguma confusão como ler e ler
novamente os tópicos para tentar fazer com que você veja o quadro geral enquanto estamos
definindo os pequenos fragmentos que compõem esse grande quadro. Enquanto o livro é
escrito linearmente, e se você estiver fazendo um curso, ele progredirá de maneira linear, não
hesite em ser muito não linear em como você aborda o material. Olhe para a frente e para trás
e leia devagar. Desnatando material mais avançado sem entender completamente os detalhes,
você pode obter uma melhor compreensão do "por que?" de programação. Revendo material
anterior e até mesmo refazendo os exercícios, você perceberá que realmente aprendeu muito
do material, mesmo que o material que você está olhando parece um pouco impenetrável.
Se algo parece particularmente difícil, geralmente não vale a pena ficar acordado a noite toda
olhando para ela. Faça uma pausa, tire uma soneca, faça um lanche, explique o que você está
tendo problemas com alguém (ou talvez com seu cachorro) e depois volte a ele com novos
olhos. Garanto-lhe que uma vez que você aprender os conceitos de programação nesse e-
book, você vai olhar para trás e ver que foi tudo muito fácil, elegante e simplesmente levou um
pouco de tempo para absorvê-lo. :D
1.12 Glossário
Bug - Um erro em um programa.
Compilar - Para traduzir um programa escrito em uma linguagem de alto nível para uma
linguagem de baixo nível de uma só vez, em preparação para execução posterior.
linguagem de alto nível - Uma linguagem de programação como o Python, projetada para ser
fácil para os humanos lerem e escreverem.
Interpret - Para executar um programa em uma linguagem de alto nível, traduzindo-o uma
linha de cada vez.
linguagem de baixo nível - Uma linguagem de programação projetada para ser fácil para um
computador executar; também chamado de “código de máquina” ou “linguagem de
montagem”.
Código da máquina - A linguagem de nível mais baixo para software, que é a linguagem que é
executado diretamente pela unidade central de processamento (CPU).
função print - Uma instrução que faz com que o interpretador Python exiba um valor na tela.
Prompt - Quando um programa exibe uma mensagem e faz uma pausa para que o usuário
digite alguma entrada para o programa.
memória secundária - Armazena programas e dados e retém suas informações mesmo quando
a alimentação é desligada. Geralmente mais lento que a memória principal. Exemplos de
memória secundária incluem unidades de disco e memória flash em pendrives.
1.13 Exercícios
Exercício 1: Qual é a função da memória secundária em um computador?
a) O interpretador Python
b) O teclado
>>>
Exercício 6: Onde no computador uma variável como “X” é armazenada após a seguinte linha
Python termina?
x = 123
b) Memória Principal
c) Memória Secundária
d) Dispositivos de Entrada
e) Dispositivos de saída
x = 43
x=x+1
print(x)
a) 43
b) 44
c) x + 1
Exercício 8: Explique cada um dos itens a seguir usando um exemplo de capacidade humana:
(5) Dispositivo de saída. Por exemplo, “Qual é o equivalente humano a uma Unidade central
de processamento"?
A instrução print também funciona para números inteiros. Usamos o comando python para
iniciar o intérprete.
python
>>> print(4)
Se você não tiver certeza do tipo de um valor, o interpretador pode lhe dizer.
<class 'str'>
>>> type(17)
<class 'int'>
Não surpreendentemente, strings pertencem ao tipo str e inteiros pertencem ao tipo int.
Menos obviamente, números com ponto decimal pertencem a um tipo chamado float, porque
esses números são representados em um formato chamado ponto flutuante.
>>> type(3.2)
<class 'float'>
E quanto o valores como “17” e “3,2”? Parecem números, mas estão em aspas como strings.
>>> type('17')
<class 'str'>
>>> type('3.2')
<class 'str'>
Ao digitar um número inteiro grande, você pode ficar tentado a usar vírgulas entre grupos de
três dígitos, como em 1.000.000. Este não é um número inteiro legal em Python, mas é legal:
>>> print(1,000,000)
100
Bem, isso não é o que esperávamos! Python interpreta 1.000.000 como uma vírgula, sequência
separada de inteiros, que imprime com espaços entre eles. Este é o primeiro exemplo que
vimos de um erro semântico: o código é executado produzindo uma mensagem de erro, mas
não faz a coisa "certa".
2.2 Variáveis
Um dos recursos mais poderosos de uma linguagem de programação é a capacidade de
manipular variáveis. Uma variável é um nome que se refere a um valor.
>>> n = 17
>>> pi = 3.1415926535897931
Este exemplo faz três atribuições. O primeiro atribui uma string a uma nova variável
mensagem nomeada; o segundo atribui o inteiro 17 a n; o terceiro atribui o (aproximado) valor
de π pi.
Para exibir o valor de uma variável, você pode usar uma instrução print:
>>> print(n)
17
>>> print(pi)
3.141592653589793
>>> type(message)
<class 'str'>
>>> type(n)
<class 'int'>
>>> type(pi)
<class 'float'>
Acontece que class é uma das palavras-chave do Python. O intérprete usa palavras-chave para
reconhecer a estrutura do programa, e não podem ser usados como uma variável.
Você pode querer manter esta lista à mão. Se o intérprete reclamar de uma das suas variáveis
e você não sabe por que, veja se está nesta lista.
2.4 Declarações
Uma instrução é uma unidade de código que o interpretador Python pode executar. Nós
temos dois tipos de instruções: print sendo uma instrução de expressão e atribuição. Quando
você digita uma instrução no modo interativo, o interpretador a executa e exibe o resultado,
se houver.
Um script geralmente contém uma sequência de instruções. Se houver mais de uma instrução,
os resultados aparecem um de cada vez conforme as instruções são executadas.
Por exemplo
print(1)
x=2
print(x)
Produz a saída
Houve uma alteração no operador de divisão entre Python 2.x e Python 3.x. No Python 3.x, o
resultado dessa divisão é um resultado de ponto flutuante:
>>> minute = 59
>>> minute/60
0.9833333333333333
O operador de divisão no Python 2.0 dividiria dois inteiros e arredondaria o resultado para um
inteiro:
>>> minute = 59
>>> minute/60
0
Para obter a mesma resposta no Python 3.0, use a divisão com ( // ). Isso irá arredondar o
resultado!
>>> minute = 59
>>> minute//60
No Python 3.0, a divisão inteira funciona muito mais do que você esperaria, se você inseriu a
expressão em uma calculadora.
2.6 Expressões
Uma expressão é uma combinação de valores, variáveis e operadores. Um valor todo por si, é
considerado uma expressão e, portanto, uma variável, então os seguintes são todos válidas
expressões (supondo que a variável x tenha um valor atribuído):
17
x + 17
Se você digitar uma expressão no modo interativo, o interpretador a avalia e exibe o resultado:
>>> 1 + 1
Mas em um script, uma expressão sozinha não faz nada! Isso é comumente fonte de confusão
para iniciantes.
Exercício 1: Digite as seguintes instruções no interpretador Python para ver o que eles fazem:
x=5
x+1
2.7 Ordem das operações
Quando mais de um operador aparece em uma expressão, a ordem de avaliação depende das
regras de precedência. Para operadores matemáticos, Python segue convenção matemática. A
sigla PEMDAS é uma maneira útil de lembrar as regras:
• Os parênteses têm a precedência mais alta e podem ser usados para forçar uma expressão
missão para avaliar na ordem que você deseja. Como as expressões entre parênteses são
avaliado primeiro, 2 * (3-1) é 4 e (1+1)**(5-2) é 8. Você também pode usar parênteses para
facilitar a leitura de uma expressão, como em (minuto * 100) / 60, mesmo que não altere o
resultado.
• A exponenciação tem a próxima precedência mais alta, então 2**1+1 é 3, não 4, e 3*1**3 é
3, não 27.
• Operadores com a mesma precedência são avaliados da esquerda para a direita. Então o
expressão 5-3-1 é 1, não 3, porque o 5-3 acontece primeiro e depois 1 é subtraído de 2.
Em caso de dúvida, sempre coloque parênteses em suas expressões para garantir que as
colocações estão sendo realizadas na ordem que você pretende.
>>> quotient = 7 // 3
>>> print(quotient)
>>> remainder = 7 % 3
>>> print(remainder)
>>> first = 10
>>> second = 15
>>> print(first+second)
25
100150
Alguma coisa
>>> print(input)
Alguma coisa
Antes de receber a entrada do usuário, é uma boa ideia imprimir um prompt informando o
usuário o que inserir. Você pode passar uma string para entrada para ser exibida para o
usuário antes de pausar para entrada:
Deex
>>> print(name)
Deex
A sequência \n no final do prompt representa uma nova linha, que é um caractere que causa
uma quebra de linha. É por isso que a entrada do usuário aparece abaixo do prompt. Se você
espera que o usuário digite um número inteiro, pode tentar converter o valor de retorno para
int usando a função int():
17
>>> int(velocidade)
17
>>> int(velocidade) + 5
22
Mas se o usuário digitar algo diferente de uma string de dígitos, você receberá um erro:
>>> int(velocidade)
Nesse caso, o comentário aparece sozinho em uma linha. Você também pode colocar
comentários no final de uma linha:
Tudo do \# até o final da linha é ignorado; não tem efeito sobre o programa.
Os comentários são mais úteis quando documentam recursos não óbvios do código. É razoável
supor que o leitor possa descobrir o que o código faz; isso é muito mais útil para explicar o
porquê.
v = 5 # atribui 5 a v
v = 5 # velocidade em metros/segundo.
Bons nomes de variáveis podem reduzir a necessidade de comentários, mas nomes longos
podem ser expressões complexas difíceis de ler, então há uma compensação.
2.12 Escolhendo nomes de variáveis mnemônicas
Contanto que você siga as regras simples de nomenclatura de variáveis e evite palavras, você
tem muitas opções quando nomeia suas variáveis. No início, esta escolha pode ser confusa
tanto quando você lê um programa quanto quando escreve seus próprios programas. Por
exemplo, os três programas a seguir são idênticos em termos do que eles realizam, mas muito
diferentes quando você os lê e tenta compreendê-los.
a = 35.0
b = 12.50
c=a*b
print(c)
horas = 35,0
taxa = 12,50
print(salario)
x1q3z9ahd = 35.0
x1q3z9afd = 12.50
O interpretador Python vê todos esses três programas como exatamente iguais, mas os
humanos veem e entendem esses programas de maneira bem diferente. Os humanos irão
entender rapidamente a intenção do segundo programa porque o programador faz nomes de
variáveis escolhidos que refletem sua intenção em relação a quais dados serão armazenados
em cada variável.
Embora tudo isso pareça ótimo, é uma boa ideia usar variáveis mnemônicas, nomes de
variáveis mnemônicas podem atrapalhar o aprendizado de um programador iniciante a
capacidade de analisar e entender o código. Isso ocorre porque os programadores iniciantes
não tem ainda uma memória para as palavras reservadas (são apenas 31 delas) e às vezes as
variáveis com nomes muito descritivos começam a parecer na linguagem e não apenas em
nomes de variáveis bem escolhidos.
Dê uma olhada rápida no código de exemplo Python a seguir, que percorre alguns dados.
Abordaremos os loops em breve, mas, por enquanto, tente apenas decifrar o que isso significa:
print(word)
O que esta acontecendo aqui? Quais dos tokens (for, word, in, etc.) são reservados palavras e
quais são apenas nomes de variáveis? O Python entende em um fundamento nível mental a
noção de palavras? Os programadores iniciantes têm problemas para separar quais partes do
código devem ser iguais a este exemplo e quais partes do código são simplesmente escolhas
feitas pelo programador.
print(slice)
É mais fácil para o programador iniciante olhar para este código e saber quais partes são
palavras reservadas definidas pelo Python e cujas partes são simplesmente nomes de variáveis
escolhido pelo programador. É bastante claro que o Python não tem fundamentos de
compreensão de pizza e fatias e o fato de que uma pizza consiste em um conjunto de uma ou
mais fatias.
Mas se nosso programa é realmente sobre ler dados e procurar palavras nos dados, pizza e
fatias são nomes de variáveis nada mnemônicos. Escolhendo-os como variável, desviariam a
atenção do significado do programa.
Após um curto período de tempo, você saberá as palavras reservadas mais comuns e você
começará a ver as palavras reservadas saltando para você:
As partes do código definidas pelo Python (for, in, print e :) estão em negrito e as variáveis
escolhidas pelo programador (palavra e palavras) não estão em negrito. Muitos os editores de
texto estão cientes da sintaxe do Python e colorirão as palavras reservadas de maneira
diferente para lhe dar pistas para manter suas variáveis e palavras reservadas separadas.
Depois de um tempo você começará a ler Python e determinará rapidamente o que é uma
variável e o que é uma palavra reservada.
2.13 Depuração
Neste ponto, o erro de sintaxe que você provavelmente cometerá é uma variável com nome
ilegal, como class e yield, que são palavras-chave, ou odd~job e US$, que são caracteres ilegais.
Se você colocar um espaço em um nome de variável, o Python pensa que são dois operandos
sem um operador:
>>> month = 09
month = 09
Para erros de sintaxe, as mensagens de erro não ajudam muito. As mensagens mais comuns
sábios são SyntaxError: invalid syntax e SyntaxError: invalid token, nenhum dos quais é muito
informativo. O erro de tempo de execução que você provavelmente cometerá é “use before
def;” isto é, tentando para usar uma variável antes de atribuir um valor. Isso pode acontecer se
você soletrar um nome da variável errado:
Os nomes das variáveis diferenciam maiúsculas de minúsculas, então LaTeX não é o mesmo
que latex.
Neste ponto, a causa mais provável de um erro semântico é a ordem das operações.
Por exemplo, para calcular 1/2π, você pode ser tentado a escrever
2.14 Glossário
Atribuição - Uma instrução que atribui um valor a uma variável.
Avaliar - Para simplificar uma expressão executando as operações para produzir um único
valor.
Palavra-chave - Uma palavra reservada que é usada pelo compilador para analisar um
programa; você não pode usar palavras-chave como if, def e while como nomes de variáveis.
Instrução - Uma seção de código que representa um comando ou ação. Até agora, a
declarações que vimos são atribuições a declaração de expressão de impressão.
Type - Uma categoria de valores. Os tipos que vimos até agora são inteiros (tipo int), números
de ponto flutuante (tipo float) e strings (tipo str).
Valor - Uma das unidades básicas de dados, como um número ou string, que um programa
manipula.
Olá deex
Exercício 3: Escreva um programa para solicitar ao usuário as horas e a taxa por hora para
Calcular o salário bruto.
Insira as horas: 35
Pagamento: 96,25
Não nos preocuparemos em garantir que nosso pagamento tenha exatamente dois dígitos
após o decimal por enquanto. Se quiser, você pode jogar com a função round integrada do
Python para arredondar corretamente o pagamento resultante para duas casas decimais.
Largura = 17
Altura = 12,0
Para cada uma das seguintes expressões, escreva o valor da expressão e o tipo (do valor da
expressão).
1. largura//2
2. largura/2,0
3. altura/3
4. 1 + 2 \* 5
Exercício 5: Escreva um programa que solicite ao usuário uma temperatura Celsius, converta a
temperatura em Fahrenheit e imprima a temperatura convertida.
Capítulo 3
Execução condicional
>>> 5 == 5
True
>>> 5 == 6
False
{}
True e False são valores especiais que pertencem à classe bool; eles não são cordas:
>>> type(True)
<class 'bool'>
>>> type(False)
<class 'bool'>
x != y # x não é igual a y
xéy # x é igual a y
x não é y # x não é o mesmo que y
Embora essas operações provavelmente sejam familiares para você, os símbolos do Python
são diferentes dos símbolos matemáticos para as mesmas operações. Um erro comum é usar
um único sinal de igual (=) em vez de um sinal de igual duplo (==). Lembrar que = é um
operador de atribuição e == é um operador de comparação. Não há algo como =< ou =>.
n%2 == 0 or n%3 == 0 é verdadeiro se qualquer uma das condições for verdadeira, ou seja, se o
número é divisível por 2 ou 3.
Finalmente, o operador not nega uma expressão booleana, então not (x > y) é verdadeiro se x
> y é falso; isto é, se x for menor ou igual a y.
Estritamente falando, os operandos dos operadores lógicos devem ser expressões booleanas.
Mas o Python não é muito rígido. Qualquer número diferente de zero é interpretado como
“true”.
True
Essa flexibilidade pode ser útil, mas há algumas sutilezas que podem ser confusas. Você pode
querer evitá-lo até ter certeza de saber o que está fazendo.
print('x é positivo')
Se a condição lógica for verdadeira, a instrução recuada será executada. Se a condição lógica
for falsa, a instrução recuada será ignorada.
As instruções if têm a mesma estrutura que as definições de função ou para loops. A instrução
consiste em uma linha de cabeçalho que termina com o caractere de dois pontos (:) seguido
por um bloco recuado. Declarações como esta são chamadas de declarações compostas,
porque eles se estendem por mais de uma linha.
Não há limite para o número de instruções que podem aparecer no corpo, mas deve haver
pelo menos um. Ocasionalmente, é útil ter um corpo sem declarações (geralmente como um
substituto para o código que você ainda não escreveu). Naquile caso, você pode usar a
instrução pass, que não faz nada.
if x < 0 :
Se você inserir uma instrução if no interpretador Python, o prompt mudará de três chevrons
para três pontos para indicar que você está no meio de um bloco de afirmações, conforme
abaixo:
>>> x = 3
... print('Small')
...
Small
>>>
3.4 Execução alternativa
Uma segunda forma da instrução if é a execução alternativa, na qual existem duas
possibilidades e a condição determina qual delas será executada. a sintaxe se parece com isso:
if x%2 == 0 :
print('x é par')
else :
Se o resto quando x é dividido por 2 for 0, então sabemos que x é par, e o programa exibe uma
mensagem para esse efeito. Se a condição for falsa, o segundo conjunto de declarações é
executado.
Como a condição deve ser verdadeira ou falsa, exatamente uma das alternativas será
executada. As alternativas são chamadas de ramos, porque são ramos em fluxo de execução.
if x < y:
elif x > y:
else:
elif é uma abreviação de “else if”. Novamente, exatamente uma ramificação será executada.
Não há limite para o número de instruções elif. Se houver uma cláusula else, ela tem que estar
no final, mas não tem que haver um.
if escolha == 'a':
print('Mal palpite')
print('Bom palpite')
if x == y:
else:
if x < y:
else:
Por exemplo, podemos reescrever o seguinte código usando uma única condicional:
if 0 <x:
if x < 10:
A instrução print é executada apenas se passarmos por ambas as condicionais, portanto, pode
obter o mesmo efeito com o operador and:
>>> int(velocidade)
No entanto, se você colocar esse código em um script Python e esse erro ocorrer, seu script
imediatamente para em suas trilhas com um traceback. Não executa a seguinte declaração.
Aqui está um exemplo de programa para converter uma temperatura Fahrenheit em uma
temperatura Celsius:
fahr = float(inp)
print(cel)
# Código: http://www.pythonlearn.com/code3/fahren.py
Se executarmos este código e fornecermos uma entrada inválida, ele simplesmente falhará
com um mensagem de erro:
python fahren.py
22.22222222222222
Existe uma estrutura de execução condicional incorporada ao Python para lidar com esses
tipos de erros esperados e inesperados denominados “try/except”. A ideia de tentar exceto
que você sabe que alguma sequência de instruções pode ter um problema e você deseja
adicionar algumas instruções a serem executadas se ocorrer um erro. Esses instruções extras
(o bloco exceto) são ignoradas se não houver erro.
Você pode pensar no recurso try and except em Python como uma “apólice de seguro” em
uma sequência de declarações.
try:
fahr = float(inp)
print(célula)
except:
print('Digite um numero')
# Código: http://www.pythonlearn.com/code3/fahren2.py
O Python começa executando a sequência de instruções no bloco try. Se tudo correr bem, ele
pula o bloco except e continua. Se ocorrer uma exceção no bloco try, o Python sai do bloco try
e executa a sequência de instruções no bloco except.
python fahren2.py
22.22222222222222
python fahren2.py
Tratar uma exceção com uma instrução try é chamado de captura de exceção. Neste exemplo,
a cláusula except imprime uma mensagem de erro. Em geral, pegar uma exceção lhe dá uma
chance de corrigir o problema, ou tentar novamente, ou pelo menos encerrar o programa
graciosamente.
Quando o Python detecta que não há nada a ganhar avaliando o resto de uma expressão
lógica, ele interrompe sua avaliação e não faz os cálculos no restante da expressão lógica.
Quando a avaliação de uma expressão lógica para porque o valor geral já é conhecido, é
chamado de curto-circuito da avaliação.
Embora isso possa parecer um ponto delicado, o comportamento do curto-circuito leva a uma
solução inteligente técnica chamada padrão guardião. Considere a seguinte sequência de
código no interpretador Python:
>>> x = 6
>>> y = 2
True
>>> x = 1
>>> y = 0
False
>>> x = 6
>>> y = 0
>>>
O terceiro cálculo falhou porque o Python estava avaliando (x/y) e y era zero, que causa um
erro de tempo de execução. Mas o segundo exemplo não falhou porque a primeira parte da
expressão x >= 2 avaliada como False, então o (x/y) nunca foi executado devido à regra de
curto-circuito e não houve erro. Podemos construir a expressão lógica para colocar
estrategicamente uma avaliação de guarda logo antes da avaliação que pode causar um erro
da seguinte forma:
>>> x = 1
>>> y = 0
False
>>> x = 6
>>> y = 0
False
>>>
Na primeira expressão lógica, x >= 2 é False, então a avaliação para no end. Na segunda
expressão lógica, x >= 2 é verdadeiro, mas y != 0 é falso, então nunca alcançara (x/y).
Na terceira expressão lógica, o y != 0 está após o cálculo (x/y), então a expressão falha com um
erro.
Na segunda expressão, dizemos que y != 0 atua como um guarda para garantir que só
executara (x/y) se y for diferente de zero.
3.9 Depuração
O traceback Python exibido quando ocorre um erro contém muitas informações, mas pode ser
esmagadora. As partes mais úteis são geralmente:
• Onde ocorreu.
Erros de sintaxe geralmente são fáceis de encontrar, mas existem algumas dicas. Erros de
Espaço em branco podem ser complicados porque espaços e tabulações são invisíveis e
estamos acostumados a ignora-los.
>>> x = 5
>>> y = 6
y=6
Neste exemplo, o problema é que a segunda linha é recuada por um espaço. Mas a mensagem
de erro aponta para y, o que é enganoso. Em geral, as mensagens de erro indica onde o
problema foi descoberto, mas o erro real pode ser anterior no código, às vezes em uma linha
anterior.
Em geral, as mensagens de erro informam onde o problema foi descoberto, mas são muitas
vezes onde não foi causado.
3.10 Glossário
Corpo - A sequência de instruções dentro de uma instrução composta.
Condicional encadeado - Uma instrução condicional com uma série de alternativas galhos.
Operador de comparação - Um dos operadores que compara seus operandos: ==, !=, >, <, >= e
<=.
Padrão guardião - Onde construímos uma expressão lógica com componentes adicionais
parisons para aproveitar o comportamento de curto-circuito.
Operador lógico - Um dos operadores que combina expressões booleanas: end, or, e not.
Condicional aninhada - Uma instrução condicional que aparece em uma das ramificações de
outra declaração condicional.
Traceback - Uma lista das funções que estão sendo executadas, impressa quando uma exceção
ocorre.
3.11 Exercícios
Exercício 1: Reescreva seu cálculo de pagamento para dar ao empregado 1,5 vezes a taxa
horária para horas trabalhadas acima de 40 horas.
Insira as horas: 45
Digite Taxa: 10
Pagamento: 475,0
Exercício 2: Reescreva seu programa de pagamento usando try e except para que seu
programa lide com entrada não numérica graciosamente, imprimindo uma mensagem e
saindo do programa. A seguir, duas execuções do programa:
Insira as horas: 20
>= 0,9 A
>= 0,8 B
>= 0,7 C
>= 0,6 D
< 0,6 F
~~~
Pontuação ruim
Pontuação ruim
Execute o programa repetidamente como mostrado acima para testar os vários valores
diferentes para a entrada.
Capítulo 4
Funções
>>> type(32)
<class 'int'>
É comum dizer que uma função “pega” um argumento e “devolve” um resultado. O resultado
é chamado de valor de retorno.
As funções max e min nos fornecem os maiores e menores valores em uma lista,
positivamente:
'w'
''
>>>
A função max nos diz o “maior caractere” na string (que acaba sendo ser a letra “w”) e a
função min nos mostra o menor caractere (que acaba por ser um espaço).
Outra função interna muito comum é a função len que nos diz quantos itens estão em seu
argumento. Se o argumento para len for uma string, ele retorna o número de caracteres na
string.
11
>>>
Essas funções não se limitam a olhar para strings. Eles podem operar em qualquer conjunto de
valores, como veremos nos próximos capítulos.
Você deve tratar os nomes das funções incorporadas como palavras reservadas (ou seja, evite
usar “max” como um nome de variável).
>>> int('32')
32
>>> int('Hello')
int pode converter valores de ponto flutuante em inteiros, mas não arredonda; isso corta fora
a parte da fração:
>>> int(3.99999)
>>> int(-2.3)
-2
32.0
>>> float('3.14159')
3.14159
>>> str(32)
'32'
>>> str(3.14159)
'3.14159'
Tornar um programa verdadeiramente não determinístico acaba não sendo tão fácil, mas há
maneiras de fazê-lo, pelo menos, parecer não determinístico. Uma delas é usar algoritmos que
geram números pseudoaleatórios. Números pseudoaleatórios não são verdadeiramente
aleatórios porque são gerados por uma computação determinística, mas apenas olhando para
os números, é praticamente impossível distingui-los do aleatório.
O módulo random fornece funções que geram números pseudo-aleatórios (que chamarei
simplesmente de “aleatório” daqui em diante).
A função random retorna um float aleatório entre 0,0 e 1,0 (incluindo 0,0 mas não 1.0). Cada
vez que você chama aleatório, obtém o próximo número em uma longa série.
import random
for i in range(10):
x = random.random()
print(x)
Este programa produz a seguinte lista de 10 números aleatórios entre 0,0 e 1.0, mas não
incluindo 1.0.
0.11132867921152356
0.5950949227890241
0.04820265884996877
0.841003109276478
0.997914947094958
0.04842330803368111
0.7416295948208405
0.510535245390327
0.27447040171978143
0.028511805472785867
Exercício 1: Execute o programa em seu sistema e veja quais números você obtém. Corra o
programa mais de uma vez e veja quais números você obtém.
A função aleatória é apenas uma das muitas funções que lidam com números aleatórios.
A função randint pega os parâmetros baixo e alto e retorna um número inteiro entre baixo e
alto (incluindo ambos).
Para escolher um elemento de uma sequência aleatoriamente, você pode usar choice:
>>> t = [1, 2, 3]
>>> random.choice(t)
>>> random.choice(t)
3
O módulo random também fornece funções para gerar valores aleatórios de con-
Essa instrução cria um objeto de módulo chamado math. Se você imprimir o módulo objeto,
você obtém algumas informações sobre ele:
>>> print(math)
O objeto do módulo contém as funções e variáveis definidas no módulo. Para acessar uma das
funções, você deve especificar o nome do módulo e o nome da função, separados por um
ponto (também conhecido como ponto). Este formato é chamado notação de ponto.
>>> graus = 45
>>> math.sin(radianos)
0,7071067811865476
A expressão math.pi obtém a variável pi do módulo math. O valor desta variável é uma
aproximação de π, com precisão de cerca de 15 dígitos.
Se você conhece sua trigonometria, pode verificar o resultado anterior comparando-o para a
raiz quadrada de dois dividido por dois:
0.7071067811865476
Uma vez que definimos uma função, podemos reutilizá-la várias vezes ao longo de nosso
programa.
def print_lyrics():
def é uma palavra-chave que indica que esta é uma definição de função. O nome da função é
print_lyrics. As regras para nomes de função são as mesmas que para nomes de variáveis:
letras, números e alguns sinais de pontuação são legais, mas o primeiro caractere não pode ser
um número. Você não pode usar uma palavra-chave como o nome de uma função, e você deve
evitar ter uma variável e uma função com o mesmo nome.
Os parênteses vazios após o nome indicam que esta função não leva nenhum argumento.
Posteriormente, construiremos funções que recebem argumentos como entrada.
Por convenção, o recuo é sempre de quatro espaços. O corpo pode conter qualquer número
de declarações.
As strings nas instruções de impressão são colocadas entre aspas. Aspas simples e duplas
fazem a mesma coisa; a maioria das pessoas usa aspas simples, exceto em casos como este
onde uma aspa simples (que também é um apóstrofo) aparece na string.
...
Para finalizar a função, você deve inserir uma linha vazia (isso não é necessário em um roteiro).
>>> print(print_lyrics)
>>> print(type(print_lyrics))
<class 'function'>
O valor de print_lyrics é um objeto de função, que tem o tipo “função”. A sintaxe para chamar
a nova função é a mesma das funções internas:
>>> print_lyrics()
Depois de definir uma função, você pode usá-la dentro de outra função. Por exemplo, para
repetir o refrão anterior, poderíamos escrever uma função chamada repeat_lyrics:
def repeat_lyrics():
print_lyrics()
print_lyrics()
E então chame repeat_lyrics:
>>> repeat_lyrics()
def print_lyrics():
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()
# Code: http://www.pythonlearn.com/code3/lyrics.py
Como você pode esperar, você precisa criar uma função antes de executá-la. Em outras
palavras, a definição da função deve ser executada antes da primeira vez que ela é chamada.
Exercício 2: Mova a última linha deste programa para cima, de modo que a chamada da função
apareca antes das definições. Execute o programa e veja qual mensagem de erro você acha.
Uma chamada de função é como um desvio no fluxo de execução. Em vez de ir para a próxima
instrução, o fluxo salta para o corpo da função, executa todas as instruções lá, e depois volta
para continuar de onde parou.
Isso parece bastante simples, até você se lembrar de que uma função pode chamar outra
enquanto estiver no meio de uma função.
Felizmente, o Python é bom em rastrear onde está, então cada vez que uma função terminar,
o programa continua de onde parou na função que o chamou. Quando chega ao final do
programa, ele termina.
Qual é a moral dessa história sórdida? Quando você lê um programa, nem sempre deseja ler
de cima para baixo. Às vezes faz mais sentido se você seguir o fluxo de execução.
Aqui está um exemplo de uma função definida pelo usuário que recebe um argumento:
def print_twice(bruce):
print(bruce)
print(bruce)
Esta função atribui o argumento a um parâmetro chamado bruce. Quando a função é
chamada, ela imprime o valor do parâmetro (seja ele qual for) duas vezes.
Esta função funciona com qualquer valor que possa ser impresso.
>>> print_twice('Spam')
Spam
Spam
>>> print_twice(17)
17
17
>>> print_twice(math.pi)
3.141592653589793
3.141592653589793
(print_twice)
>>> print_twice(math.cos(math.pi))
-1.0
-1.0
O argumento é avaliado antes da função ser chamada, então nos exemplos, as expressões
“Spam '*4andmath.cos(math.pi)' são avaliadas apenas uma vez.
>>> print_twice(michael)
O nome da variável que passamos como argumento (michael) não tem nada a ver com o nome
do parâmetro (bruce). Não importa o valor chamado de volta para casa (no chamador); aqui
em print_twice, chamamos todo mundo de bruce.
Quando você chama uma função frutífera, quase sempre quer fazer algo com o resultado; por
exemplo, você pode atribuí-lo a uma variável ou usá-lo como parte de uma expressão:
x = math.cos(radians)
golden = (math.sqrt(5) + 1) / 2
Quando você chama uma função no modo interativo, o Python exibe o resultado:
>>> math.sqrt(5)
2.23606797749979
Mas em um script, se você chamar uma função frutífera e não armazenar o resultado da
função em uma variável, o valor de retorno desaparece na névoa!
math.sqrt(5)
Este script calcula a raiz quadrada de 5, mas como não armazena o resultado em uma variável
ou exibir o resultado, não é muito útil.
As funções vazias podem exibir algo na tela ou ter algum outro efeito, mas eles não têm um
valor de retorno. Se você tentar atribuir o resultado a uma variável, você obtém um valor
especial chamado None.
Bing
Bing
>>> print(result)
None
O valor None não é o mesmo que a string “None”. É um valor especial que tem seu próprio
tipo:
>>> print(type(None))
<class 'NoneType'>
Para retornar um resultado de uma função, usamos a instrução return em nossa função. Por
exemplo, poderíamos criar uma função muito simples chamada addtwo que adiciona dois
números juntos e retorna um resultado.
added = a + b
return added
x = addtwo(3, 5)
print(x)
# Code: http://www.pythonlearn.com/code3/addtwo.py
Quando este script for executado, a instrução print imprimirá “8” porque a função addtwo foi
chamada com 3 e 5 como argumentos. Dentro da função, os parâmetros aeb foram 3 e 5,
respectivamente. A função calculou a soma de os dois números e os colocou na variável de
função local chamada Added. Então ele usou a instrução return para enviar o valor calculado
de volta ao código de chamada como o resultado da função, que foi atribuído à variável x e
impresso.
4.11 Por que funções?
Pode não estar claro por que vale a pena dividir um programa em funções. Mas, existem vários
motivos:
• As funções podem tornar um programa menor eliminando o código repetitivo. Mais tarde,
se você fizer uma alteração, basta fazê-la em um só lugar.
• Dividir um programa longo em funções permite depurar as partes uma a uma vez e, em
seguida, montá-los em um todo de trabalho.
• Funções bem projetadas geralmente são úteis para muitos programas. Uma vez que você
escreve e depura um, você pode reutilizá-lo.
4.12 Depuração
Se você estiver usando um editor de texto para escrever seus scripts, poderá ter problemas
com espaços e tabulações. A melhor forma de evitar esses problemas é utilizar os espaços
exclusivamente (sem abas). A maioria dos editores de texto que conhecem o Python fazem
isso por padrão, mas alguns não.
Tabs e espaços geralmente são invisíveis, o que os torna difíceis de depurar, então tente
encontrar um editor que gerencie o recuo para você.
Além disso, não se esqueça de salvar seu programa antes de executá-lo. Algum
desenvolvimento ambientes fazem isso automaticamente, mas alguns não. Nesse caso, o
programa que você está vendo no editor de texto não é o mesmo que o programa que você
está correndo.
A depuração pode demorar muito se você continuar executando o mesmo programa incorreto
de novo e de novo!
Certifique-se de que o código que você está vendo é o código que você está executando. Se
você não tem certeza, coloque algo como print("hello") no início do programa e execute-o
novamente. Se você não vê o hello, você não está executando o programa certo!
4.13 Glossário
Algoritmo - Um processo geral para resolver uma categoria de problemas.
Argumento - Um valor fornecido a uma função quando a função é chamada. Este valor é
atribuído ao parâmetro correspondente na função.
Composição - Usando uma expressão como parte de uma expressão maior, ou uma declaração
como parte de uma declaração maior.
Determinístico - Pertencente a um programa que faz a mesma coisa toda vez que é executado,
dadas as mesmas entradas.
Notação de ponto - A sintaxe para chamar uma função em outro módulo especificando o
nome do módulo seguido por um ponto (ponto) e o nome da função.
Função - Uma sequência nomeada de instruções que executa alguma operação útil. As funções
podem ou não receber argumentos e podem ou não produzir um resultado.
Chamada de função - Uma instrução que executa uma função. Consiste na função nome
seguido por uma lista de argumentos.
Definição de função - Uma instrução que cria uma nova função, especificando seu nome,
parâmetros e as instruções que ele executa.
Objeto de função - Um valor criado por uma definição de função. O nome da função é uma
variável que se refere a um objeto de função.
Objeto de módulo - Um valor criado por uma instrução de importação que fornece acesso aos
dados e o código definidos em um módulo.
Parâmetro - Um nome usado dentro de uma função para se referir ao valor passado como um
argumento.
Pseudoaleatório - Pertencente a uma sequência de números que parecem ser aleatórios, mas
são gerados por um programa determinístico.
Valor de retorno - O resultado de uma função. Se uma chamada de função for usada como
uma expressão, o valor de retorno é o valor da expressão.
c) Indica que a seguinte seção de código recuada deve ser armazenada para uso posterior
d) b e c são verdadeiras
def fred():
print("Zap")
def jane():
print("ABC")
jane()
fred()
jane()
Exercício 6: Reescreva seu cálculo de pagamento com tempo e meio para horas extras e crie
uma função chamada computepay que leva dois parâmetros (horas e taxa).
Insira as horas: 45
Digite Taxa: 10
Pagamento: 475,0
Exercício 7: Reescreva o programa de notas do capítulo anterior usando uma função chamada
computergrade que recebe uma pontuação como parâmetro e retorna uma nota como uma
corda.
Nota Pontuação
> 0,9 A
> 0,8 B
> 0,7 C
> 0,6 D
<= 0,6 F
Execução do Programa:
Pontuação ruim
Pontuação ruim
Execute o programa repetidamente para testar os vários valores diferentes para entrada.
Capítulo 5
Iteração
x=x+1
Isso significa “obter o valor atual de x, adicionar 1 e, em seguida, atualizar x com o novo valor."
Se você tentar atualizar uma variável que não existe, receberá um erro, porque o Python avalia
o lado direito antes de atribuir um valor a x:
>>> x = x + 1
Antes de atualizar uma variável, você deve inicializá-la, geralmente com uma simples
atribuição:
>>> x = 0
>>> x = x + 1
n=5
while n > 0:
print(n)
n=n-1
print('Blastoff!')
Você quase pode ler a instrução while como se fosse em inglês. Significa: “Enquanto n for
maior que 0, exiba o valor de n e reduza o valor de n em 1. Quando chegar a 0, saia da
instrução while e exiba a palavra Blastoff!”
Esse tipo de fluxo é chamado de loop porque a terceira etapa retorna a principal. Cada vez que
executamos o corpo do loop, chamamos de iteração. Para o loop acima, diríamos: “Ele teve
cinco iterações”, o que significa que o corpo do loop foi executado cinco vezes.
O corpo do loop deve alterar o valor de uma ou mais variáveis para que eventualmente, a
condição se torne falsa e o loop termina. Chamamos a variável capaz de mudar cada vez que o
loop é executado e controla quando o loop termina de variável de iteração. Se não houver
variável de iteração, o loop será repetido indefinidamente, resultando em um loop infinito.
No caso da contagem regressiva, podemos provar que o loop termina porque sabemos que o
valor de n é finito, e podemos ver que o valor de n fica menor a cada tempo através do loop,
então, eventualmente, temos que chegar a 0. Outras vezes, um loop é obviamente infinito
porque não tem nenhuma variável de iteração.
5.4 “Loops infinitos” e break
Às vezes, você não sabe que é hora de terminar um loop até chegar na metade do corpo.
Nesse caso, você pode escrever um loop infinito de propósito e usar o break para sair do loop.
Este loop é obviamente um loop infinito porque a expressão lógica na declaração while é
simplesmente a constante lógica True:
n = 10
while True:
n=n-1
print('Done!')
Se você cometer o erro e executar este código, aprenderá rapidamente como parar um
processo Python descontrolado em seu sistema ou, descubra onde está o botão de desligar do
seu computador. Este programa será executado para sempre ou até que a bateria acabe
porque a expressão lógica no topo do loop é sempre verdadeira em virtude do fato de que a
expressão é o valor constante True.
Embora este seja um loop infinito disfuncional, ainda podemos usar esse padrão para construir
loops úteis, desde que adicionemos cuidadosamente o código ao corpo do loop para
explicitamente saia do loop usando break quando atingirmos a condição de saída.
Por exemplo, supunhetamos que você queira obter informações do usuário até que ele digite
concluído.
while True:
if line == 'done':
break
print(line)
print('Done!')
# Code: http://www.pythonlearn.com/code3/copytildone1.py
A condição do loop é True, que é sempre verdadeira, então o loop é executado repetidamente
até atingir a instrução break.
Cada vez, ele solicita ao usuário um colchete angular. Se o usuário digitar feito, a instrução
break sai do loop. Caso contrário, o programa ecoa qualquer coisa, o usuário digita e volta para
o início do loop. Aqui está um exemplo de execução:
hello there
> finished
finished
> done
Done!
Essa maneira de escrever loops while é comum porque você pode verificar a condição em
qualquer lugar do loop (não apenas no topo) e você pode expressar a condição de parada
afirmativamente (“pare quando isso acontecer”) em vez de negativamente (“continue até isso
acontece.").
Aqui está um exemplo de um loop que copia sua entrada até que o usuário digite “done”, mas
trata as linhas que começam com o caractere hash como linhas que não devem ser impressas
(tipo como comentários do Python).
while True:
if line[0] == '#':
continue
if line == 'done':
break
print(line)
print('Done!')
# Code: http://www.pythonlearn.com/code3/copytildone2.py
Aqui está um exemplo de execução deste novo programa com continue adicionado.
hello there
print this!
> done
Done!
Todas as linhas são impressas, exceto aquela que começa com o sinal de jogo da velha, porque
quando o continue é executado, ele termina a iteração atual e volta para a instrução while
para iniciar a próxima iteração, ignorando assim a instrução print.
A sintaxe de um loop for é semelhante ao loop while em que há um for declaração e um corpo
de loop:
print('Done!')
Em termos de Python, a variável friends é uma lista1 de três strings e o loop for percorre a lista
e executa o corpo uma vez para cada uma das três strings, a lista resultando nesta saída:
Happy New Year: Joseph
Done!
Traduzir este loop for para o inglês não é tão direto quanto o loop while, mas se você pensar
em amigos como um conjunto, é assim: “Execute as instruções no corpo do for loop uma vez
para cada amigo no conjunto chamado friends.”
Observando o loop for, for e in são palavras-chave reservadas do Python e amigo e amigos são
variáveis.
Em particular, friend é a variável de iteração para o loop for. O amigo variável muda para cada
iteração do loop e controla quando o loop for é concluído. A variável de iteração percorre
sucessivamente as três strings armazenadas na variável amigos.
count = count + 1
Definimos a variável count como zero antes do início do loop e, em seguida, escrevemos um
loop for para percorrer a lista de números. Nossa variável de iteração é denominada itervar e
embora não usemos itervar no loop, ele controla o loop e causa o corpo do loop a ser
executado uma vez para cada um dos valores na lista. No corpo do loop, adicionamos 1 ao
valor atual de contagem para cada um dos valores na lista. Enquanto o loop está sendo
executado, o valor de count é o número de valores que vimos “até agora”.
Após a conclusão do loop, o valor de count é o número total de itens. O número total “cai no
nosso colo” no final do loop. Nós construímos o loop assim que temos o que queremos quando
o loop terminar.
total = 0
À medida que o loop é executado, total acumula a soma dos elementos; uma variável usada
desta forma é às vezes chamada de acumulador. Nem o loop de contagem nem o loop de
soma são particularmente úteis na prática, porque existem funções internas len() e sum() que
calculam o número de itens em uma lista e o total dos itens na lista, respectivamente.
print('Before:', largest)
largest = itervar
print('Largest:', largest)
Before: None
Loop: 3 3
Loop: 41 41
Loop: 12 41
Loop: 9 41
Loop: 74 74
Loop: 15 74
Largest: 74
A variável maior é melhor pensada como o “maior valor que vimos até agora”. Antes do loop,
definimos o maior como a constante None. None é uma constante especial que podemos
armazenar em uma variável para marcar a variável como "vazia". Antes do início do loop, o
maior valor que vimos até agora é None, pois ainda não vimos nenhum valor. Enquanto o loop
está em execução, se o maior for None, então pegue o primeiro valor que vemos como o
maior até agora. Você pode ver na primeira iteração quando o valor de itervar é 3, já que o
maior é None, definimos imediatamente o maior ser 3.
Após a primeira iteração, o maior não é mais Nenhum, então a segunda parte da expressão
lógica composta que verifica itervar > maior dispara somente quando vemos um valor maior
que o “maior até agora”. Quando vemos um novo “mesmo maior” valor, tomamos esse novo
valor para o maior. Você pode ver no programa a maior produção progride de 3 para 41 para
74.
No final do loop, verificamos todos os valores e a variável maior agora contém o maior valor na
lista.
Para calcular o menor número, o código é muito semelhante com uma pequena alteração:
smallest = None
print('Before:', smallest)
smallest = itervar
print('Smallest:', smallest)
Novamente, menor é o “menor até agora” antes, durante e depois da execução do loop.
Quando o loop for concluído, o menor contém o valor mínimo na lista.
Novamente, como na contagem e na soma, as funções internas max() e min() fazem escrever
esses loops exatos é desnecessário.
def min(values):
smallest = None
smallest = value
return smallest
Na versão de função do menor código, removemos todas as instruções de impressão para ser
equivalente à função min que já está incorporada ao Python.
5.8 Depuração
Ao começar a escrever programas maiores, você pode passar mais tempo de depuração. Mais
código significa mais chances de cometer um erro e mais lugares para erros se esconderem.
Uma maneira de reduzir o tempo de depuração é “depurar por bisseção”. Por exemplo, se
existem 100 linhas em seu programa e você as verifica uma de cada vez, seria como dar 100
passos.
Em vez disso, tente dividir o problema pela metade. Olhe para o meio do programa, ou perto
dele, para um valor intermediário que você pode verificar. Adicione uma instrução de
impressão (ou outra coisa que tenha um efeito verificável) e execute o programa. Se a
verificação do ponto médio estiver incorreta, o problema deve estar na primeira metade do
programa. Se estiver correto, o problema está no segundo tempo.
Cada vez que você executa uma verificação como esta, você reduz pela metade o número de
linhas que precisa procurar. Depois de seis passos (que é muito menos do que 100), você
estaria reduzido a uma ou duas linhas de código, pelo menos em teoria.
Na prática nem sempre fica claro qual é o “meio do programa” e nem sempre possível verificá-
lo. Não faz sentido contar linhas e encontrar o exato ponto médio. Em vez disso, pense em
lugares no programa onde pode haver erros e lugares onde é fácil colocar um cheque. Em
seguida, escolha um local onde você acha as chances são quase as mesmas de que o bug esteja
antes ou depois da verificação.
5.9 Glossário
Acumulador - Uma variável usada em um loop para somar ou acumular um resultado.
Contador - Uma variável usada em um loop para contar o número de vezes que algo
aconteceu. Inicializamos um contador em zero e então incrementamos o contador a cada vez
que queremos “contar” algo.
Inicializar - Uma atribuição que dá um valor inicial a uma variável que será atualizada.
Incremento - Uma atualização que aumenta o valor de uma variável (geralmente em um).
Loop infinito - Um loop no qual a condição final nunca é satisfeita ou para qual não há
condição de terminação.
Iteração - Execução repetida de um conjunto de instruções usando uma função que chama a si
mesmo ou a um loop.
5.10 Exercícios
Exercício 1: Escreva um programa que leia números repetidamente até que o usuário digite
"feito". Depois de inserir "done", imprima o total, a contagem e a média dos números. Se o
usuário inserir algo diferente de um número, detecte o erro usando try e except e imprima
uma mensagem de erro e pule para o próximo número.
Digite um número: 4
Digite um número: 5
Entrada inválida
Digite um número: 7
16 3 5.333333333333333
Exercício 2: Escreva outro programa que solicite uma lista de números como acima e no final
imprime o máximo e o mínimo dos números da média.
Capítulo 6
String
6.1 Uma string é uma sequência
Uma string é uma sequência de caracteres. Você pode acessar os personagens um de cada vez
com o operador colchete:
A expressão entre colchetes é chamada de índice. O índice indica qual caractere na sequência
que você quiser (daí o nome).
>>> print(letter)
Para a maioria das pessoas, a primeira letra de “banana” é b, não a. Mas em Python, o índice é
um deslocamento do início da string e a localização da primeira letra é zero.
>>> print(letter)
Você pode usar qualquer expressão, incluindo variáveis e operadores, como um índice, mas o
valor do índice deve ser um número inteiro. Caso contrário, você obtém:
[0]
[1]
[2]
[3]
[4]
[5]
>>> len(fruit)
Para obter a última letra de uma string, você pode tentar algo assim:
A razão para o IndexError é que não há nenhuma letra em 'banana' com o índice 6. Como
começamos a contar do zero, as seis letras são numeradas de 0 a 5. Para obter o último
caractere, você deve subtrair 1 do comprimento:
>>> last = fruit[length-1]
>>> print(last)
Como alternativa, você pode usar índices negativos, que contam para trás a partir do final da
corda. A expressão fruit[-1] retorna a última letra, fruit[-2] retorna a penúltima, e assim por
diante.
index = 0
letter = fruit[index]
print(letter)
index = index + 1
Este loop percorre a string e exibe cada letra em uma linha por si só. A condição do loop é
index \< len(fruit), portanto, quando o índice é igual ao comprimento da string, a condição é
falsa e o corpo do loop não é executado. O último caractere acessado é aquele com o índice
len(fruit)-1, que é o último caractere na string.
Exercício 1: Escreva um loop while que comece no último caractere da string e faça seu
caminho de volta para o primeiro caractere da string, imprimindo cada letra em uma linha
separada, exceto para trás.
print(char)
Cada vez que passa pelo loop, o próximo caractere na string é atribuído a variável char. O loop
continua até que nenhum caractere seja deixado.
6.4 Fatias de cordas
Um segmento de uma string é chamado de fatia. Selecionar uma fatia é semelhante a
selecionar uma personagem:
>>> print(s[0:5])
Monty
>>> print(s[6:12])
Python
O operador retorna a parte da string do caractere “n-eth” para o caractere “m-eth”, incluindo
o primeiro, mas excluindo o último.
Se você omitir o primeiro índice (antes dos dois pontos), a fatia começa no início da corda. Se
você omitir o segundo índice, a fatia vai para o final da string:
>>> fruit[:3]
'ban'
>>> fruit[3:]
'ana'
Se o primeiro índice for maior ou igual ao segundo, o resultado é uma string vazia,
representada por duas aspas:
>>> fruit[3:3]
''
Uma string vazia não contém caracteres e tem comprimento 0, mas fora isso, é igual a
qualquer outra string.
O “objeto” neste caso é a string e o “item” é o caractere que você tentou atribuir. Por
enquanto, um objeto é o mesmo que um valor, mas vamos refinar isso mais tarde. Um item é
um dos valores em uma sequência.
O motivo do erro é que as strings são imutáveis, o que significa que você não pode alterar uma
string existente. O melhor que você pode fazer é criar uma nova string que seja uma variação
da original:
>>> print(new_greeting)
Jello, world!
Este exemplo concatena uma nova primeira letra em uma fatia de saudação. não tem efeito na
string original.
word = 'banana'
count = 0
if letter == 'a':
count = count + 1
print(count)
Este programa demonstra outro padrão de computação chamado contador. A variável count é
inicializada em 0 e então incrementada cada vez que um a é encontrado. Quando o loop
termina, count contém o resultado: o número total de a’s.
Exercício 3:
Encapsule esse código em uma função chamada count e generalize-o para que aceita a string e
a letra como argumentos.
6.7 O operador in
A palavra in é um operador booleano que recebe duas strings e retorna True se o primeiro
aparece como uma substring no segundo:
True
False
if word == 'banana':
Outras operações de comparação são úteis para colocar palavras em ordem alfabética:
else:
Uma maneira comum de resolver esse problema é converter strings em um formato padrão,
como tudo em minúsculas, antes de realizar a comparação. Lembre-se disso caso você tenha
que se defender contra um homem armado com um abacaxi.
Python tem uma função chamada dir que lista os métodos disponíveis para um objeto. A
função type mostra o tipo de um objeto e a função dir mostra os métodos disponíveis.
>>> type(stuff)
<class 'str'>
>>> dir(stuff)
>>> help(str.capitalize)
Help on method_descriptor:
capitalize(...)
>>>
Embora a função dir liste os métodos, você pode usar ajuda para obter algumas
documentações sobre um método, uma melhor fonte de documentação para métodos de
string seria https://docs.python.org/3.5/library/stdtypes.html#string-methods.
Por exemplo, o método upper pega uma string e retorna uma nova string com todas as letras
maiúsculas:
>>> print(new_word)
BANANA
Esta forma de notação de ponto especifica o nome do método, upper, e o nome da string para
aplicar o método, palavra. Os parênteses vazios indicam que este método não aceita nenhum
argumento.
Uma chamada de método é chamada de invocação; neste caso, diríamos que estamos
invocando superior na palavra.
Por exemplo, existe um método de string chamado find que procura a posição de uma string
dentro de outra:
>>> print(index)
Neste exemplo, invocamos find sobre word e passamos a letra que estamos procurando como
um parâmetro.
O método find pode encontrar substrings, bem como caracteres:
>>> word.find('na')
Ele pode receber como segundo argumento o índice onde deve começar:
>>> word.find('na', 3)
Uma tarefa comum é remover espaços em branco (espaços, tabulações ou novas linhas) do
início e fim de uma string usando o método strip:
>>> line.strip()
'Here we go'
>>> line.startswith('Have')
True
>>> line.startswith('h')
False
Você notará que começa com maiúsculas, e minúsculas para corresponder, então às vezes
pegamos uma linha e mapeamos tudo para letras minúsculas antes de fazer qualquer
verificação usando o método lower.
>>> line.startswith('h')
False
>>> line.lower()
>>> line.lower().startswith('h')
True
No último exemplo, o método lower é chamado e então usamos startswith para ver se a string
minúscula resultante começa com a letra “h”. Enquanto estivermos cuidado com a ordem,
podemos fazer várias chamadas de métodos em uma única expressão.
E queríamos extrair apenas a segunda metade do endereço (ou seja, uct.ac.za) de cada linha,
podemos fazer isso usando o método find e o corte de strings.
>>> print(atpos)
21
>>> print(sppos)
31
>>> print(host)
uct.ac.za
>>>
Usamos uma versão do método find que nos permite especificar uma posição em a string onde
queremos encontrar para começar a procurar. Ao fatiar, extraímos o caracteres de “um além
do arroba, mas não incluindo o espaço personagem".
https://docs.python.org/3.5/library/stdtypes.html#string-methods.
O primeiro operando é a string de formato, que contém uma ou mais sequências de formato
que especificam como o segundo operando é formatado. O resultado é uma string.
Por exemplo, a sequência de formato “%d” significa que o segundo operando deve ser
formatado como um número inteiro (d significa “decimal”):
>>> camels = 42
'42'
O resultado é a string “42”, que não deve ser confundida com o valor inteiro 42.
Uma sequência de formato pode aparecer em qualquer lugar na string, para que você possa
incorporar um valor em uma frase:
>>> camels = 42
Se houver mais de uma sequência de formato na string, o segundo argumento terá que ser
uma tupla. Cada sequência de formato é casada com um elemento da tupla, em ordem.
O exemplo a seguir usa “%d” para formatar um inteiro, “%g” para formatar um flutuante
número do ponto (não pergunte por quê) e “%s” para formatar uma string:
>>> 'In %d years I have spotted %g %s.' % (3, 0.1, 'camels')
O operador de formato é poderoso, mas pode ser difícil de usar. você pode ler mais sobre isso
em https://docs.python.org/3.5/library/stdtypes.html#printf-style-string-formatting.
6.12 Depuração
Uma habilidade que você deve cultivar ao programar é sempre se perguntar: “O que poderia
dar errado aqui?” ou, alternativamente, “Que loucura nosso usuário pode fazer para travar
nosso programa (aparentemente) perfeito?”
Por exemplo, veja o programa que usamos para demonstrar o loop while no capítulo sobre
iteração:
while True:
if line[0] == '#':
continue
if line == 'done':
break
print(line)
print('Done!')
# Code: http://www.pythonlearn.com/code3/copytildone2.py
Veja o que acontece quando o usuário insere uma linha de entrada vazia:
hello there
print this!
>
if line[0] == '#':
O código funciona bem até que seja apresentada uma linha vazia. Então não há zero-th
personagem, então obtemos um traceback. Existem duas soluções para isso tornar a linha três
“segura” mesmo que a linha esteja vazia.
Uma possibilidade é simplesmente usar o método startswith que retorna False se a string está
vazia.
if line.startswith('#'):
Outra maneira é escrever com segurança a instrução if usando o padrão guardião e certifique-
se de que a segunda expressão lógica seja avaliada apenas onde houver pelo menos um
caractere na string.:
6.13 Glossário
Contador - Uma variável usada para contar algo, geralmente inicializada em zero e depois
incrementada.
Operador de formato - Um operador, %, que recebe uma string de formato e uma tupla e
gera/apaga uma string que inclui os elementos da tupla formatados conforme especificado
pela string de formato.
Sequência de formato - Uma sequência de caracteres em uma string de formato, como %d,
que especifica como um valor deve ser formatado.
String de formato - Uma string, usada com o operador de formato, que contém sequências.
Sinalizador - Uma variável booleana usada para indicar se uma condição é verdadeira ou falsa.
Imutável - A propriedade de uma sequência cujos itens não podem ser atribuídos.
Índice - Um valor inteiro usado para selecionar um item em uma sequência, como um
caractere em uma corda.
Objeto - Algo a que uma variável pode se referir. Por enquanto, você pode usar “objeto” e
“valor” de forma intercambiável.
Pesquisa - Um padrão de passagem que para quando encontra o que está procurando.
Percorrer - Para percorrer os itens em uma sequência, executando uma operação semelhante
em cada um.
6.14 Exercícios
Exercício 5: Pegue o seguinte código Python que armazena uma string:
‘str = ’X-DSPAM-Confidence:0.8475’
Use localizar e segmentar strings para extrair a parte da string após os dois pontos caractere e,
em seguida, use a função float para converter a string extraída em um número de ponto
flutuante.
A documentação usa uma sintaxe que pode ser confusa. Por exemplo, em find(sub[, start[,
end]]), os colchetes indicam argumentos opcionais. é obrigatório, mas o início é opcional
hahaha e, se você incluir o início, o fim será opcional.
Capítulo 7
Arquivos
7.1 Persistência
Até agora, aprendemos como escrever programas e comunicar nossas intenções para a
Unidade Central de Processamento usando execução condicional, funções e iterações.
Aprendemos como criar e usar estruturas de dados na Memória Principal. A CPU e a memória
são onde nosso software funciona e é executado. É onde todos os “pensamentos” acontecem.
Mas se você se lembra de nossas discussões sobre arquitetura de hardware, uma vez que a
energia é desligada, qualquer coisa armazenada na CPU ou na memória principal é apagada.
Então até agora, nossos programas são apenas exercícios divertidos e transitórios para
aprender Python.
Neste capítulo, começamos a trabalhar com Memória Secundária (ou arquivos). A memória
Secundária não é apagada quando a energia é desligada. Ou no caso de um flash USB drive, os
dados que escrevemos de nossos programas podem ser removidos do sistema e transportados
para outro sistema.
>>> print(fhand)
Se o arquivo não existir, a abertura falhará com um traceback e você não obterá um handle
para acessar o conteúdo do arquivo:
Mais tarde, usaremos try e except para lidar com mais elegância com a situação em que
tentamos abrir um arquivo que não existe.
Return-Path: <postmaster@collab.sakaiproject.org>
To: source@collab.sakaiproject.org
From: stephen.marquard@uct.ac.za
Details: http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772
...
www.pythonlearn.com/code3/mbox.txt
www.pythonlearn.com/code3/mbox-short.txt
Esses arquivos estão em um formato padrão para um arquivo que contém várias mensagens
de correio. As linhas que começam com “From” separam as mensagens, e as linhas que
começam com “De:” fazem parte das mensagens. Para mais informações sobre o formato
mbox, consulte en.wikipedia.org/wiki/Mbox.
Para quebrar o arquivo em linhas, existe um caractere especial que representa o “fim da linha”
chamada de caractere de nova linha.
Em Python, representamos o caractere de nova linha como uma barra invertida em constantes
de string. Mesmo que pareçam dois caracteres, na verdade é um único caractere. Quando
olhamos para a variável inserindo “stuff” no interpretador, ele nos mostra o \n na string, mas
quando usamos print para mostrar a string, vemos a string quebrada em duas linhas pelo
caractere de nova linha.
>>> stuff
'Hello\nWorld!'
>>> print(stuff)
Hello
World!
>>> print(stuff)
>>> len(stuff)
Você também pode ver que o comprimento da string X\nY é de três caracteres porque o
caractere de nova linha é um único caractere.
Então, quando olhamos para as linhas de um arquivo, precisamos imaginar que existe um
caractere invisível chamado de nova linha no final de cada linha que marca o fim da linha.
count = 0
count = count + 1
# Code: http://www.pythonlearn.com/code3/open.py
Podemos usar o identificador de arquivo como a sequência em nosso loop for. Nosso loop for
simplesmente conta o número de linhas no arquivo e as imprime. A tradução aproximada do
loop for para o inglês é, “para cada linha no arquivo representado pelo arquivo identificador,
adicione um à variável de contagem.”
A razão pela qual a função open não lê o arquivo inteiro é que o arquivo pode ser bastante
grande com muitos gigabytes de dados. A declaração aberta leva a mesma quantidade de
tempo, independentemente do tamanho do arquivo. O loop for realmente causa os dados a
serem lidos do arquivo.
Quando o arquivo é lido usando um loop for dessa maneira, o Python cuida da divisão dos
dados no arquivo em linhas separadas usando o caractere de nova linha. Python lê cada linha
através da nova linha e inclui a nova linha como o último caractere na variável de linha para
cada iteração do loop for.
Como o loop for lê os dados uma linha por vez, ele pode ler e contar as linhas em arquivos
muito grandes sem esgotar a memória principal para armazenar os dados. O programa acima
pode contar as linhas em qualquer tamanho de arquivo usando muito pouca memória, pois
cada linha é lida, contada e descartada.
Se você sabe que o arquivo é relativamente pequeno comparado ao tamanho de sua memória
principal, você pode ler o arquivo inteiro em uma string usando o método read no
identificador de arquivo.
>>> print(len(inp))
94626
>>> print(inp[:20])
From stephen.marquar
Neste exemplo, todo o conteúdo (todos os 94.626 caracteres) do arquivo mbox-short.txt são
lidos diretamente na variável inp. Usamos string slic-ing para imprimir os primeiros 20
caracteres dos dados de string armazenados em inp.
Quando o arquivo é lido dessa maneira, todos os caracteres, incluindo todas as linhas e
caracteres de nova linha são uma grande string na variável inp. Lembre-se que isso forma da
função aberta, só deve ser usada se os dados do arquivo couberem confortavelmente na
memória principal do seu computador.
Se o arquivo for muito grande para caber na memória principal, você deve escrever seu
programa para ler o arquivo em partes usando um loop for ou while.
Por exemplo, se quisermos ler um arquivo e imprimir apenas as linhas que começam com o
prefixo “From:”, poderíamos usar o método string startswith para selecionar apenas aquelas
linhas com o prefixo desejado:
fhand = open('mbox-short.txt')
count = 0
if line.startswith('From:'):
print(line)
# Code: http://www.pythonlearn.com/code3/search1.py
From: stephen.marquard@uct.ac.za
From: louis@media.berkeley.edu
From: zqian@umich.edu
From: rjlowe@iupui.edu
...
A saída parece ótima, pois as únicas linhas que vemos são aquelas que começam com “De:”,
mas por que estamos vendo as linhas extras em branco? Isso se deve a esse invisível caractere
de nova linha. Cada uma das linhas termina com uma nova linha, então a instrução print
imprime a string na linha variável que inclui uma nova linha e depois imprime adiciona outra
nova linha, resultando no efeito de espaçamento duplo que vemos.
Poderíamos usar o corte de linha para imprimir todos, exceto o último caractere, mas uma
abordagem mais simples é usar o método rstrip que remove os espaços em branco do lado
direito de uma string do seguinte modo:
fhand = open('mbox-short.txt')
line = line.rstrip()
if line.startswith('From:'):
print(line)
# Code: http://www.pythonlearn.com/code3/search2.py
From: stephen.marquard@uct.ac.za
From: louis@media.berkeley.edu
From: zqian@umich.edu
From: rjlowe@iupui.edu
From: zqian@umich.edu
From: rjlowe@iupui.edu
From: cwen@iupui.edu
...
À medida que seus programas de processamento de arquivos ficam mais complicados, você
pode querer estruturar seus loops de pesquisa usando continue. A ideia básica do loop de
pesquisa é que você está procurando linhas “interessantes” e efetivamente pulando linhas
“desinteressantes”. E então, quando encontramos uma linha interessante, fazemos algo com
essa linha.
Podemos estruturar o loop para seguir o padrão de pular linhas desinteressantes como segue:
fhand = open('mbox-short.txt')
line = line.rstrip()
# Pular 'linhas desinteressantes'
if not line.startswith('From:'):
continue
print(line)
# Code: http://www.pythonlearn.com/code3/search3.py
A saída do programa é a mesma. Em inglês, as linhas desinteressantes são aquelas que não
começam com “From:”, que pulamos usando continue. Para as linhas “interessantes” (ou seja,
aquelas que começam com “De:”) realizamos o processamento nessas linhas.
Podemos usar o método find string para simular uma pesquisa de editor de texto que encontra
linhas onde a string de pesquisa está em qualquer lugar da linha. Como find procura por uma
ocorrência de uma string dentro de outra string e retorna a posição da string ou -1 se a string
não foi encontrada, podemos escrever o seguinte loop para mostrar as linhas que contêm a
string “@uct.ac.za” (ou seja, eles vêm da Universidade da Cidade do Cabo na África do Sul):
fhand = open('mbox-short.txt')
line = line.rstrip()
print(line)
# Code: http://www.pythonlearn.com/code3/search4.py
From: stephen.marquard@uct.ac.za
Author: stephen.marquard@uct.ac.za
From: david.horwitz@uct.ac.za
Author: david.horwitz@uct.ac.za
...
Isso é bastante simples de fazer lendo o nome do arquivo do usuário usando raw_input do
seguinte modo:
fhand = open(fname)
count = 0
if line.startswith('Subject:'):
count = count + 1
# Code: http://www.pythonlearn.com/code3/search6.py
Lemos o nome do arquivo do usuário e o colocamos em uma variável chamada fname e abra
esse arquivo. Agora podemos executar o programa repetidamente em arquivos diferentes.
python search6.py
python search6.py
Antes de dar uma olhada na próxima seção, dê uma olhada no programa acima e pergunte a
você mesmo: "O que poderia dar errado aqui?" ou “O que nosso usuário amigável faria que
nosso pequeno e agradável programa fosse encerrado de forma deselegante com um
traceback, fazendo-nos parecer não tão legais aos olhos de nossos usuários?”
7.7 Usando try, except e open
Eu disse para você não espiar. Esta é a sua última chance.
python search6.py
fhand = open(fname)
python search6.py
fhand = open(fname)
Não ria. Os usuários eventualmente farão tudo o que puderem para quebrar seus programas,
seja de propósito ou com intenção maliciosa. De fato, uma parte importante de qualquer
equipe de desenvolvimento de software é uma pessoa ou grupo chamado Garantia de
qualidade (ou QA para abreviar), cujo trabalho é fazer as coisas mais loucas possível em uma
tentativa de quebrar o software que o programador criou. Ou pode ser SOMENTE UM
HACKER!!
A equipe de QA é responsável por encontrar as falhas nos programas antes que tenhamos
entregado o programa aos usuários finais que podem estar comprando o software ou pagando
para escrever o software. Portanto, a equipe de controle de qualidade é a melhor equipe do
programador amigo.
Então, agora que vemos a falha no programa, podemos corrigi-la elegantemente usando a
estrutura try/except. Precisamos assumir que a chamada aberta pode falhar e adicionar código
de recuperação quando a abertura falha da seguinte forma:
fname = input('Enter the file name: ')
try:
fhand = open(fname)
except:
exit()
count = 0
if line.startswith('Subject:'):
count = count + 1
# Code: http://www.pythonlearn.com/code3/search7.py
A função exit encerra o programa. É uma função que chamamos que nunca retorna. Agora,
quando nosso usuário (ou equipe de QA) digita tolices ou nomes de arquivos ruins, nós
“pegue-os” e recupere-se graciosamente:
python search7.py
python search7.py
Depois de se tornar mais habilidoso em Python, você pode se engajar em diálogos com outros
Programadores Python para decidir qual das duas soluções equivalentes para um problema é
“mais pitônico”. O objetivo de ser “mais pitônico” captura a noção de que programação é
parte engenharia e parte arte. Nem sempre estamos interessados em apenas fazendo algo
funcionar, também queremos que nossa solução sejam elegantes e seja apreciado como
elegante por nossos pares.
>>> print(fout)
Se o arquivo já existir, abri-lo no modo de gravação limpa os dados antigos e inicia fresco, por
isso tome cuidado! Se o arquivo não existir, um novo será criado.
>>> fout.write(line1)
24
Novamente, o objeto de arquivo rastreia onde está, portanto, se você chamar write
novamente, ele adicionará os novos dados até o final.
>>> fout.write(line2)
24
Quando terminar de escrever, você deve fechar o arquivo para garantir que o último bit de
dados é gravado fisicamente no disco para que não seja perdido se a energia acabar
desligando.
>>> fout.close()
Poderíamos fechar os arquivos que abrimos para leitura também, mas podemos ser um pouco
desleixados se estivermos abrindo apenas alguns arquivos, pois o Python garante que todos os
arquivos abertos sejam fechados quando o programa termina. Quando estamos escrevendo
arquivos, queremos explicitamente fechar os arquivos para não deixar nada ao acaso.
7.9 Depuração
Ao ler e gravar arquivos, você pode ter problemas com brancos. Ritmo. Esses erros podem ser
difíceis de depurar porque espaços, tabulações e novas linhas são normalmente invisível:
>>> print(s)
123
A função incorporada repr pode ajudar. Toma qualquer objeto como argumento e Retorna
uma representação de string do objeto. Para strings, representa espaço em branco com
sequências de barra invertida:
>>> print(repr(s))
Outro problema que você pode encontrar é que sistemas diferentes usam caracteres
diferentes. Caracteres para indicar o fim de uma linha. Alguns sistemas usam uma nova linha,
representada por \n. Outros usam um caractere de retorno, representado por \r. Alguns usam
os dois. Se você mover arquivos entre sistemas diferentes, essas inconsistências podem causar
problemas.
Para a maioria dos sistemas, existem aplicativos para converter de um formato para outro.
Você pode encontrá-los (e ler mais sobre este assunto) em wikipedia.org/wiki/Newline. Ou,
claro, você mesmo pode escrever um.
7.10 Glossary
Catch - Para evitar que uma exceção termine um programa usando a declarações try e except.
Nova linha - Um caractere especial usado em arquivos e strings para indicar o fim de uma
linha.
Pythonic - Uma técnica que funciona elegantemente em Python. “Usar try e except é a
maneira Pythonica de se recuperar um arquivos perdidos”.
7.11 Exercises
Exercício 1: Escreva um programa para ler um arquivo e imprimir o conteúdo do arquivo (linha
por linha) tudo em caixa alta. A execução do programa ficará da seguinte forma:
python shout.py
RETURN-PATH: <POSTMASTER@COLLAB.SAKAIPROJECT.ORG>
www.pythonlearn.com/code3/mbox-short.txt
X-DSPAM-Confidence:0.8475
Quando você encontrar uma linha que começa com “X-DSPAM-Confidence:” separe a linha
para extrair o número de ponto flutuante na linha. Conte essas linhas e em seguida, calcule o
total dos valores de confiança de spam dessas linhas. Quando você chegar ao final do arquivo,
imprima a confiança média de spam.
Digite o nome do arquivo: mbox.txt
python egg.py
python egg.py
python egg.py
Não estamos encorajando você a colocar Easter Eggs em seus programas; isso é apenas um
exercício. Hahahaha
Capítulo 8
Listas
8.1 Uma lista é uma sequência
Como uma string, uma lista é uma sequência de valores. Em uma string, os valores são
caracteres em uma lista, eles podem ser de qualquer tipo. Os valores na lista são chamados
elementos ou às vezes Unid.
Existem várias maneiras de criar uma nova lista; o mais simples é incluir os elementos entre
colchetes ([ e ]):
~~ {.python} [10, 20, 30, 40]['sapo crocante', 'bexiga de carneiro', 'vômito de cotovia'] ~~
{.Pitão}
O primeiro exemplo é uma lista de quatro inteiros. A segunda é uma lista de três strings. Os
elementos de uma lista não precisam ser do mesmo tipo. A lista a seguir contém uma string,
um float, um integer e (lo!) outra lista:
Uma lista que não contém elementos é chamada de lista vazia; você pode criar um com
colchetes vazios, [].
Como você pode esperar, você pode atribuir valores de lista a variáveis:
>>> vazio = []
>>> print(cheeses[0])
Cheddar
Ao contrário das strings, as listas são mutáveis porque você pode alterar a ordem dos itens em
uma lista ou reatribuir um item em uma lista. Quando o operador colchete aparece ao lado
esquerdo de uma atribuição, identifica o elemento da lista que será atribuído.
>>> numbers[1] = 5
>>> print(numbers)
[17, 5]
Você pode pensar em uma lista como uma relação entre índices e elementos. Esse
relacionamento é chamado de mapeamento; cada índice “mapeia” um dos elementos.
• Se você tentar ler ou escrever um elemento que não existe, você obtém um IndexError.
• Se um índice tiver um valor negativo, ele faz a contagem regressiva a partir do final da lista.
True
False
8.3 Percorrendo uma lista
A maneira mais comum de percorrer os elementos de uma lista é com um loop for. A sintaxe é
a mesma das strings:
print(cheese)
Isso funciona bem se você só precisa ler os elementos da lista. Mas se você quer para escrever
ou atualizar os elementos, você precisa dos índices. Uma maneira comum de fazer isso é
combinar as funções range e len:
for i in range(len(numbers)):
numbers[i] = numbers[i] * 2
Este loop percorre a lista e atualiza cada elemento. len retorna o número de elementos na
lista. Range retorna uma lista de índices de 0 a n − 1, onde n é o comprimento da lista. Cada
vez que passar pelo loop, i obtém o índice do próximo elemento. A instrução de atribuição no
corpo usa i para ler o valor antigo do elemento e para atribuir o novo valor.
for x in empty:
Embora uma lista possa conter outra lista, a lista aninhada ainda conta como um único
elemento. O comprimento desta lista é quatro:
>>> b = [4, 5, 6]
>>> c = a + b
>>> print(c)
[1, 2, 3, 4, 5, 6]
>>> [0] * 4
[0, 0, 0, 0]
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
O primeiro exemplo se repete quatro vezes. O segundo exemplo repete a lista três vezes.
>>> t[1:3]
['b', 'c']
>>> t[:4]
>>> t[3:]
Se você omitir o primeiro índice, a fatia começa no início. Se você omitir o segundo, a fatia vai
até o fim. Portanto, se você omitir ambos, a fatia será uma cópia de toda a lista.
>>> t[:]
Um operador de fatia no lado esquerdo de uma atribuição pode atualizar vários elementos:
>>> print(t)
>>> t.append('d')
>>> print(t)
>>> t1.extend(t2)
>>> print(t1)
>>> t.sort()
>>> print(t)
A maioria dos métodos de lista é void; eles modificam a lista e retornam None. Se você
acidentalmente escrever t = t.sort(), ficará desapontado com o resultado.
>>> x = t.pop(1)
>>> print(t)
['a', 'c']
>>> print(x)
pop modifica a lista e retorna o elemento que foi removido. Se você não fornecer um índice,
ele exclui e retorna o último elemento.
>>> print(t)
['a', 'c']
Se você conhece o elemento que deseja remover (mas não o índice), pode usar remove:
>>> t.remove('b')
>>> print(t)
['a', 'c']
Para remover mais de um elemento, você pode usar del com um índice de fatia:
>>> print(t)
['a', 'f']
Como de costume, a fatia seleciona todos os elementos, mas não incluindo, o segundo índice.
>>> print(len(nums))
>>> print(max(nums))
74
>>> print(min(nums))
>>> print(sum(nums))
154
>>> print(sum(nums)/len(nums))
25
A função sum() só funciona quando os elementos da lista são números. A outras funções
(max(), len(), etc.) trabalham com listas de strings e outros tipos que podem ser comparáveis.
Poderíamos reescrever um programa anterior que calculasse a média de uma lista de números
inserido pelo usuário usando uma lista.
total = 0
count = 0
while (True):
value = float(inp)
count = count + 1
print('Average:', average)
# Code: http://www.pythonlearn.com/code3/avenum.py
Neste programa, temos as variáveis count e total para manter o número e executando o total
dos números do usuário enquanto solicitamos repetidamente ao usuário um número.
Poderíamos simplesmente lembrar cada número à medida que o usuário o inseriu e usar
funções para calcular a soma e contar no final.
numlist = list()
while (True):
value = float(inp)
numlist.append(value)
print('Average:', average)
# Code: http://www.pythonlearn.com/code3/avelist.py
Fazemos uma lista vazia antes do início do loop e, a cada vez que tivermos um número, nós o
anexamos à lista. No final do programa, simplesmente calculamos a soma dos números na lista
e divido-a pela contagem dos números na lista para ver a média.
>>> s = 'spam'
>>> t = list(s)
>>> print(t)
Como lista é o nome de uma função interna, você deve evitar usá-la como um nome variável.
Também evite a letra l porque parece muito com o número 1. É por isso que eu uso t.
A função de lista quebra uma string em letras individuais. Se você quiser quebrar uma string
em palavras, você pode usar o método split:
>>> t = s.split()
>>> print(t)
>>> print(t[2])
The
Depois de usar split para quebrar a string em uma lista de palavras, você pode usar o comando
operador de índice (colchete) para examinar uma palavra específica na lista.
Você pode chamar split com um argumento opcional chamado delimitador que especifica
quais caracteres usar como limites de palavras. O exemplo a seguir usa um hífen como
delimitador:
>>> s = 'spam-spam-spam'
join é o inverso de split. Ele pega uma lista de strings e concatena os elementos. join é um
método de string, então você deve invocá-lo no delimitador e passar a lista como parâmetro:
>>> delimiter.join(t)
Nesse caso, o delimitador é um caractere de espaço; portanto, join coloca um espaço entre as
palavras. Para concatenar strings sem espaços, você pode usar a string vazia, “”, como um
delimitador.
O método split é muito eficaz quando confrontado com este tipo de problema. Podermos
escrever um pequeno programa que procure linhas onde a linha começa com “From”, Split
essas linhas e, em seguida, imprimir a terceira palavra na linha:
fhand = open('mbox-short.txt')
line = line.rstrip()
words = line.split()
print(words[2])
# Code: http://www.pythonlearn.com/code3/search5.py
Aqui também usamos a forma contraída da instrução if onde colocamos o continue na mesma
linha do if. Esta forma contraída do if funciona o mesmo que se o continue estivesse na
próxima linha e recuado.
Sat
Fri
Fri
Fri
...
Mais tarde, aprenderemos técnicas cada vez mais sofisticadas para escolher as linhas para
trabalharmos e como separamos essas linhas para encontrar a informação exata que estamos
procurando.
a = 'banana'
b = 'banana'
Sabemos que a e b referem-se a uma string, mas não sabemos se eles se referem à mesma
corda. Existem dois estados possíveis:
Em um caso, a e b referem-se a dois objetos diferentes que têm o mesmo valor. No segundo
caso, eles se referem ao mesmo objeto.
Para verificar se duas variáveis se referem ao mesmo objeto, você pode usar a operação is
ator.
>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True
Neste exemplo, o Python criou apenas um objeto string, e ambos a e b referem-se a isto.
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False
Neste caso diríamos que as duas listas são equivalentes, pois possuem os mesmos elementos,
mas não idênticos, porque não são o mesmo objeto. Se dois objetos são idênticos, também
são equivalentes, mas se são equivalentes, não são necessariamente idênticos.
Até agora, usamos “objeto” e “valor” de forma intercambiável, mas é mais preciso dizer que
um objeto tem um valor. Se você executar a = [1,2,3], a se refere a um objeto de lista cujo
valor é uma sequência específica de elementos. Se outra lista tiver os mesmos elementos,
diríamos que tem o mesmo valor.
8.12 Aliasing
Se a se refere a um objeto e você atribui b = a, então ambas as variáveis se referem ao mesmo
objeto:
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
Um objeto com mais de uma referência tem mais de um nome, então dizemos que o objeto é
aliased.
Se o objeto com alias for mutável, as alterações feitas com um alias afetarão o outro:
>>> b[0] = 17
>>> print(a)
[17, 2, 3]
Embora esse comportamento possa ser útil, ele é propenso a erros. Em geral, é mais seguro
evitar aliasing quando estiver trabalhando com objetos mutáveis.
Para objetos imutáveis como strings, o aliasing não é um problema tão grande. Exemplo:
a = 'banana'
b = 'banana'
def delete_head(t):
del t[0]
>>> delete_head(letters)
>>> print(letters)
['b', 'c']
É importante distinguir entre operações que modificam listas e operações que criam novas
listas. Por exemplo, o método append modifica uma lista, mas o operador + cria uma nova
lista:
>>> t1 = [1, 2]
>>> t2 = t1.append(3)
>>> print(t1)
[1, 2, 3]
>>> print(t2)
None
>>> t3 = t1 + [3]
>>> print(t3)
[1, 2, 3]
>>> t2 is t3
False
Essa diferença é importante quando você escreve funções que devem modificar listas. Por
exemplo, esta função não exclui o cabeçalho de uma lista:
def bad_delete_head(t):
t = t[1:] # ERRADO!
O operador de fatia cria uma nova lista e a atribuição faz referência a ela, mas nada disso tem
efeito na lista que foi passada como argumento.
Uma alternativa é escrever uma função que crie e retorne uma nova lista. Por exemplo, tail
retorna todos menos o primeiro elemento de uma lista:
def tail(t):
return t[1:]
>>> print(rest)
['b', 'c']
Exercício 1: Escreva uma função chamada chop que pegue uma lista e a modifique, removendo
o primeiro e últimos elementos e retorna None.
Em seguida, escreva uma função chamada middle que recebe uma lista e retorna uma nova
lista que contém todos, exceto o primeiro e o último elementos.
8.14 Depuração
O uso descuidado de listas (e outros objetos mutáveis) pode levar a longas horas de
depuração.
1. Não se esqueça de que a maioria dos métodos de lista modifica o argumento e retorna
None. Isso é o oposto dos métodos de string, que retornam uma nova string e deixa o original
em paz.
word = word.strip()
Como sort retorna None, a próxima operação que você executar com t provavelmente falhara.
Antes de usar métodos e operadores de lista, você deve ler a documentação cuidadosamente
e, em seguida, teste-os no modo interativo. Os métodos e os operadores que listam
compartilham com outras sequências (como strings) são documentados em
https://docs.python.org/2/library/stdtypes.html#string-methods . Os métodos e operadores
que se aplicam apenas a sequências mutáveis são documentados em
https://docs.python.org/2/library/stdtypes.html#mutable-sequence-types .
Parte do problema com as listas é que existem muitas maneiras de fazer as coisas. Por
exemplo, para remover um elemento de uma lista, você pode usar pop, remove, del, ou até
mesmo uma atribuição de fatia.
Para adicionar um elemento, você pode usar o método append ou o operador +. Mas não se
esqueça que estes estão certos:
t.append(x)
t = t + [x]
E estes estão errados:
t.append([x]) # ERRADO!
t = t.append(x) # ERRADO!
t + [x] # ERRADO!
t = t + x # ERRADO!
Experimente cada um desses exemplos no modo interativo para certificar-se de que você
entendeu suportar o que eles fazem. Observe que apenas o último causa um erro de execução;
os outros três são legais, mas fazem a coisa errada.
Se você quiser usar um método como sort que modifica o argumento, mas você precisa
manter a lista original também, você pode fazer uma cópia.
orig = t[:]
t.sort()
Neste exemplo, você também pode usar a função interna sorted, que retorna uma nova lista
ordenada e deixa o original sozinho. Mas nesse caso você deve evitar usar sort como um nome
de variável!
Vamos revisitar nosso programa que está procurando o dia da semana na partir de linhas do
nosso arquivo:
Como estamos quebrando esta linha em palavras, poderíamos simplesmente olhar para a
primeira palavra da linha para determinar se estamos interessados na linha em todo. Podemos
usar continue para pular linhas que não tenha "De" como a primeira palavra da seguinte
forma:
fhand = open('mbox-short.txt')
words = line.split()
print(words[2])
Isso parece muito mais simples e nem precisamos fazer o rstrip para remover a nova linha no
final do arquivo. Mas é melhor?
python search8.py
Sat
Isso meio que funciona e vemos o dia da primeira linha (Sáb), mas depois o programa falha
com um erro de rastreamento. O que deu errado? que bagunça de dados causaram a falha de
nosso elegante, inteligente e muito Pythonic programa?
Você pode olhar para ele por um longo tempo e decifrá-lo ou perguntar a alguém para obter
ajuda, mas a abordagem mais rápida e inteligente é adicionar uma instrução de impressão. O
melhor lugar para adicionar a instrução de impressão é logo antes da linha onde o programa
falhou e imprimir os dados que parecem estar causando a falha.
words = line.split()
print('Debug:', words)
print(words[2])
Quando executamos o programa, muitas saídas saem da tela, mas no final, vemos nossa saída
de depuração e o traceback para sabermos o que aconteceu pouco antes do traceback.
Debug: []
Cada linha de depuração está imprimindo a lista de palavras que obtemos quando dividimos a
linha em palavras. Quando o programa falha, a lista de palavras fica vazia []. Se abrirmos o
arquivo em um editor de texto e olharmos para o arquivo, nesse ponto parece do seguinte
modo:
X-DSPAM-Result: Innocent
X-DSPAM-Confidence: 0.8475
X-DSPAM-Probability: 0.0000
Details: http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772
O erro ocorre quando nosso programa encontra uma linha em branco! claro que são “palavras
zero” em uma linha em branco. Por que não pensamos nisso quando estávamos escrevendo o
código? Quando o código procura a primeira palavra (palavra[0]) para verificar e ver se
corresponde a “De”, obtemos um erro de “índice fora do intervalo”.
É claro que este é o lugar perfeito para adicionar algum código de guardião para evitar
checagem. a primeira palavra se a primeira palavra não estiver lá. Existem muitas maneiras de
proteja este código; escolheremos verificar o número de palavras que temos antes de
olharmos para a primeira palavra:
fhand = open('mbox-short.txt')
count = 0
words = line.split()
if len(words) == 0 : continue
Podemos pensar nas duas instruções continue como nos ajudando a refinar o conjunto de
linhas que são “interessantes” para nós e que queremos processar um pouco mais. Uma linha
que não tem palavras “desinteressante” para nós, então pulamos para a próxima linha. Uma
linha que não tem “De” como primeira palavra é desinteressante para nós, então nós o
ignoramos.
O programa modificado é executado com sucesso, então talvez esteja correto. Nossa
declaração do guardião garante que as palavras [0] nunca falharão, mas talvez não seja
suficiente. Quando estamos programando, devemos estar sempre pensando: "O que pode dar
errado?"
Exercício 2: Descubra qual linha do programa acima ainda não está devidamente protegida.
Veja se você pode construir um arquivo de texto que faz com que o programa falhe e
modifique o programa para que a linha esteja devidamente protegida e teste-a para ter
certeza de que lida com seu novo arquivo de texto.
Exercício 3: Reescreva o código do guardião no exemplo acima sem duas instruções if. Em vez
disso, use uma expressão lógica composta usando o operador lógico and com uma única
instrução if.
8.15 Glossário
Aliasing - Uma circunstância em que duas ou mais variáveis se referem ao mesmo objeto.
Delimitador - Um caractere ou string usado para indicar onde uma string deve ser dividida.
Elemento - Um dos valores em uma lista (ou outra sequência); também chamados de itens.
Objeto - Algo a que uma variável pode se referir. Um objeto tem um tipo e um valor.
Escreva um programa para abrir o arquivo romeo.txt e leia-o linha por linha. Para cada linha,
divida a linha em uma lista de palavras usando a função split.
Para cada palavra, verifique se a palavra já está em uma lista. Se a palavra não estiver em uma
lista, adicioná-lo à lista.
'with', 'yonder']
Exercício 5: Escreva um programa para ler os dados da caixa de correio e quando você
encontrar a linha que começa com “From”, você dividirá a linha em palavras usando a função
divisão. Estamos interessados em saber quem enviou a mensagem, que é a segunda palavra na
linha De.
Você analisará a linha De e imprimirá a segunda palavra para cada linha De, então você
também contará o número de linhas De (não De:) e imprimirá no final.
python fromcount.py
stephen.marquard@uct.ac.za
louis@media.berkeley.edu
zqian@umich.edu
cwen@iupui.edu
cwen@iupui.edu
cwen@iupui.edu
Exercício 6: Reescreva o programa que solicita ao usuário uma lista de números e imprima o
máximo e o mínimo dos números no final quando o usuário entra "concluído". Escreva o
programa para armazenar os números que o usuário insere em uma lista e use as funções
max() e min() para calcular o máximo e o mínimo de números após a conclusão do loop.
Digite um número: 6
Digite um número: 2
Digite um número: 9
Digite um número: 3
Digite um número: 5
Máximo: 9,0
Mínimo: 2,0
Capítulo 9
Dicionários
Um dicionário é como uma lista, mas mais geral. Em uma lista, as posições de índice devem ser
inteiros; em um dicionário, os índices podem ser (quase) de qualquer tipo.
Você pode pensar em um dicionário como um mapeamento entre um conjunto de índices (que
são chamadas chaves) e um conjunto de valores. Cada chave é mapeada para um valor. A
associação de uma chave e um valor é chamado de par chave-valor ou às vezes um item.
Como exemplo, construiremos um dicionário que mapeia palavras em inglês para espanhol,
então as chaves e os valores são todos strings.
A função dict cria um novo dicionário sem itens. Porque o ditado é o nome de uma função
interna, você deve evitar usá-lo como um nome de variável.
>>> print(eng2sp)
{}
As chaves, {}, representam um dicionário vazio. Para adicionar itens ao dicionário, você pode
usar colchetes:
Esta linha cria um item que mapeia da chave 'one' para o valor "uno". Se nós imprimirmos o
dicionário novamente, vemos um par chave-valor com dois pontos entre a chave e o valor:
>>> print(eng2sp)
{'one': 'uno'}
Este formato de saída também é um formato de entrada. Por exemplo, você pode criar um
novo dicionário com três itens. Mas se você imprimir eng2sp, poderá se surpreender:
>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}
>>> print(eng2sp)
A ordem dos pares chave-valor não é a mesma. Na verdade, se você digitar o mesmo exemplo
em seu computador, você pode obter um resultado diferente. Em geral, a ordem dos itens em
um dicionário é imprevisível.
Mas isso não é um problema porque os elementos de um dicionário nunca são indexados com
índices inteiros. Em vez disso, você usa as chaves para procurar os valores correspondentes:
>>> print(eng2sp['two'])
'dos'
A chave 'dos' sempre mapeia para o valor "dos" para que a ordem dos itens não matter.
>>> print(eng2sp['four'])
KeyError: 'four'
>>> len(eng2sp)
O operador in funciona em dicionários; ele informa se algo aparece como uma chave no
dicionário (aparecer como um valor não é bom o suficiente).
True
False
Para ver se algo aparece como um valor em um dicionário, você pode usar os valores do
método, que retorna os valores como uma lista e, em seguida, use o operador in:
True
O operador in usa algoritmos diferentes para listas e dicionários. Para listas, usa um algoritmo
de busca linear. À medida que a lista aumenta, o tempo de pesquisa aumenta em proporção
direta ao comprimento da lista. Para dicionários, o Python usa um algoritmo chamado tabela
hash que possui uma propriedade notável: o operador in leva aproximadamente a mesma
quantidade de tempo, não importa quantos itens haja em um dicionário. Não vou explicar por
que as funções de hash são tão mágicas, mas você pode ler mais sobre isso em
wikipedia.org/wiki/Hash_table.
1. Você pode criar 26 variáveis, uma para cada letra do alfabeto. Então você poderia
percorrer a string e, para cada caractere, incrementar o correspondente contador,
provavelmente usando uma condicional encadeada.
2. Você pode criar uma lista com 26 elementos. Então você pode converter cada caractere
a um número (usando a função integrada ord), use o número como um índice na lista e
incremente o contador apropriado.
3. Você pode criar um dicionário com caracteres como chaves e contadores como valores
correspondentes. A primeira vez que você vê um personagem, você deve adicionar um
item ao dicionário. Depois disso, você incrementaria o valor de um artigo existente.
Cada uma dessas opções executa o mesmo cálculo, mas cada uma delas implementa esse
cálculo de uma maneira diferente.
Uma implementação é uma forma de executar uma computação; algumas implementações
são melhores que outras. Por exemplo, uma vantagem da implementação do dicionário, a
vantagem é que não precisamos saber de antemão quais letras aparecem na string e só temos
que abrir espaço para as letras que aparecem.
word = 'brontosaurus'
d = dict()
for c in word:
if c not in d:
d[c] = 1
else:
d[c] = d[c] + 1
print(d)
O loop for percorre a string. Cada vez que passar pelo loop, se o caractere c não está no
dicionário, criamos um novo item com a chave c e o valor inicial 1 (já que vimos esta carta uma
vez). Se c já estiver no dicionário, incrementamos d[c].
O histograma indica que as letras 'a' e "b" aparecem uma vez; “o” aparece duas vezes, e assim
por diante.
Os dicionários têm um método chamado get que recebe uma chave e um valor padrão. Se o
key aparece no dicionário, get retorna o valor correspondente; caso contrário isto retorna o
valor padrão. Por exemplo:
100
Podemos usar get para escrever nosso loop de histograma de forma mais concisa. Porque o
método get lida automaticamente com o caso em que uma chave não está em um dicionário,
podemos reduza quatro linhas para uma e elimine a instrução if.
word = 'brontosaurus'
d = dict()
for c in word:
d[c] = d.get(c,0) + 1
print(d)
A utilização do método get para simplificar esse loop de contagem acaba sendo comumente
um “idioma” usado em Python e vamos usá-lo muitas vezes no resto do e-book. Portanto, você
deve parar um momento e comparar o loop usando a instrução if e no operador com o loop
usando o método get. Eles fazem exatamente a mesma coisa, mas uma é mais sucinta.
Para o primeiro conjunto de exemplos, usaremos uma versão abreviada e simplificada do texto
sem pontuação. Posteriormente trabalharemos com o texto da cena com pontuação incluída.
Vamos escrever um programa Python para ler as linhas do arquivo, quebrar cada linha em uma
lista de palavras e, em seguida, percorrer cada uma das palavras na linha e conte cada palavra
usando um dicionário.
Você verá que temos dois loops for. O loop externo está lendo as linhas do arquivo e o loop
interno está iterando através de cada uma das palavras naquela linha em particular. Este é um
exemplo de um padrão chamado loops aninhados porque um dos loops é o loop externo e o
outro loop é o loop interno.
Como o loop interno executa todas as suas iterações cada vez que o loop externo faz uma
única iteração, pensamos no loop interno como iterando “mais rapidamente” e o loop externo
como iteração mais lenta.
A combinação dos dois loops aninhados garante que contaremos cada palavra em cada linha
do arquivo de entrada.
try:
fhand = open(fname)
except:
exit()
counts = dict()
words = line.split()
counts[word] = 1
else:
counts[word] += 1
print(counts)
# Code: http://www.pythonlearn.com/code3/count1.py
Quando executamos o programa, vemos um despejo bruto de todas as contagens em hash não
classificado em ordem. (o arquivo romeo.txt está disponível em
www.pythonlearn.com/code3/romeo.txt )
python count1.py
print(key, counts[key])
jan 100
chuck 1
annie 42
Podemos usar esse padrão para implementar os vários idiomas de loop que criamos escrito
anteriormente. Por exemplo, se quisermos encontrar todas as entradas em um dicionário com
um valor acima de dez, poderíamos escrever o seguinte código:
counts = { 'chuck' : 1 , 'annie' : 42, 'jan': 100}
if counts[key] > 10 :
print(key, counts[key])
O loop for itera pelas chaves do dicionário, então devemos usar o índice operador para
recuperar o valor correspondente para cada chave. Aqui está o que a saída parece:
jan 100
annie 42
Se você deseja imprimir as chaves em ordem alfabética, primeiro faça uma lista das chaves no
dicionário usando o método de chaves disponível em objetos de dicionário e, em seguida,
classifique essa lista e percorra a lista classificada, procurando cada chave e imprimindo os
pares chave-valor na ordem classificada da seguinte forma:
lst = list(counts.keys())
print(lst)
lst.sort()
print(key, counts[key])
annie 42
chuck 1
jan 100
Primeiro, você vê a lista de chaves em ordem não classificada que obtemos do método keys.
Em seguida, vemos os pares chave-valor na ordem do loop for.
Como a função split do Python procura por espaços e trata palavras como tokens separados
por espaços, trataríamos as palavras “suave!” e “suave” como palavras diferentes e criaria
uma entrada de dicionário separada para cada palavra.
Além disso, como o arquivo possui letras maiúsculas, trataríamos “quem” e “Quem” como
diferentes palavras com contagens diferentes.
Podemos resolver esses dois problemas usando os métodos de string lower, punctuation, e
traduzir. A tradução é o mais sutil dos métodos. Aqui está a documentação para traduzir:
Exclua todos os caracteres de que estão em deletechars (se houver) e, em seguida, traduza os
caracteres usando a tabela, que deve ser uma string de 256 caracteres fornecendo a tradução
para cada valor de caractere, indexado por seu ordinal. Se a tabela for Nenhuma, somente a
etapa de exclusão de caracteres é executada.
Não especificaremos a tabela, mas usaremos o parâmetro deletechars para excluir toda a
pontuação. Vamos até deixar Python nos dizer a lista de caracteres que considera
“pontuação”:
>>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
import string
try:
fhand = open(fname)
except:
exit()
counts = dict()
line = line.rstrip()
line = line.lower()
words = line.split()
counts[word] = 1
else:
counts[word] += 1
print(counts)
# Code: http://www.pythonlearn.com/code3/count2.py
Usamos translate para remover toda a pontuação e lower para forçar a linha a diminuir. Caso
contrário, o programa permanece inalterado. Observe que para Python 2.5 e anteriores,
translate não aceita None como o primeiro parâmetro, então use este código para a chamada
de tradução:
Analisar essa saída ainda é difícil de manejar e podemos usar o Python para nos fornecer
exatamente o que estamos procurando, mas, para isso, precisamos aprender sobre as tuplas
do Python.
9.5 Depuração
À medida que você trabalha com conjuntos de dados maiores, pode se tornar complicado
depurar imprimindo e verificando os dados manualmente. Aqui estão algumas sugestões para
depurar grandes conjuntos de dados:
Verifique resumos e tipos Em vez de imprimir e verificar todo o conjunto de dados, considere
imprimir resumos dos dados: por exemplo, o número de itens em um dicionário ou o total de
uma lista de números. Uma causa comum de erros de tempo de execução é um valor que não
é do tipo correto. Para depurando esse tipo de erro, muitas vezes basta imprimir o tipo de um
valor.
Escreva autoverificações Às vezes, você pode escrever código para verificar erros
automaticamente. Calmamente. Por exemplo, se você estiver calculando a média de uma lista
de números, você poderia verificar se o resultado não é maior que o maior elemento da lista
ou menor que o menor. Isso é chamado de “verificação de sanidade” porque detecta
resultados que são “completamente ilógicos”.
Outro tipo de verificação compara os resultados de dois cálculos para ver se eles são
consistentes. Isso é chamado de "checagem de Consistência".
Imprima bem a saída A formatação da saída de depuração pode facilitar a detectar um erro.
9.6 Glossário
Dicionário - Um mapeamento de um conjunto de chaves para seus valores correspondentes.
Função de hash - Uma função usada por uma tabela de hash para calcular a localização de uma
chave.
Chave - Um objeto que aparece em um dicionário como a primeira parte de um par chave-
valor.
Lookup - Uma operação de dicionário que pega uma chave e localiza o valor correspondente.
Loops aninhados - Quando há um ou mais loops “dentro” de outro loop. O loop interno é
executado toda vez que o loop externo é executado uma vez, até a conclusão.
9.7 Exercícios
Exercício 2: Escreva um programa que classifique cada mensagem de correio em que dia da
semana em que o commit foi feito. Para fazer isso, procure por linhas que começam com
“From”, então procure a terceira palavra e mantenha uma contagem contínua de cada um dos
dias da semana. No final do programa imprima o conteúdo do seu dicionário (encomende Não
importa).
Linha de amostra:
python dow.py
Exercício 3: Escreva um programa para ler um log de correio, construa um histograma usando
um dicionário para contar quantas mensagens vieram de cada endereço de e-mail e imprima o
dicionário.
{'gopal.ramasammycook@gmail.com': 1, 'louis@media.berkeley.edu': 3,
'cwen@iupui.edu': 5, 'antranig@caret.cam.ac.uk': 1,
'rjlowe@iupui.edu': 2, 'gsilver@umich.edu': 3,
'david.horwitz@uct.ac.za': 4, 'wagnermr@iupui.edu': 1,
'zqian@umich.edu': 4, 'stephen.marquard@uct.ac.za': 2,
'ray@media.berkeley.edu': 1}
Exercício 4: Adicione um código ao programa acima para descobrir quem tem mais mensagens
no arquivo.
cwen@iupui.edu 5
zqian@umich.edu 195
Exercício 5: Este programa registra o nome de domínio (em vez do endereço) onde a
mensagem foi enviada em vez de quem o e-mail veio (ou seja, todo o e-mail de endereço). No
final do programa, imprima o conteúdo do seu dicionário.
python schoolcount.py
Enter a file name: mbox-short.txt
Embora não seja necessário, é comum colocar tuplas entre parênteses para ajudar
identificarmos tuplas rapidamente quando olhamos para o código Python:
Para criar uma tupla com um único elemento, você deve incluir a vírgula final:
>>> t1 = ('a',)
>>> type(t1)
<type 'tuple'>
Sem a vírgula, o Python trata ('a') como uma expressão com uma string entre parênteses, teses
que é avaliada como uma string:
>>> t2 = ('a')
>>> type(t2)
<type 'str'>
Outra maneira de construir uma tupla é a tupla de função interna. Sem argumentos, ele cria
uma tupla vazia:
>>> t = tuple()
>>> print(t)
()
Se o argumento for uma sequência (string, lista ou tupla), o resultado da chamada para tupla é
uma tupla com os elementos da sequência:
>>> t = tuple('lupins')
>>> print(t)
Como tupla é o nome de um construtor, você deve evitar usá-la como uma variável nome.
A maioria dos operadores de lista também funciona em tuplas. O operador colchete indexa um
elemento:
>>> print(t[0])
'a'
>>> print(t[1:3])
('b', 'c')
>>> print(t)
True
True
Decore uma sequência construindo uma lista de tuplas com uma ou mais chaves de
classificação precedendo os elementos da sequência
[DSU]
Por exemplo, suponha que você tenha uma lista de palavras e queira classificá-las de mais
longo para o mais curto:
txt = 'but soft what light in yonder window breaks'
words = txt.split()
t = list()
t.append((len(word), word))
t.sort(reverse=True)
res = list()
res.append(word)
print(res)
# Code: http://www.pythonlearn.com/code3/soft.py
O primeiro loop constrói uma lista de tuplas, onde cada tupla é uma palavra precedida por seu
comprimento.
sort compara o primeiro elemento, length, first, e considera apenas o segundo elemento para
desempate. O argumento de palavra-chave reverse=True diz ao sort para entrar ordem
decrescente.
O segundo loop percorre a lista de tuplas e constrói uma lista de palavras em ordem
descendente. Ordem de comprimento. As palavras de quatro caracteres são classificadas em
ordem alfabética reversa, então “what” aparece antes de “soft” na lista a seguir.
É claro que a linha perde muito de seu impacto poético quando transformada em uma lista
Python e classificados em ordem de comprimento de palavra decrescente.
Neste exemplo, temos uma lista de dois elementos (que é uma sequência) e atribuímos o
primeiro e os segundos elementos da sequência às variáveis x e y em uma única instrução.
>>> m = [ 'have', 'fun' ]
>>> x, y = m
>>> x
'have'
>>> y
'fun'
>>>
Não é mágica, o Python traduz aproximadamente a sintaxe de atribuição de tupla para ser a
seguinte:
>>> x = m[0]
>>> y = m[1]
>>> x
'have'
>>> y
'fun'
>>>
>>> (x, y) = m
>>> x
'have'
>>> y
'fun'
>>>
Uma aplicação particularmente inteligente de atribuição de tuplas nos permite trocar os
valores de duas variáveis em uma única instrução:
>>> a, b = b, a
Ambos os lados dessa instrução são tuplas, mas o lado esquerdo é uma tupla de variáveis, o
lado direito é uma tupla de expressões. Cada valor no lado direito é atribuído à sua respectiva
variável no lado esquerdo. Todas as expressões do lado direito são avaliados antes de qualquer
uma das tarefas.
>>> a, b = 1, 2, 3
Mais geralmente, o lado direito pode ser qualquer tipo de sequência (string, lista ou tupla). Por
exemplo, para dividir um endereço de e-mail em um nome de usuário e um domínio, você
pode escrever:
O valor de retorno de split é uma lista com dois elementos; o primeiro elemento é atribuído
para uname, o segundo para domínio.
>>> print(uname)
monty
>>> print(domain)
python.org
>>> t = list(d.items())
>>> print(t)
Como você deve esperar de um dicionário, os itens não estão em nenhuma ordem específica.
No entanto, como a lista de tuplas é uma lista e as tuplas são comparáveis, podemos agora
ordenar a lista de tuplas. Converter um dicionário em uma lista de tuplas é uma maneira de
produzir o conteúdo de um dicionário classificado por chave:
>>> t = list(d.items())
>>> t
>>> t.sort()
>>> t
print(val, key)
Este loop tem duas variáveis de iteração porque items retorna uma lista de tuplas e chaves, val
é uma atribuição de tupla que itera sucessivamente por cada um dos valores-chave pares no
dicionário.
Para cada iteração no loop, a chave e o valor são avançados para o próximo par chave-valor no
dicionário (ainda em ordem de hash).
10 a
22 c
1b
Novamente, está na ordem da chave de hash (ou seja, nenhuma ordem específica).
Para fazer isso, primeiro fazemos uma lista de tuplas onde cada tupla está (valor, chave). O
método items nos daria uma lista de tuplas (chave, valor), mas desta vez queremos para
classificar por valor, não por chave. Depois de construirmos a lista com a chave-valor tuplas, é
uma questão simples ordenar a lista na ordem inversa e imprimir a nova, lista ordenada.
>>> l = list()
...
>>> l
>>> l.sort(reverse=True)
>>> l
>>>
Construindo cuidadosamente a lista de tuplas para ter o valor como primeiro elemento de
cada tupla, podemos classificar a lista de tuplas e classificar o conteúdo do nosso dicionário
por valor.
10.6 As palavras mais comuns
Voltando ao nosso exemplo contínuo do texto de Romeu e Julieta, Ato 2, Cena 2, podemos
aumentar nosso programa para usar esta técnica para imprimir as dez palavras mais comuns
no texto como segue:
import string
fhand = open('romeo-full.txt')
counts = dict()
line = line.translate(string.punctuation)
line = line.lower()
words = line.split()
counts[word] = 1
else:
counts[word] += 1
lst = list()
lst.append((val, key))
lst.sort(reverse=True)
print(key, val)
# Code: http://www.pythonlearn.com/code3/count3.py
A primeira parte do programa que lê o arquivo e calcula o dicionário que mapeia cada palavra
para a contagem de palavras no documento permanece inalterada. Mas em vez de
simplesmente imprimir contagens e encerrar o programa, construímos uma lista de (val, key)
tuplas e, em seguida, classifique a lista na ordem inversa.
Como o valor é o primeiro, ele será usado para as comparações. Se houver mais de uma tupla
com o mesmo valor, ele vai olhar para o segundo elemento (a chave), então as tuplas em que
o valor é o mesmo serão classificadas pela ordem alfabética da chave.
No final, escrevemos um bom loop for que faz uma iteração de atribuição múltipla e imprime
as dez palavras mais comuns iterando por uma fatia da lista (primeiro[:10]).
Então agora a saída finalmente se parece com o que queremos para nossa análise de
frequência de palavras.
61 i
42 and
40 romeo
34 to
34 the
32 thou
32 juliet
30 that
29 my
24 thee
O fato de que essa complexa análise de dados pode ser feita com um método fácil de entender
o programa Python de 19 linhas é uma das razões pelas quais o Python é uma boa escolha
como uma linguagem para explorar informações.
Encontraríamos uma chave composta se quiséssemos criar uma lista telefônica que mapeia
pares de sobrenome e primeiro nome para números de telefone. Assumindo que definimos as
variáveis last, first e number, poderíamos escrever um dicionário de declaração de atribuição
da seguinte forma:
directory[last,first] = number
A expressão entre colchetes é uma tupla. Poderíamos usar atribuição de tupla em um loop for
para percorrer este dicionário.
for last, first in directory:
Este loop percorre as chaves no diretório, que são tuplas. Atribui os elementos de cada tupla
para o último e o primeiro, depois imprime o nome e o telefone correspondente ao número.
Em muitos contextos, os diferentes tipos de sequências (strings, listas e tuplas) podem ser
usados de forma intercambiáveis. Então, como e por que você escolhe um sobre os outros?
Para começar com o óbvio, as strings são mais limitadas do que outras sequências porque os
elementos devem ser caracteres. Eles também são imutáveis. Se você precisar da capacidade
de alterar os caracteres em uma string (em vez de criar uma nova string), você pode querer
usar uma lista de caracteres em vez disso.
Listas são mais comuns que tuplas, principalmente porque são mutáveis. Mas aqui são alguns
casos em que você pode preferir tuplas:
1. Em alguns contextos, como uma instrução return, é sintaticamente mais simples criar
uma tupla do que uma lista. Em outros contextos, você pode preferir uma lista.
2. Se você quiser usar uma sequência como uma chave de dicionário, você deve usar um
tipo mutável como uma tupla ou string.
3. Se você estiver passando uma sequência como argumento para uma função, usando
tuplas você reduz o potencial de comportamento inesperado devido ao aliasing.
Como as tuplas são imutáveis, elas não fornecem métodos como sort e reverse, que
modificam as listas existentes. No entanto, o Python fornece as funções integradas
classificadas e inversas, que pegam qualquer sequência como parâmetro e retornam uma nova
sequência com os mesmos elementos em uma ordem diferente.
10.9 Depuração
Listas, dicionários e tuplas são conhecidos genericamente como estruturas de dados; nesse
capítulo, estamos começando a ver estruturas de dados compostas, como listas de tuplas, e
dicionários que contêm tuplas como chaves e listas como valores. Estrutura de dados
compostos são úteis, mas são propensas ao que chamo de erros de forma; ou seja, erros
causados quando uma estrutura de dados tem o tipo, tamanho ou composição errados, ou
talvez você escreve algum código e esquece a forma de seus dados e introduz um erro.
Por exemplo, se você está esperando uma lista com um inteiro e eu lhe der um simples inteiro
(não em uma lista), não funcionará.
Reading Examine seu código, leia-o para si mesmo e verifique se ele diz o que você quis
dizer.
Remoendo Tire um tempo para pensar! Que tipo de erro é: sintaxe, tempo de execução,
semântico? Quais informações você pode obter das mensagens de erro ou da saída do
programa? Que tipo de erro pode causar o problema que você está vendo? O que você mudou
por último, antes do problema aparecer?
Recuar Em algum momento, o melhor a fazer é recuar, desfazer as mudanças recentes, até
chegar a um programa que funcione e que você entenda. Então você pode começar a
reconstruir.
Por exemplo, ler seu código pode ajudar se o problema for um erro tipográfico, mas não se o
problema for um mal-entendido conceitual. Se você não entender o que seu programa faz,
você pode lê-lo 100 vezes e nunca ver o erro, porque o erro está na sua cabeça.
Você tem que ter tempo para pensar. A depuração é como uma ciência experimental. Você
deve ter pelo menos uma hipótese sobre qual é o problema. Se houver dois ou mais
possibilidades, tente pensar em um teste que eliminaria uma delas.
Fazer uma pausa ajuda a pensar. Falar também. Se você explicar o problema para outra pessoa
(ou até para si mesmo), às vezes você encontrará a resposta antes que você termine de fazer a
pergunta.
Mas mesmo as melhores técnicas de depuração falharão se houver muitos erros ou se o
código que você está tentando corrigir for muito grande e complicado. Às vezes a melhor
opção é recuar, simplificando o programa até chegar a algo que funcione, e nisso, entendendo
o programa.
Os programadores iniciantes muitas vezes relutam em recuar porque não suportam, exclua
uma linha de código (mesmo que esteja errado). Se isso faz você se sentir melhor, copie seu
programa em outro arquivo antes de começar a desmontá-lo. Então você pode colar as peças
de volta um pouco de cada vez.
Encontrar um erro difícil requer leitura, corrida, ruminação e, às vezes, retirada. Se você ficar
preso em uma dessas atividades, tente as outras.
10.10 Glossário
Comparável - Um tipo onde um valor pode ser verificado para ver se é maior, menor ou igual a
outro valor do mesmo tipo. Tipos que são comparável pode ser colocado em uma lista e
classificado.
Hashable - Um tipo que tem uma função de hash. Tipos imutáveis como inteiros, flutuantes, e
strings são passíveis de hash; tipos mutáveis como listas e dicionários não são.
Dispersão - A operação de tratar uma sequência como uma lista de argumentos. forma (de
uma estrutura de dados) Um resumo do tipo, tamanho e composição de uma estrutura de
dados.
Atribuição de tupla - Uma atribuição com uma sequência no lado direito e uma tupla de
variáveis à esquerda. O lado direito é avaliado e então seus elementos são atribuído às
variáveis à esquerda.
10.11 Exercícios
Exercício 1: Revise um programa anterior da seguinte forma: Leia e analise o “From” linhas e
retire os endereços da linha. Conte o número de mensagens de cada pessoa usando um
dicionário.
Após todos os dados terem sido lidos, imprima a pessoa com mais commits criando uma lista
de tuplas (count, email) do dicionário. Em seguida, classifique a lista em ordem inversa e
imprima a pessoa que tem mais commits.
Sample Line:
cwen@iupui.edu 5
zqian@umich.edu 195
Exercício 2: Este programa conta a distribuição da hora do dia para cada uma das mensagens.
Você pode extrair a hora da linha “from” encontrando a hora string e, em seguida, dividindo
essa string em partes usando o caractere de dois pontos. Uma vez que você acumulou as
contagens para cada hora, imprima as contagens, uma por linha, classificados por hora,
conforme mostrado abaixo.
Exemplo de Execução:
python timeofday.py
04 3
06 1
07 1
09 2
10 3
11 6
14 1
15 2
16 4
17 2
18 1
19 1
Essa tarefa de pesquisar e extrair é tão comum que o Python tem uma ferramenta muito
poderosa na biblioteca chamada expressões regulares que lida com muitas dessas tarefas de
maneira bastante elegante. A razão pela qual não introduzimos expressões regulares
anteriormente neste e-book é porque embora sejam muito poderosos, são um pouco
complicados e sua sintaxe leva alguns tempo para ir se acostumando.
As expressões regulares são quase sua própria linguagem de programação para pesquisa e
analisar cadeias de caracteres. Na verdade, livros inteiros foram escritos sobre o tópico de
expressões regulares. Neste capítulo, abordaremos apenas os fundamentos das expressões.
Para obter mais detalhes sobre expressões regulares, consulte:
http://en.wikipedia.org/wiki/Regular_expression
https://docs.python.org/2/library/re.html
A biblioteca de expressões regulares deve ser importada para o seu programa antes de você
poder usá-la. O uso mais simples da biblioteca de expressões regulares é a função search(). O
programa a seguir demonstra um uso trivial da função de pesquisa.
import re
hand = open('mbox-short.txt')
line = line.rstrip()
if re.search('From:', line):
print(line)
# Code: http://www.pythonlearn.com/code3/re01.py
Abrimos o arquivo, percorremos cada linha e usamos a expressão regular search() para
imprimir apenas as linhas que contêm a string “From:”. Este programa não usa o poder real
das expressões regulares, já que poderíamos facilmente ter usado line.find() para obter o
mesmo resultado.
O poder das expressões regulares surge quando adicionamos caracteres especiais a string de
pesquisa que nos permite controlar com mais precisão quais linhas correspondem a corda.
Adicionar esses caracteres especiais à nossa expressão regular nos permite fazer combinação e
extração sofisticadas ao escrever muito pouco código.
import re
hand = open('mbox-short.txt')
line = line.rstrip()
if re.search('^From:', line):
print(line)
# Code: http://www.pythonlearn.com/code3/re02.py
Agora, apenas corresponderemos às linhas que começam com a string “From:”. Isso ainda é
um exemplo muito simples que poderíamos ter feito de forma equivalente com o método
startwith() da biblioteca de strings. Mas serve para introduzir a noção de que regular
expressões contêm caracteres de ação especiais que nos dão mais controle sobre o que
corresponderá à expressão regular.
No exemplo a seguir, a expressão regular “F..m:” corresponderia a qualquer uma das strings
“From:”, “Fxxm:”, “F12m:” ou “F!@m:” desde que os caracteres de ponto na expressão regular
corresponde a qualquer caractere.
import re
hand = open('mbox-short.txt')
for line in hand:
line = line.rstrip()
if re.search('^F..m:', line):
print(line)
# Code: http://www.pythonlearn.com/code3/re03.py
import re
hand = open('mbox-short.txt')
line = line.rstrip()
if re.search('^From:.+@', line):
print(line)
# Code: http://www.pythonlearn.com/code3/re04.py
A string de pesquisa “ˆFrom:.+@” corresponderá com sucesso às linhas que começam com
“from:”, seguido de um ou mais caracteres (“.+”), seguido de arroba. Então isso corresponderá
à seguinte linha:
From: uct.ac.za
Você pode pensar no curinga “.+” como uma expansão para corresponder a todos os
caracteres entre o caractere de dois pontos e o sinal de arroba.
From:
É bom pensar nos caracteres de adição e asterisco como “agressivos”. Por exemplo, a
sequência a seguir corresponderia ao último sinal de arroba na sequência conforme o “.+”
empurra para fora, como mostrado abaixo:
From: iupui.edu
É possível dizer a um asterisco ou sinal de mais para não ser tão “ganancioso” adicionando
outro personagem. Consulte a documentação detalhada para obter informações sobre como
desligar o comportamento ganancioso.
Return-Path: <postmaster@collab.sakaiproject.org>
for <source@collab.sakaiproject.org>;
Author: stephen.marquard@uct.ac.za
Não queremos escrever código para cada um dos tipos de linhas, divisão e corte diferente para
cada linha. Este programa a seguir usa findall () para encontrar as linhas com endereços de e-
mail neles e extraia um ou mais endereços de cada uma dessas linhas.
import re
lst = re.findall('\S+@\S+', s)
print(lst)
# Code: http://www.pythonlearn.com/code3/re05.py
O método findall() procura a string no segundo argumento e retorna uma lista de todas as
strings que se parecem com endereços de e-mail. Estamos usando um de dois caracteres
sequênciais que corresponde a uma caractere sem espaço em branco (\\S).
['csev@umich.edu', 'cwen@iupui.edu']
Traduzindo a expressão regular, procuramos substrings que tenham pelo menos um caractere
que não seja um espaço em branco, seguido por um sinal de arroba, seguido por pelo menos
um ou mais caracteres sem espaço em branco. O “\\S+” corresponde a tantos espaços que não
estão em branco possíveis.
import re
hand = open('mbox-short.txt')
line = line.rstrip()
x = re.findall('\S+@\S+', line)
if len(x) > 0:
print(x)
# Code: http://www.pythonlearn.com/code3/re06.py
Lemos cada linha e extraímos todas as substrings que correspondem a nossa expressão. Como
findall() retorna uma lista, simplesmente verificamos se o número de elementos em nossa lista
retornada é maior que zero para imprimir apenas as linhas onde encontramos pelo menos
uma substring que se pareça com um endereço de e-mail.
['wagnermr@iupui.edu']
['cwen@iupui.edu']
['<postmaster@collab.sakaiproject.org>']
['<200801032122.m03LMFo4005148@nakamura.uits.iupui.edu>']
['<source@collab.sakaiproject.org>;']
['<source@collab.sakaiproject.org>;']
['<source@collab.sakaiproject.org>;']
['apache@localhost)']
['source@collab.sakaiproject.org;']
Alguns de nossos endereços de e-mail possuem caracteres incorretos como “<” ou “;” no
começo ou no fim. Vamos declarar que estamos interessados apenas na parte da string que
começa e termina com uma letra ou um número.
Para fazer isso, usamos outro recurso de expressões regulares. Colchetes são usado para
indicar um conjunto de vários caracteres aceitáveis que estamos dispostos a considerar
coincidindo. De certo modo, o “\\S” está pedindo para corresponder ao conjunto de “não
espaço". Agora seremos um pouco mais explícitos em relação aos personagens que iremos
corresponder.
[a-zA-Z0-9]\S*@\S*[a-zA-Z]
Isso está ficando um pouco complicado e você pode começar a ver por que as expressões
regulares são sua própria linguagem para si mesmos. Traduzindo esta expressão regular,
estamos procurando por substrings que começam com uma única letra minúscula, letra
maiúscula ou número “[a-zA-Z0-9]”, seguido de zero ou mais caracteres não em branco
(“\\S*”), seguido por um sinal de arroba, seguido por zero ou mais caracteres não em branco
(“\\S*”), seguido de letra maiúscula ou minúscula. Observe que trocamos de “+” a “*” para
indicar zero ou mais caracteres não em branco desde “[a-zA-Z0-9]” já é um caractere não em
branco. Lembre-se que o “*” ou “+” se aplica ao único caractere imediatamente à esquerda do
sinal de adição ou asterisco.
Se usarmos essa expressão em nosso programa, nossos dados ficam muito mais limpos:
import re
hand = open('mbox-short.txt')
line = line.rstrip()
x = re.findall('[a-zA-Z0-9]\S+@\S+[a-zA-Z]', line)
if len(x) > 0:
print(x)
# Code: http://www.pythonlearn.com/code3/re07.py
...
['wagnermr@iupui.edu']
['cwen@iupui.edu']
['postmaster@collab.sakaiproject.org']
['200801032122.m03LMFo4005148@nakamura.uits.iupui.edu']
['source@collab.sakaiproject.org']
['source@collab.sakaiproject.org']
['source@collab.sakaiproject.org']
['apache@localhost']
Observe também que a saída do programa é uma lista Python que possui uma string como o
único elemento na lista.
X-DSPAM-Confidence: 0.8475
X-DSPAM-Probability: 0.0000
Não queremos apenas números de ponto flutuante de qualquer linha. Nós só queremos extrair
números de linhas que possuem a sintaxe acima.
Traduzindo isso, estamos dizendo, queremos linhas que comecem com “X-”, seguido de zero
ou mais caracteres (“.*”), seguidos de dois pontos (“:”) e depois um espaço. Depois do espaço
em que procuramos um ou mais caracteres que sejam um dígito (0-9) ou um ponto “[0-9.]+”.
Observe que dentro dos colchetes, o ponto corresponde a um período real (ou seja, não é um
curinga entre colchetes).
Esta é uma expressão muito compacta que corresponderá apenas às linhas que estamos
interessado da seguinte forma:
import re
hand = open('mbox-short.txt')
line = line.rstrip()
print(line)
# Code: http://www.pythonlearn.com/code3/re10.py
Quando executamos o programa, vemos os dados bem filtrados para mostrar apenas as linhas
que estamos procurando.
X-DSPAM-Confidence: 0.8475
X-DSPAM-Probability: 0.0000
X-DSPAM-Confidence: 0.6178
X-DSPAM-Probability: 0.0000
Mas agora temos que resolver o problema de extrair os números. Enquanto isso ser simples o
suficiente para usar split, podemos usar outro recurso de expressões regulares para pesquisar
e analisar a linha ao mesmo tempo.
Parênteses são outro caractere especial em expressões regulares. Quando você adiciona
parênteses a uma expressão regular, eles são ignorados ao corresponder à string. Mas quando
você está usando findall (), os parênteses indicam que, embora você queira a expressão inteira
para corresponder, você só está interessado em extrair uma parte da substring que
corresponde à expressão regular.
# Procure por linhas que começam com 'X' seguido por qualquer
import re
hand = open('mbox-short.txt')
line = line.rstrip()
if len(x) > 0:
print(x)
# Code: http://www.pythonlearn.com/code3/re11.py
Em vez de chamar search (), adicionamos parênteses em torno da parte da expressão regular
que representa o número de ponto flutuante para indicar que queremos apenas o findall ()
para nos devolver a parte do número de ponto flutuante da corda correspondente.
['0.8475']
['0.0000']
['0.6178']
['0.0000']
['0.6961']
['0.0000']
..
Os números ainda estão em uma lista e precisam ser convertidos de strings para pontos
flutuantes, vamos usamos o poder das expressões regulares para pesquisar e extrair as
informações que achamos interessantes.
Como no outro exemplo dessa técnica, se você olhar para o arquivo, verá várias linhas do
formulário:
Details: http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772
Se quiséssemos extrair todos os números de revisão (o número inteiro no final dessas linhas)
usando a mesma técnica acima, poderíamos escrever o seguinte programa:
import re
hand = open('mbox-short.txt')
line = line.rstrip()
x = re.findall('^Details:.*rev=([0-9.]+)', line)
if len(x) > 0:
print(x)
# Code: http://www.pythonlearn.com/code3/re12.py
Traduzindo nossa expressão regular, estamos procurando por linhas que começam com “De-
tails:”, seguido por qualquer número de caracteres (“.*”), seguido por “rev=” e então por um
ou mais dígitos. Queremos encontrar linhas que correspondam à expressão inteira, mas
queremos apenas extrair o número inteiro no final da linha, então cercamos “[0-9]+” com
parênteses.
['39772']
['39771']
['39770']
['39769']
...
Lembre-se que o “[0-9]+” é “ganancioso” e tenta fazer uma string tão grande quanto dígitos
possível antes de extrair esses dígitos. Esse comportamento “ganancioso” é o motivo pelo qual
obter todos os cinco dígitos para cada número. A biblioteca de expressões regulares se
expande em ambas as direções até encontrar um não-dígito, ou o início ou o fim de uma linha.
Agora podemos usar expressões regulares para refazer um exercício anterior no e-book onde
estávamos interessados na hora do dia de cada mensagem de correio. Nós procuramos por
linhas do formulário:
Vamos extrair a hora do dia para cada linha. Anteriormente nós fizemos isso com duas
chamadas para dividir. Primeiro a linha foi dividida em palavras e depois puxamos a quinta
palavra e divida-a novamente no caractere de dois pontos para retirar os dois personagens nos
quais estávamos interessados.
Embora isso tenha funcionado, na verdade resulta em um código bastante frágil que assume
as linhas bem formatadas. Se você adicionar verificação de erro suficiente (ou um grande
pente/exceto bloco) para garantir que seu programa nunca falhe quando apresentado com
linhas formatadas incorretamente, o código aumentaria para 10 a 15 linhas de código que
foram bem difícil de ler.
Podemos fazer isso de uma maneira muito mais simples com a seguinte expressão regular:
^From .* [0-9][0-9]:
A tradução dessa expressão regular é que estamos procurando por linhas que começam com
“from” (observe o espaço), seguido de qualquer número de caracteres (“.*”), seguido por um
espaço, seguido de dois dígitos “[0-9][0-9]”, seguido de dois pontos. Esse é a definição dos
tipos de linhas que estamos procurando.
Para extrair apenas a hora usando findall(), adicionamos parênteses ao redor dos dois dígitos
da seguinte forma:
^From .* ([0-9][0-9]):
import re
hand = open('mbox-short.txt')
line = line.rstrip()
# Code: http://www.pythonlearn.com/code3/re13.py
['09']
['18']
['16']
['15']
...
import re
y = re.findall('\$[0-9.]+',x)
Como prefixamos o cifrão com uma barra invertida, ele realmente corresponde ao dólar a
string de entrada em vez de corresponder ao “fim da linha” e o restante da expressão regular
corresponde a um ou mais dígitos ou ao caractere de ponto. Observação: Dentro de colchetes,
os caracteres não são “especiais”. Então, quando dizemos “[0-9.]”, realmente significa dígitos
ou um ponto. Fora dos colchetes, um ponto é o “wild-card” e corresponde a qualquer
caractere. Dentro de colchetes, o período é um periodo.
11.5 Resumo
Embora isso apenas tenha arranhado a superfície das expressões regulares, aprendemos um
pouco sobre a linguagem de expressões regulares. Eles são strings de pesquisa com caracteres
especiais que comunicam seus desejos ao sistema de expressão regular quanto ao que define
“correspondência” e o que é extraído das strings correspondentes.
* Aplica-se ao caractere imediatamente anterior e indica que corresponde a zero ou mais do(s)
caractere(s) anterior(es).
[aeiou] Corresponde a um único caractere desde que esse caractere esteja no conjunto
especificado. Neste exemplo, corresponderia a “a”, “e”, “i”, “o” ou “u”, mas nenhum outro
caractere.
[a-z0-9] Você pode especificar intervalos de caracteres usando o sinal de menos. Este exemplo
é um único caractere que deve ser uma letra minúscula ou um dígito.
( ) Quando parênteses são adicionados a uma expressão regular, eles são ignorados para o
propósito de correspondência, mas permitem que você extraia um subconjunto específico do
correspondente string em vez de toda a string ao usar findall ().
\\b Corresponde à string vazia, mas apenas no início ou no final de uma palavra.
\\B Corresponde à string vazia, mas não no início ou no final de uma palavra.
From: stephen.marquard@uct.ac.za
From: louis@media.berkeley.edu
From: zqian@umich.edu
From: rjlowe@iupui.edu
Isso diz ao grep para mostrar as linhas que começam com a string “From:” no arquivo mbox-
short.txt. Se você experimentar um pouco o comando grep e ler a documentação para grep,
você encontrará algumas diferenças sutis entre o suporte regular e a expressões em Python e
suporte a expressões regulares em grep. como um exemplo, grep não suporta o caractere não
em branco “\\S” então você precisará para usar a notação de conjunto um pouco mais
complexa “[ˆ]”, que significa simplesmente combinar um caractere que não seja um espaço.
11.7 Depuração
Python tem alguma documentação interna simples e rudimentar que pode ser bastante útil se
você precisar de uma atualização rápida para acionar sua memória sobre o nome exato de um
determinado método. Esta documentação pode ser visualizada no interpretador Python no
modo interativo.
help> modules
Se você sabe qual módulo deseja usar, pode usar o comando dir() para encontrar os métodos
no módulo da seguinte maneira:
>>> import re
>>> dir(re)
Você também pode obter uma pequena quantidade de documentação sobre um método
específico usando o comando dir.
>>>
A documentação integrada não é muito extensa, mas pode ser útil quando você está com
pressa ou não tem acesso a um navegador ou mecanismo de pesquisa.
11.8 Glossário
Código frágil - Código que funciona quando os dados de entrada estão em um formato
específico, mas é propenso a quebrar se houver algum desvio do formato correto. Nós
chamamos isso de “código frágil” porque é facilmente quebrado.
Grep - Um comando disponível na maioria dos sistemas Unix que pesquisa arquivos de texto
procurando linhas que correspondam a expressões regulares. O nome do comando fica para
“analisador generalizado de expressões regulares”.
Expressão regular - Uma linguagem para expressar cadeias de pesquisa mais complexas. A
expressão regular pode conter caracteres especiais que indicam que uma pesquisa
corresponde apenas no início ou no final de uma linha ou muitos outros recursos e habilidades
semelhantes.
11.9 Exercícios
Exercício 1: Escreva um programa simples para simular a operação do comando grep, mando
no Unix. Peça ao usuário para inserir uma expressão regular e contar o número de linhas que
correspondem à expressão regular:
$ python grep.py
$ python grep.py
$ python grep.py
E extraia o número de cada uma das linhas usando uma expressão regular e o método findall().
Calcule a média dos números e imprima a média.
Enter file:mbox.txt
38549.7949721
Enter file:mbox-short.txt
39756.9259259
Capítulo 12
Programas em rede
Embora muitos dos exemplos neste livro se concentrem na leitura de arquivos e na procura
para dados nesses arquivos, existem muitas fontes diferentes de informação quando se
considera a Internet.
Neste capítulo, vamos fingir ser um navegador da Web e recuperar páginas da Web usando
protocolo de transporte de hipertexto (HTTP). Então vamos ler através da web dados da
página e analisá-los.
Um soquete é muito parecido com um arquivo, exceto que um único soquete fornece uma
conexão bidirecional entre dois programas. Você pode ler e gravar no mesmo soquete. Se você
escrever algo em um soquete, ele será enviado para o aplicativo na outra extremidade da
tomada. Se você ler o soquete, receberá os dados que o outro aplicativo enviou.
Mas se você tentar ler um soquete quando o programa na outra extremidade do soquete não
enviou nenhum dado, você apenas senta e espera. Se os programas em ambas as
extremidades do soquete simplesmente espere por alguns dados sem enviar nada, eles vão
esperar por muitoooo tempo.
Portanto, uma parte importante dos programas que se comunicam pela Internet é ter algum
tipo de protocolo. Um protocolo é um conjunto de regras precisas que determinam quem é de
ir primeiro, o que eles devem fazer e, em seguida, quais são as respostas a essa mensagem, e
quem envia a seguir, e assim por diante. De certa forma, os dois aplicativos em cada
extremidade do soquete está dançando e tomando cuidado para não pisar no pé um do outro.
http://www.w3.org/Protocols/rfc2616/rfc2616.txt
Este é um documento longo e complexo de 176 páginas com muitos detalhes. Se você achar
interessante, sinta-se livre para ler tudo. Mas se você der uma olhada na página 36 do
RFC2616, você encontrará a sintaxe para a solicitação GET. Para solicitar um documento de um
servidor web, fazemos uma conexão com o servidor www.pythonlearn.com em porta 80 e, em
seguida, envie uma linha do formulário
GET http://data.pr4e.org/romeo.txt HTTP/1.0
Onde o segundo parâmetro é a página da web que estamos solicitando e também envie uma
linha em branco. O servidor web responderá com algumas informações de cabeçalho sobre o
documento e uma linha em branco seguida do conteúdo do documento.
import socket
mysock.connect(('data.pr4e.org', 80))
mysock.send(cmd)
while True:
data = mysock.recv(512)
break
print(data.decode())
mysock.close()
# Code: http://www.pythonlearn.com/code3/socket1.py
Depois de enviarmos essa linha em branco, escrevemos um loop que recebe dados em 512
caracteres pedaços do soquete e imprime os dados até que não haja mais dados para ler (ou
seja, o recv() retorna uma string vazia).
HTTP/1.1 200 OK
ETag: "143c1b33-a7-4b395bea"
Accept-Ranges: bytes
Content-Length: 167
Connection: close
Content-Type: text/plain
A saída começa com cabeçalhos que o servidor web envia para descrever o documento. Por
exemplo, o cabeçalho Content-Type indica que o documento é um documento de texto
simples (texto/simples).
Depois que o servidor nos envia os cabeçalhos, ele adiciona uma linha em branco para indicar
o final dos cabeçalhos e, em seguida, envia os dados reais do arquivo romeo.txt.
Este exemplo mostra como fazer uma conexão de rede de baixo nível com soquetes. Sockets
podem ser usados para se comunicar com um servidor web ou com um servidor de correio ou
muitos outros tipos de servidores. Basta encontrar o documento que descreve o protocolo e
escreve o código para enviar e receber os dados de acordo com o protocolo.
No entanto, como o protocolo que usamos com mais frequência é o protocolo da Web HTTP,
Python tem uma biblioteca especial projetada especificamente para suportar o protocolo HTTP
para a recuperação de documentos e dados na web.
import time
HOST = 'data.pr4e.org'
PORT = 80
mysock.connect((HOST, PORT))
count = 0
picture = b""
while True:
data = mysock.recv(5120)
time.sleep(0.25)
print(len(data), count)
mysock.close()
pos = picture.find(b"\r\n\r\n")
print(picture[:pos].decode())
picture = picture[pos+4:]
fhand.write(picture)
fhand.close()
# Code: http://www.pythonlearn.com/code3/urljpeg.py
2920 2920
1460 4380
1460 5840
1460 7300
...
1460 62780
1460 64240
2920 67160
1460 68620
1681 70301
HTTP/1.1 200 OK
Server: Apache
ETag: "19c141-111a9-4ea280f8354b8"
Accept-Ranges: bytes
Content-Length: 70057
Connection: close
Content-Type: image/jpeg
Você pode ver que, para esta URL, o cabeçalho Content-Type indica o corpo do documento
que é uma imagem (image/jpeg). Assim que o programa for concluído, você poderá visualizar
os dados da imagem abrindo o arquivo stuff.jpg em um visualizador de imagens.
À medida que o programa é executado, você pode ver que não obtemos 5120 caracteres toda
vez, chamamos o método recv(). Recebemos tantos personagens quanto foram transferidos
através da rede para nós pelo servidor web no momento em que chamamos recv(). Nisso, Por
exemplo, obtemos 1460 ou 2920 caracteres cada vez que solicitamos até 5120 caracteres de
dados.
Seus resultados podem ser diferentes dependendo da velocidade da sua rede. Observe
também que ema última chamada para recv() obtemos 1681 bytes, que é o fim do fluxo, e na
próxima chamada para recv(), obtemos uma string de comprimento zero que nos diz que o
servidor chamado close () em sua extremidade do soquete e não há mais dados futuros.
Podemos desacelerar nossas chamadas recv() sucessivas descomentando a chamada para hora
de dormir(). Desta forma, esperamos um quarto de segundo após cada chamada para que o
servidor possa “ficar à frente” de nós e enviar mais dados para nós antes de chamarmos recv()
de novo. Com o delay, no lugar o programa executa da seguinte forma:
$ python urljpeg.py
1460 1460
5120 6580
5120 11700
...
5120 62900
5120 68020
2281 70301
HTTP/1.1 200 OK
Server: Apache
ETag: "19c141-111a9-4ea280f8354b8"
Accept-Ranges: bytes
Content-Length: 70057
Connection: close
Content-Type: image/jpeg
Agora, além da primeira e da última chamada para recv (), agora temos 5120 caracteres cada
vez que pedimos novos dados.
Existe um buffer entre o servidor que faz as solicitações send() e nosso aplicativo, fazendo
requisições recv(). Quando executamos o programa com o atraso no lugar, em algum
momento, o servidor pode preencher o buffer no soquete e ser forçado a pausar até que
nosso programa comece a esvaziar o buffer. A pausa do envio do aplicativo ou o aplicativo
receptor é chamado de “controle de fluxo”.
12.4 Recuperando páginas da web com urllib
Embora possamos enviar e receber dados manualmente por HTTP usando a biblioteca de
soquetes, existe uma maneira muito mais simples de executar essa tarefa comum em Python
usando o método biblioteca urllib.
Usando urllib, você pode tratar uma página da web como um arquivo. Você simplesmente
indica qual página da web você gostaria de recuperar e urllib lida com todo o HTTP protocolo e
detalhes do cabeçalho.
O código equivalente para ler o arquivo romeo.txt da web usando urllib é como segue:
fhand = urllib.request.urlopen('http://data.pr4e.org/romeo.txt')
print(line.decode().strip())
# Code: http://www.pythonlearn.com/code3/urllib1.py
Depois que a página da Web for aberta com urllib.urlopen, podemos tratá-la como um arquivo
e leia-o usando um loop for.
counts = dict()
fhand = urllib.request.urlopen('http://data.pr4e.org/romeo.txt')
words = line.decode().split()
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts)
# Code: http://www.pythonlearn.com/code3/urlwords.py
Novamente, depois de abrir a página da Web, podemos lê-la como um arquivo local.
O Google também usa a frequência de links das páginas que encontra para uma página
específica como uma medida de quão “importante” é uma página e quão alta a página deve
aparecer em seus resultados de pesquisa.
<p>
<a href="http://www.dr-chuck.com/page2.htm">
Second Page</a>.
</p>
Podemos construir uma expressão regular bem formada para corresponder e extrair o link e
valores do texto acima da seguinte forma:
href=http://.+?
Nossa expressão regular procura strings que começam com “href=”http://“, seguidas por um
ou mais caracteres (”.+¿'), seguido de outra aspa dupla. A questão marcada adicionada com
".+?" indica que a correspondência deve ser feita de forma "não gananciosa" moderada em vez
de um modo “ganancioso”. Uma correspondência não gulosa tenta encontrar a menor
sequência de correspondência possível e uma correspondência gulosa tenta encontrar a maior
cadeia correspondente possível.
Adicionamos parênteses à nossa expressão regular para indicar qual parte de nossa
correspondência string que gostaríamos de extrair e produzir o seguinte programa:
import re
html = urllib.request.urlopen(url).read()
print(link.decode())
# Code: http://www.pythonlearn.com/code3/urlregex.py
O método de expressão regular findall nos dará uma lista de todas as strings que
correspondem à nossa expressão regular, retornando apenas o texto do link entre a dupla
citações.
python urlregex.py
Enter - http://www.dr-chuck.com/page1.htm
http://www.dr-chuck.com/page2.htm
python urlregex.py
Enter - http://www.pythonlearn.com/book.htm
http://www.greenteapress.com/thinkpython/thinkpython.html
http://allendowney.com/
http://www.pythonlearn.com/code
http://www.lib.umich.edu/espresso-book-machine
http://www.pythonlearn.com/py4inf-slides.zip
Expressões regulares funcionam muito bem quando seu HTML está bem formatado e
previsível. Mas como existem muitas páginas HTML "quebradas" por aí, uma solução é usar
apenas expressões regulares que pode perder alguns links válidos ou acabar com dados ruins.
Isso pode ser resolvido usando uma biblioteca de análise de HTML robusta.
Como exemplo, vamos simplesmente analisar algumas entradas HTML e extrair links usando a
biblioteca BeautifulSoup. Você pode baixar e instalar o código BeautifulSoup em:
http://www.crummy.com/software/
Mesmo que o HTML se pareça com o XML e algumas páginas são cuidadosamente construídas
para ser XML, a maioria do HTML geralmente é quebrada de maneiras que causam um
analisador de XML rejeitar toda a página de HTML como formada incorretamente.
BeautifulSoup tolera HTML altamente falho e ainda permite que você extraia facilmente os
dados de que precisa.
Usaremos o urllib para ler a página e depois usaremos o BeautifulSoup para extrair os
atributos href das tags âncoras.
# https://pypi.python.org/pypi/beautifulsoup4
# Ou baixe o arquivo
# http://www.pythonlearn.com/code3/bs4.zip
tags = soup('a')
print(tag.get('href', None))
# Code: http://www.pythonlearn.com/code3/urllinks.py
O programa solicita um endereço da web, abre a página da web, lê os dados e passa os dados
para o analisador BeautifulSoup e, em seguida, recupera todas as tags âncora e imprime o
atributo href para cada tag.
python urllinks.py
Enter - http://www.dr-chuck.com/page1.htm
http://www.dr-chuck.com/page2.htm
python urllinks.py
Enter - http://www.pythonlearn.com/book.htm
http://www.greenteapress.com/thinkpython/thinkpython.html
http://allendowney.com/
http://www.si502.com/
http://www.lib.umich.edu/espresso-book-machine
http://www.pythonlearn.com/code
http://www.pythonlearn.com/
Você pode usar o BeautifulSoup para extrair várias partes de cada tag da seguinte maneira:
# https://pypi.python.org/pypi/beautifulsoup4
# Ou baixe o arquivo
# http://www.pythonlearn.com/code3/bs4.zip
html = urlopen(url).read()
# http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser
tags = soup('a')
print('TAG:', tag)
print('Contents:', tag.contents[0])
print('Attrs:', tag.attrs)
# Code: http://www.pythonlearn.com/code3/urllink2.py
python urllink2.py
Enter - http://www.dr-chuck.com/page1.htm
Second Page</a>
URL: http://www.dr-chuck.com/page2.htm
O padrão é abrir a URL e usar read para baixar todo o conteúdo do documento em uma
variável de string (img) e, em seguida, escreva essa informação em um arquivo local da
seguinte forma:
img = urllib.request.urlopen('http://data.pr4e.org/cover.jpg').read()
fhand.write(img)
fhand.close()
# Code: http://www.pythonlearn.com/code3/curl1.py
12.9. GLOSSÁRIO
Este programa lê todos os dados de uma só vez na rede e os armazena na variável img na
memória principal do seu computador, em seguida abre o arquivo cover.jpg e grava os dados
em seu disco. Isso funcionará se o tamanho do arquivo for menor do que o tamanho da
memória do seu computador.
No entanto, se este for um arquivo de áudio ou vídeo grande, este programa pode travar ou
pelo menos executado extremamente lentamente quando o computador fica sem memória. A
fim de evitar ficar sem memória, recuperamos os dados em blocos (ou buffers) e então
escrevemos cada bloco em seu disco antes de recuperar o próximo bloco. Desta forma o
programa pode ler qualquer arquivo de tamanho sem usar toda a memória que você tem em
seu computador.
img = urllib.request.urlopen('http://data.pr4e.org/cover.jpg')
size = 0
while True:
info = img.read(100000)
fhand.close()
# Code: http://www.pythonlearn.com/code3/curl2.py
Neste exemplo, lemos apenas 100.000 caracteres por vez e escrevemos os caracteres para o
arquivo cover.jpg antes de recuperar os próximos 100.000 caracteres de dados da web.
python curl2.py
curl -O http://www.pythonlearn.com/cover.jpg
O comando curl é a abreviação de “copiar URL” e, portanto, esses dois exemplos são
habilmente chamados curl1.py e curl2.py em www.pythonlearn.com/code à medida que
implementam funcionalidade semelhante ao comando curl. Há também uma amostra do
programa curl3.py que faz essa tarefa com um pouco mais de eficiência, caso você realmente
queira, use esse padrão em um programa que você está escrevendo.
12.9 Glossário
BeautifulSoup - Uma biblioteca Python para analisar documentos HTML e extrair dados de
documentos HTML que compensam a maioria das imperfeições no HTML que os navegadores
geralmente ignoram. Você pode baixar o código Beautifulsoup em www.crummy.com.
Porta - Um número que geralmente indica qual aplicativo você está contatando quando você
faz uma conexão de soquete com um servidor. Por exemplo, o tráfego da web geralmente usa
a porta 80 enquanto o tráfego de e-mail usa a porta 25.
Scrape - Quando um programa finge ser um navegador da web e recupera uma página da web,
em seguida, examina o conteúdo da página da web. Frequentemente, os programas seguem
os links em uma página para encontrar a próxima página para que possam percorrer uma rede
de páginas ou uma rede social.
Socket - Uma conexão de rede entre dois aplicativos onde os aplicativos podem enviar e
receber dados em qualquer direção.
Spider - O ato de um mecanismo de pesquisa da Web, recuperar uma página e, em seguida,
todas as páginas vinculados de uma página e assim por diante até que tenham quase todas as
páginas da Internet que eles usam para construir seu índice de pesquisa.
12.10 Exercícios
Exercício 1: Altere o programa socket socket1.py para solicitar ao usuário a URL para que ele
possa ler qualquer página da web. Você pode usar split('/') para dividir a URL em duas partes
componentes para que você possa extrair o nome do host para a chamada de conexão de
soquete. Adicione a verificação de erros usando try e except para lidar com a condição em que
o usuário insere uma URL formatando incorretamente ou inexistente.
Exercício 2: Altere seu programa de soquete para que ele conte o número de caracteres dados
que recebeu e para de exibir qualquer texto depois de mostrar 3.000 caracteres. O programa
deve recuperar o documento inteiro e contar o número total de caracteres e exibir a contagem
do número de caracteres no final do documento.
Exercício 3: Use urllib para replicar o exercício anterior de (1) recuperar o documento de uma
URL, (2) exibindo até 3.000 caracteres e (3) contando o número total de caracteres no
documento. Não se preocupe com os cabeçalhos, Neste exercício, basta mostrar os primeiros
3.000 caracteres do conteúdo do documento.
Exercício 4: Altere o programa urllinks.py para extrair e contar o parágrafo (p) tags do
documento HTML recuperado e exibir a contagem dos parágrafos como a saída do seu
programa. Não exiba o texto do parágrafo, apenas conte eles. Teste seu programa em várias
páginas da Web pequenas, bem como em algumas páginas da Web Páginas maiores.
Exercício 5: (Avançado) Altere o programa socket para que mostre apenas dados depois que os
cabeçalhos e uma linha em branco forem recebidos. Lembre-se que recv é recebendo
caracteres (novas linhas e tudo), não linhas.
Capítulo 13
Usando serviços da Web
Depois que ficou fácil recuperar documentos e analisar documentos por HTTP usando
programas, não demorou muito para desenvolver uma abordagem onde começaram a
produzir documentos que foram especificamente concebidos para serem consumidos por
outros programas (ou seja, não HTML para ser exibido em um navegador).
Existem dois formatos comuns que usamos ao trocar dados pela web. A “eXtensible Markup
Language” ou XML que está em uso há muito tempo e é mais adequado para troca de dados
em estilo de documento. Quando os programas só querem trocar dicionários, listas ou outras
informações internas entre si, eles usam JavaScript Object Notation ou JSON (consulte
www.json.org). Vamos olhar para os dois formatos.
<person>
<name>Chuck</name>
<phone type="intl">
</phone>
<email hide="yes"/>
</person>
Muitas vezes é útil pensar em um documento XML como uma estrutura de árvore onde é uma
pessoa de marca principal e outras marcas, como telefone, são desenhadas como filhos de
seus pais.
13.2 Analisando XML
Aqui está um aplicativo simples que analisa algum XML e extrai alguns elementos de dados do
XML:
import xml.etree.ElementTree as ET
data = '''
<person>
<name>Chuck</name>
<phone type="intl">
</phone>
<email hide="yes"/>
</person>'''
tree = ET.fromstring(data)
print('Name:', tree.find('name').text)
print('Attr:', tree.find('email').get('hide'))
# Code: http://www.pythonlearn.com/code3/xml1.py
A função find pesquisa na árvore XML e recupera um nó que corresponde à tag especificada.
Cada nó pode ter algum texto, alguns atributos (como hide) e alguns nós “filhos”. Cada nó
pode ser o topo de uma árvore de nós.
Name: Chuck
Attr: yes
O uso de um analisador de XML como o ElementTree tem a vantagem de que, embora o XML
neste exemplo é bastante simples, verifica-se que existem muitas regras a respeito XML válido
e usar ElementTree nos permite extrair dados de XML sem preocupando-se com as regras da
sintaxe XML.
13.3 Percorrendo os nós
Muitas vezes, o XML tem vários nós e precisamos escrever um loop para processar todos os
nós. No programa a seguir, percorremos todos os nós do usuário:
import xml.etree.ElementTree as ET
input = '''
<stuff>
<users>
<user x="2">
<id>001</id>
<name>Chuck</name>
</user>
<user x="7">
<id>009</id>
<name>Brent</name>
</user>
</users>
</stuff>'''
stuff = ET.fromstring(input)
lst = stuff.findall('users/user')
print('Name', item.find('name').text)
print('Id', item.find('id').text)
print('Attribute', item.get("x"))
# Code: http://www.pythonlearn.com/code3/xml2.py
O método findall recupera uma lista Python de subárvores que representam o usuário
estruturas na árvore XML. Então podemos escrever um loop for que olhe para cada um dos
nós do usuário e imprime os elementos de texto name e id, bem como o atributo x do nó do
usuário.
User count: 2
Name Chuck
Id 001
Attribute 2
Name Brent
Id 009
Attribute 7
Aqui está uma codificação JSON que é aproximadamente equivalente ao XML simples acima:
"name" : "Chuck",
"phone" : {
"type" : "intl",
},
"email" : {
"hide" : "yes"
Você notará algumas diferenças. Primeiro, em XML, podemos adicionar atributos como “intl”
para a tag "phone". Em JSON, simplesmente temos pares chave-valor. Também o XML a tag
“pessoa” se foi, substituída por um conjunto de chaves externas.
Em geral, estruturas JSON são mais simples que XML porque JSON tem menos capacidades do
que XML. Mas o JSON tem a vantagem de mapear diretamente para algumas combinação de
dicionários e listas. E como quase todas as linguagens de programação têm algo equivalente
aos dicionários e listas do Python, o JSON é uma ural para que dois programas cooperantes
troquem dados.
JSON está rapidamente se tornando o formato de escolha para quase todas as trocas de dados
entre aplicações devido à sua relativa simplicidade em comparação com o XML.
No programa a seguir, usamos a biblioteca json integrada para analisar o JSON e leia os dados.
Compare isso de perto com os dados e códigos XML equivalentes acima. O JSON tem menos
detalhes, então devemos saber com antecedência que estamos obtendo uma list e que a lista
é de usuários e cada usuário é um conjunto de pares chave-valor. o JSON é mais sucinto (uma
vantagem), mas também menos autodescritivo (uma desvantagem).
import json
input = '''
{ "id" : "001",
"x" : "2",
"name" : "Chuck"
},
{ "id" : "009",
"x" : "7",
"name" : "Chuck"
]'''
info = json.loads(input)
print('Name', item['name'])
print('Id', item['id'])
print('Attribute', item['x'])
# Code: http://www.pythonlearn.com/code3/json2.py
Se você comparar o código para extrair dados do JSON e XML analisados, você vera que o que
obtemos de json.loads() é uma lista Python que percorremos com um loop for, e cada item
dessa lista é um dicionário Python. Uma vez que o JSON for analisado, podemos usar o
operador de índice do Python para extrair os vários bits de dados para cada usuário. Não
precisamos usar a biblioteca JSON para vasculhar o JSON analisado, já que os dados retornados
são simplesmente estruturas nativas do Python.
User count: 2
Name Chuck
Id 001
Attribute 2
Name Brent
Id 009
Attribute 7
Em geral, há uma tendência da indústria de afastar-se do XML e em direção ao JSON para web
Serviços. Como o JSON é mais simples e mapeia mais diretamente para estruturas de dados
nativas que já temos em linguagens de programação, a análise e extração de dados, o código
geralmente é mais simples e direto ao usar JSON. Mas o XML é mais auto descritivo do que
JSON e, portanto, há alguns aplicativos em que o XML retém uma vantagem. Por exemplo, a
maioria dos processadores de texto armazena documentos internamente usando XML em vez
de JSON.
O próximo passo é começar a definir e documentar “contratos” entre aplicativos usando essas
técnicas. O nome geral para esses contextos de aplicativo para aplicativo tracts são interfaces
de programas de aplicativos ou APIs. Quando usamos uma API, geralmente um programa
disponibiliza um conjunto de serviços para uso por outros aplicativos e publica as APIs (ou seja,
as “regras”) que devem ser seguidas para acessar os serviços fornecidos pelo programa.
Vemos muitos exemplos de SOA quando usamos a web. Podemos ir para um único web site e
reservar viagens aéreas, hotéis e automóveis, tudo em um único site. Os dados para hotéis não
é armazenado nos computadores das companhias aéreas. Em vez disso, os computadores das
companhias aéreas contata os serviços nos computadores do hotel e recupera os dados do
hotel e apresenta ao usuário. Quando o usuário concorda em fazer uma reserva de hotel
usando o site da companhia aérea, o site da companhia aérea usa outro serviço da web nos
sistemas do hotel para realmente fazer a reserva. E quando chegar a hora de cobrar o valor
total da transação cartão de crédito, ainda outros computadores se envolvem no processo.
Uma arquitetura orientada a serviços tem muitas vantagens, incluindo: (1) sempre manter
apenas uma cópia dos dados (isto é particularmente importante para coisas como hotéis
reservas onde não queremos comprometer em excesso) e (2) os proprietários dos dados
podem definir as regras sobre o uso de seus dados. Com essas vantagens, um SOA o sistema
deve ser cuidadosamente projetado para ter bom desempenho e atender às necessidades do
usuário.
Quando uma aplicação disponibiliza um conjunto de serviços em sua API na web, nós
chamamos esses serviços da web.
O serviço de geocodificação é gratuito, mas com taxa limitada, portanto você não pode fazer
uso ilimitado da API em um aplicativo comercial. Mas se você tiver alguns dados de pesquisa
em que um usuário final inseriu um local em uma caixa de entrada de formato livre, você pode
usar esta API para limpar seus dados muito bem.
Ao usar uma API gratuita como a API de geocodificação do Google, você precisa ser respeitoso
no uso desses recursos. Se muitas pessoas abusarem do serviço, o Google pode reduzir
significativamente seu serviço gratuito.
Você pode ler a documentação online deste serviço, mas é bastante simples e você pode até
testá-lo usando um navegador digitando o seguinte URL em seu navegador:
http://maps.googleapis.com/maps/api/geocode/json?address=Ann+Arbor%2C+MI
Certifique-se de desempacotar a URL e remover todos os espaços do URL antes de colar no seu
navegador.
O seguinte é um aplicativo simples para solicitar ao usuário uma string de pesquisa, chamar a
API de geocodificação do Google e extrair informações do JSON retornado.
import urllib.request, urllib.parse, urllib.error
import json
serviceurl = 'http://maps.googleapis.com/maps/api/geocode/json?'
while True:
print('Retrieving', url)
uh = urllib.request.urlopen(url)
data = uh.read().decode()
try:
js = json.loads(data)
except:
js = None
print(data)
continue
print(json.dumps(js, indent=4))
lat = js["results"][0]["geometry"]["location"]["lat"]
lng = js["results"][0]["geometry"]["location"]["lng"]
location = js['results'][0]['formatted_address']
print(location)
# Code: http://www.pythonlearn.com/code3/geojson.py
O programa pega a string de pesquisa e constrói uma URL com a string de pesquisa como um
parâmetro codificado corretamente e, em seguida, usa urllib para recuperar o texto da API de
geocodificação do Google. Ao contrário de uma página da web fixa, os dados que obtemos
dependem dos parâmetros que enviamos e os dados geográficos armazenados nos servidores
do Google.
Depois de recuperar os dados JSON, nós os analisamos com a biblioteca json e fazemos
algumas verificações para ter certeza de que recebemos bons dados e, em seguida, extraia as
informações que nós estamos procurando.
$ python geojson.py
Retrieving http://maps.googleapis.com/maps/api/
geocode/json?sensor=false&address=Ann+Arbor%2C+MI
"status": "OK",
"results": [
"geometry": {
"location_type": "APPROXIMATE",
"location": {
"lat": 42.2808256,
"lng": -83.7430378
},
"address_components": [
"types": [
"locality",
"political"
],
],
"types": [
"locality",
"political"
Insira o local:
Às vezes, depois de obter sua chave de API, você simplesmente inclui a chave como parte do
POST dados ou talvez como um parâmetro na URL ao chamar a API.
Outras vezes, o fornecedor deseja maior garantia da origem das solicitações, e eles
acrescentam que esperam que você envie mensagens assinadas criptograficamente usando
arquivos compartilhados, chaves e segredos. Uma tecnologia muito comum usada para assinar
solicitações na Internet é chamado OAuth. Você pode ler mais sobre o protocolo OAuth em
www.oauth.net.
À medida que a API do Twitter se tornava cada vez mais valiosa, o Twitter passou de uma
plataforma aberta e API pública para uma API que exigia o uso de assinaturas OAuth em cada
API solicitada. Felizmente, ainda existem várias bibliotecas OAuth convenientes e gratuitas,
então você pode evitar escrever uma implementação OAuth do zero lendo a especificação.
Essas bibliotecas são de complexidade variável e têm graus variados de riqueza. O site OAuth
tem informações sobre várias bibliotecas OAuth.
Para este próximo programa de amostra, faremos o download dos arquivos twurl.py,
hidden.py, oauth.py e twitter1.py de www.pythonlearn.com/code e coloque-os todos em uma
pasta em seu computador.
Para usar esses programas, você precisará ter uma conta no Twitter e autorizar seu código
Python como um aplicativo, configurar uma chave, segredo, token e segredo do token. Você
editará o arquivo hidden.py e colocará essas quatro strings na variáveis apropriadas no
arquivo:
# https://apps.twitter.com/
def oauth():
"consumer_secret" : "dNKenAC3New...mmn7Q",
"token_key" : "10185562-eibxCp9n2...P4GEQQOSGI",
"token_secret" : "H0ycCFemmC4wyf1...qoIpBo"}
# Code: http://www.pythonlearn.com/code3/hidden.py
https://api.twitter.com/1.1/statuses/user_timeline.json
Mas assim que todas as informações de segurança forem adicionadas, a URL parecerá mais
como:
https://api.twitter.com/1.1/statuses/user_timeline.json?count=2
&oauth_version=1.0&oauth_token=101...SGI&screen_name=drchuck
&oauth_nonce=09239679&oauth_timestamp=1380395644
&oauth_signature=rLK...BoD&oauth_consumer_key=h7Lu...GNg
&oauth_signature_method=HMAC-SHA1
Você pode ler a especificação OAuth se quiser saber mais sobre o significado dos vários
parâmetros que são adicionados para atender aos requisitos de segurança do OAuth.
Para os programas que executamos com o Twitter, ocultamos toda a complexidade nos
arquivos oauth.py e twurl.py. Simplesmente definimos os segredos em hidden.py e enviamos a
URL desejada para a função twurl.augment() e o código da biblioteca adiciona todos os
parâmetros necessários para a URL para nós.
import twurl
TWITTER_URL = 'https://api.twitter.com/1.1/statuses/user_timeline.json'
while True:
print('')
url = twurl.augment(TWITTER_URL,
print('Retrieving', url)
connection = urllib.request.urlopen(url)
data = connection.read().decode()
print(data[:250])
headers = dict(connection.getheaders())
# cabeçalhos de impressão
print('Remaining', headers['x-rate-limit-remaining'])
# Code: http://www.pythonlearn.com/code3/twitter1.py
intersections: http:\/\/t.co\/tIiVWtEhj4\n#brilliant",
"source":"web","truncated":false,"in_rep
Remaining 178
"id":384015634108919808,"id_str":"384015634108919808",
"source":"web","truncated":false,
Remaining 177
import twurl
import json
TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json'
while True:
print('')
url = twurl.augment(TWITTER_URL,
{'screen_name': acct, 'count': '5'})
print('Retrieving', url)
connection = urllib.request.urlopen(url)
data = connection.read().decode()
headers = dict(connection.getheaders())
print('Remaining', headers['x-rate-limit-remaining'])
js = json.loads(data)
print(json.dumps(js, indent=4))
for u in js['users']:
print(u['screen_name'])
s = u['status']['text']
# Code: http://www.pythonlearn.com/code3/twitter2.py
Como o JSON se torna um conjunto de listas e dicionários Python aninhados, podemos usar
uma combinação da operação de índice e loops for para percorrer o retorno das estruturas de
dados com muito pouco código Python.
A saída do programa é a seguinte (alguns dos itens de dados são encurtados para caber na
página):
Remaining 14
"next_cursor": 1444171224491980205,
"users": [
"id": 662433,
"followers_count": 28725,
"status": {
"text": "@jazzychad I just bought one .__.",
"retweeted": false,
},
"screen_name": "leahculver",
},
"id": 40426722,
"followers_count": 2635,
"status": {
},
"screen_name": "_valeriei",
],
"next_cursor_str": "1444171224491980205"
leahculver
_valeriei
ericbollens
halherzog
scweeker
@DeviceLabDC love it! Now where so I get that "etc
O último bit da saída é onde vemos o loop for lendo os cinco mais recentes “amigos” da conta
drchuck no Twitter e imprimir o status mais recente para cada amigo. Há muito mais dados
disponíveis no JSON retornado. Se você olha na saída do programa, você também pode ver
que o “encontre os amigos” de uma conta específica tem uma limitação de taxa diferente do
número de linhas do tempo consultas que podemos executar por período de tempo.
Essas chaves de API seguras permitem que o Twitter tenha uma confiança sólida de que eles
sabem quem está usando sua API e dados e em que nível. A abordagem de limitação de taxa
nos permite fazer recuperações de dados pessoais simples, mas não nos permite construir um
produto que extrai dados de sua API milhões de vezes por dia.
13.9 Glossário
API Application Program Interface - Um contrato entre aplicativos que define os padrões de
interação entre dois componentes do aplicativo.
ElementTree - Uma biblioteca Python integrada usada para analisar dados XML.
13.10 Exercícios
Exercício 1: Altere o www.pythonlearn.com/code3/geojson.py ou
www.pythonlearn.com/code3/geoxml.py para imprimir o país de dois código dos dados
recuperados. Adicione verificação de erros para que seu programa não de traceback se o
código do país não estiver lá. Assim que estiver funcionando, pesquise para “Oceano Atlântico”
e certifique-se de que ele pode lidar com locais que não estão em nenhum país.
Capítulo 14
Programação orientada a objetos
• Código sequencial
À medida que os programas chegam a ter milhões de linhas, torna-se cada vez mais
importante escrever códigos que são fáceis de entender. Se você estiver trabalhando em um
programa de milhões de linhas, você nunca pode manter todo o programa em sua mente ao
mesmo tempo. Então nós precisamos de maneiras de dividir o programa em várias partes
menores para resolvem um problema, corrigir um bug ou adicionar um novo recurso.
De certa forma, a programação orientada a objetos é uma maneira de organizar seu código
para que você poça ampliar em 500 linhas do código e entendê-lo enquanto ignora as outras
999.500 linhas de código no momento.
14.2 Começando
Como muitos aspectos da programação, é necessário aprender os conceitos de objeto de
programação orientada antes que você possa usá-los efetivamente. Portanto, aproxime-se
deste capítulo como uma forma de aprender alguns termos e conceitos e trabalhar com alguns
exemplos para estabelecer uma base para o aprendizado futuro. Ao longo do resto do e-book
estaremos usando objetos em muitos dos programas, mas não estaremos construindo nosso
novos objetos nos programas.
O principal resultado deste capítulo é ter uma compreensão básica de como os objetos são
construídos e como eles funcionam e, mais importante, como fazemos uso dos recursos dos
objetos que nos são fornecidos pelas bibliotecas Python.
stuff = list()
stuff.append('python')
stuff.append('chuck')
stuff.sort()
print (stuff[0])
print (stuff.__getitem__(0))
print (list.__getitem__(stuff,0))
# Code: http://www.pythonlearn.com/code3/party1.py
Mas, em vez de focar no que essas linhas realizam, vamos ver o que esta realmente
acontecendo do ponto de vista da programação orientada a objetos. Não se preocupe se os
parágrafos a seguir não fizerem sentido na primeira vez que você os ler porque ainda não
definimos todos esses termos.
A primeira linha está construindo um objeto do tipo lista, a segunda e a terceira linhas estão
chamando o método append(), a quarta linha está chamando o método sort() e a quinta linha
está recuperando o item na posição 0.
A sexta linha está chamando o método __getitem__() na lista de coisas com um parâmetro de
zero.
print (stuff.__getitem__(0))
A sétima linha é uma maneira ainda mais detalhada de recuperar o 0º item da lista.
print (list.__getitem__(stuff,0))
Neste código, nos preocupamos em chamar o método __getitem__ na classe lista e passar na
lista (coisas) e o item que queremos recuperar da lista como parâmetros.
As últimas três linhas do programa são completamente equivalentes, mas é mais consistente e
conveniente simplesmente usar a sintaxe de colchetes para procurar um item em uma
determinada posição em uma lista.
Podemos dar uma olhada nas capacidades de um objeto olhando para a saída da função dir():
>>> dir(stuff)
>>>
A definição precisa de dir() é que ele lista os métodos e atribuições de um objeto Python.
O restante deste capítulo definirá todos os termos acima, portanto, certifique-se de voltar
depois de terminar o capítulo e releia os parágrafos acima para verificar seu entendimento.
wf = int(usf) - 1
Quando estamos “dentro” do programa, temos algumas interações definidas com o “outro
lado” do mundo, mas essas interações são bem definidas e geralmente não são algo
concentrados. Enquanto estamos codificando nos preocupamos apenas com os detalhes
“dentro do programa".
Uma maneira de pensar sobre a programação orientada a objetos é que estamos separando
nosso programa em múltiplas “zonas”. Cada “zona” contém algum código e dados (como um
programa) e tendo interações bem definidas com o mundo exterior e as outras zonas dentro
do programa.
# https://pypi.python.org/pypi/beautifulsoup4
# Ou baixe o arquivo
# http://www.pythonlearn.com/code3/bs4.zip
html = urllib.request.urlopen(url).read()
tags = soup('a')
print(tag.get('href', None))
# Code: http://www.pythonlearn.com/code3/urllinks.py
Lemos a URL em uma string e, em seguida, passamos para urllib para recuperar os dados da
web. A biblioteca urllib usa a biblioteca socket para fazer a real conexão de rede para
recuperar os dados. Pegamos a corda que recebemos de volta do urllib e entregue-o ao
BeautifulSoup para análise. BeautifulSoup faz uso de outro objeto chamado html.parser1 e
retorna um objeto. Chamamos os método tags(), método no objeto retornado e, em seguida,
obtenha um dicionário de objetos de tag e faça um loop através das tags e chame o método
get() para cada tag para imprimir o~ atributo 'href'.
A chave aqui não é entender completamente como este programa funciona, mas ver como nós
construirmos uma rede de objetos interativos e orquestrar o movimento da informação entre
os objetos para criar um programa. Também é importante observar que quando você olhou
para aquele programa vários capítulos atrás, você pode entender completamente o que estava
acontecendo no programa, mesmo sem perceber que o programa estava “orquestrando o
movimento de dados entre objetos”. Naquela época eram apenas linhas de código que fez o
trabalho.
Essa capacidade de focar em uma parte de um programa que nos interessa e ignorar o resto
do programa também é útil para os desenvolvedores dos objetos. Por exemplo os
programadores que desenvolvem BeautifulSoup não precisam saber ou se preocupar com a
forma de como recuperar nossa página HTML, quais partes queremos ler ou o que planejamos
fazer com os dados que extraímos da página web.
Outra palavra que usamos para captar essa ideia de que ignoramos os detalhes internos de
objetos que usamos é “encapsulamento”. Isso significa que podemos saber como usar um
objeto sem saber como ele realiza internamente o que precisamos fazer.
Um objeto pode conter uma série de funções (que chamamos de “métodos”), bem como
dados usados por essas funções. Chamamos itens de dados que fazem parte dos objetos
"atributos".
Usamos a palavra-chave class para definir os dados e o código que comportão cada um dos
objetos. A palavra-chave class inclui o nome da classe e inicia um bloco de código recuado
onde incluímos os atributos (dados) e métodos (código).
class PartyAnimal:
x=0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
an.party()
an.party()
an.party()
PartyAnimal.party(an)
# Code: http://www.pythonlearn.com/code3/party2.py
Cada método se parece com uma função, começando com a palavra-chave def e consistindo
de um bloco de código recuado. Este exemplo tem um atributo (x) e um método (party). Os
métodos têm um primeiro parâmetro especial que nomeamos por convenção auto.
Assim como a palavra-chave def não faz com que o código de função seja executado, a
palavra-chave class não cria um objeto. Em vez disso, a palavra-chave class define um modelo
indicando quais dados e códigos estarão contidos em cada objeto do tipo PartyAnimal. A classe
é como um cortador de biscoitos e os objetos criados usando o class são os cookies. Você não
coloca glacê no cortador de biscoitos, você põe glacê nos biscoitos e você pode colocar glacê
diferente em cada biscoito.
Se você continuar com o código de exemplo, veremos a primeira linha de código executável:
an = PartyAnimal()
É aqui que instruímos o Python a construir (por exemplo, criar) um objeto ou “instância da
classe chamada PartyAnimal”. Parece uma chamada de função para a própria classe e o Python
constrói o objeto com os dados e métodos corretos e retorna o objeto que é então atribuído à
variável an. De certa forma, isso é bastante semelhante para a seguinte linha que temos usado
o tempo todo:
counts = dict()
Aqui estamos instruindo o Python a construir um objeto usando o modelo dict (já presente no
Python), retorne a instância do dicionário e atribua-a a contagens variáveis.
Quando a classe PartyAnimal é usada para construir um objeto, a variável an é usada para
apontar para esse objeto. Usamos um para acessar o código e os dados dessa determinada
instância de um objeto PartyAnimal.
an.party()
Quando o método party é chamado, o primeiro parâmetro (que chamamos por convenção
self) aponta para a instância particular do objeto PartyAnimal que a party está chamando de
dentro. Dentro do método party, vemos a linha:
self.x = self.x + 1
Esta sintaxe usando o operador 'dot' está dizendo 'o x dentro de si'. Então cada vez que party()
é chamado, o valor x interno é incrementado em 1 e o valor é impresso fora.
Para ajudar a entender a diferença entre uma função global e um método dentro de uma
classe/objeto, a linha a seguir é outra maneira de chamar o método party dentro de um
objeto:
PartyAnimal.party(an)
So far 1
So far 2
So far 3
So far 4
class PartyAnimal:
x=0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
# Code: http://www.pythonlearn.com/code3/party3.py
Você pode ver que, usando a palavra-chave class, criamos um novo tipo, de saída dir, você
pode ver que o atributo x interage e o método party são disponíveis no objeto.
14.8 Ciclo de Vida do Objeto
Nos exemplos anteriores, estamos definindo uma classe (template) e usando essa classe para
criar uma instância dessa classe (object) e, em seguida, usar a instância. Quando o programa
termina, todas as variáveis são descartadas. Normalmente não pensamos muito sobre a
criação e destruição de variáveis, mas muitas vezes como nossos objetos se tornam mais
complexo, precisamos realizar alguma ação dentro do objeto para definir as coisas como o
objeto está sendo construído e, possivelmente, limpar as coisas enquanto o objeto está sendo
descartado.
Se queremos que nosso objeto esteja ciente desses momentos de construção e destruição,
adicionamos métodos especialmente nomeados ao nosso objeto:
class PartyAnimal:
x=0
def __init__(self):
print('I am constructed')
def party(self) :
self.x = self.x + 1
print('So far',self.x)
def __del__(self):
an = PartyAnimal()
an.party()
an.party()
an = 42
print('an contains',an)
# Code: http://www.pythonlearn.com/code3/party4.py
I am constructed
So far 1
So far 2
I am destructed 2
an contains 42
Conforme o Python está construindo nosso objeto, ele chama nosso método __init__ para nos
fornecer uma chance de configurar alguns valores padrão ou iniciais para o objeto. Quando
Python encontra a linha:
an = 42
Na verdade, "joga nosso objeto fora" para que possa reutilizar uma variável para armazenar o
valor 42. Exatamente no momento em que nosso objeto está sendo 'destruído', nosso código
destruidor (__del__) é chamado. Não podemos impedir que nossa variável seja destruída, mas
podemos fazer qualquer limpeza necessária antes que nosso objeto não exista mais.
Quando estamos fazendo vários objetos de nossa classe, podemos querer configurar
diferentes valores iniciais diferentes para cada um dos objetos. Podemos passar dados para os
construtores para dar a cada objeto um valor inicial diferente:
class PartyAnimal:
x=0
name = ''
self.name = nam
print(self.name,'constructed')
def party(self) :
self.x = self.x + 1
print(self.name,'party count',self.x)
s = PartyAnimal('Sally')
s.party()
j = PartyAnimal('Jim')
j.party()
s.party()
# Code: http://www.pythonlearn.com/code3/party5.py
O construtor tem um parâmetro self que aponta para a instância do objeto e parâmetros
adicionais que são passados para o construtor conforme o objeto é sendo construído:
s = PartyAnimal('Sally')
self.name = nam
Copia o parâmetro passado em (nam) para o atributo name dentro da instância do objeto.
A saída do programa mostra que cada um dos objetos (s e j) contém suas próprias cópias
independentes de x e nam:
Sally constructed
Jim constructed
14.10 Herança
Outro recurso poderoso da programação orientada a objetos é a capacidade de criar uma nova
classe estendendo uma classe existente. Ao estender uma classe, chamamos a classe original
como a 'classe pai' e a nova classe como a 'classe filha'.
Para este exemplo, moveremos nossa classe PartyAnimal para seu próprio arquivo:
class PartyAnimal:
x=0
name = ''
self.name = nam
print(self.name,'constructed')
def party(self) :
self.x = self.x + 1
print(self.name,'party count',self.x)
# Code: http://www.pythonlearn.com/code3/party.py
class CricketFan(PartyAnimal):
points = 0
def six(self):
self.points = self.points + 6
self.party()
print(self.name,"points",self.points)
s = PartyAnimal("Sally")
s.party()
j = CricketFan("Jim")
j.party()
j.six()
print(dir(j))
# Code: http://www.pythonlearn.com/code3/party6.py
Quando estamos definindo o objeto CricketFan, indicamos que estamos estendendo a classe
PartyAnimal. Isso significa que todas as variáveis (x) e métodos (party) da classe PartyAnimal
são herdados pela classe CricketFan.
Você pode ver que dentro do método six na classe CricketFan, podemos chamar o método
party da classe PartyAnimal. As variáveis e métodos da classe pai são mescladas na classe filha.
À medida que o programa é executado, podemos ver que s e j são instâncias independentes de
PartyAnimal e CricketFan. O objeto j tem recursos adicionais além do objeto s.
Sally constructed
Jim constructed
Jim points 6
Na saída dir para o objeto j (instância da classe CricketFan), você pode ver que ele tem os
atributos e métodos da classe pai, bem como o atributos e métodos que foram adicionados
quando a classe foi estendida para criar o Classe CricketFan.
14.11 Resumo
Esta é uma introdução muito rápida à programação orientada a objetos que se concentra
principalmente na terminologia e na sintaxe de definição e uso de objetos. Vamos
rapidamente revisar o código que examinamos no início do capítulo. Neste ponto você deve
entender completamente o que está acontecendo.
stuff = list()
stuff.append('python')
stuff.append('chuck')
stuff.sort()
print (stuff[0])
print (stuff.__getitem__(0))
print (list.__getitem__(stuff,0))
# Code: http://www.pythonlearn.com/code3/party1.py
A primeira linha constrói um objeto de lista. Quando o Python cria o objeto de lista, ele chama
o método construtor (chamado __init__) para configurar os dados internos atributos que
serão usados para armazenar os dados da lista. Devido ao encapsulamento, nós nem
precisamos saber, nem precisa se preocupar com isso em atributos de dados internos são
organizados.
Não estamos passando nenhum parâmetro para o construtor e quando o construtor retorna,
usamos a variável stuff para apontar para a instância retornada da lista class.
A segunda e terceira linhas estão chamando o método append com um parâmetro para
adicionar um novo item no final da lista atualizando os atributos dentro do material. Então, na
quarta linha, chamamos o método sort sem parâmetros para classificar os dados dentro do
objeto material.
Em seguida, imprimimos o primeiro item da lista usando os colchetes que são um atalho para
chamar o método __getitem__ dentro do objeto stuff. E isso é equivalente a chamar o método
__getitem__ na classe de lista passando o objeto material como o primeiro parâmetro e a
posição que estamos procurando como o segundo parâmetro.
14.12 Glossário
Atributo - Uma variável que faz parte de uma classe.
Classe - Um modelo que pode ser usado para construir um objeto. Define os atributos e
métodos que irão compor o objeto.
Classe filha - Uma nova classe criada quando uma classe pai é estendida. a classe filha herda
todos os atributos e métodos da classe pai.
Herança - Quando criamos uma nova classe (filho) estendendo uma classe existente (pai). A
classe filha tem todos os atributos e métodos da classe pai mais os atributos e métodos
adicionais definidos pela classe filha.
Método - Uma função que está contida dentro de uma classe e os objetos que são construídos
a partir da class. Alguns padrões orientados a objetos usam ‘message’ em vez de 'método' para
descrever este conceito.
Objeto - Uma instância construída de uma classe. Um objeto contém todos os atributos e
métodos que foram definidos pela classe. Alguns documentos orientados a objetos usam o
termo ‘instância’ de forma intercambiável com ‘objeto’.
Classe pai - A classe que está sendo estendida para criar uma nova classe filha. A classe pai
contribui com todos os seus métodos e atributos para A nova chaild class.
Capítulo 15
Usando bancos de dados e SQL
15.1 O que é um banco de dados?
Um banco de dados é um arquivo organizado para armazenar dados. A maioria dos bancos de
dados são organizados como um dicionário no sentido de que eles mapeiam de chaves para
valores. A maior da diferença é que o banco de dados está em disco (ou outro armazenamento
permanente), então ele persiste após o término do programa. Como um banco de dados é
armazenado em armazenamento permanente, ele pode armazenar muito mais dados do que
um dicionário, que é limitado ao tamanho da memória no computador.
Existem muitos sistemas de banco de dados diferentes que são usados para uma ampla
variedade de propósitos. Incluindo: Oracle, MySQL, Microsoft SQL Server, PostgreSQL e SQLite.
Focamos no SQLite neste e-book, porque é um banco de dados muito comum e é já embutido
no Python. O SQLite foi projetado para ser incorporado a outras aplicações para fornecer
suporte de banco de dados dentro do aplicativo. Por exemplo, o Firefox, o navegador também
usa o banco de dados SQLite internamente, assim como muitos outros produtos.
http://sqlite.org/
O SQLite é adequado para alguns dos problemas de manipulação de dados que vemos em
Informática, como o aplicativo spidering do Twitter que descrevemos neste capítulo.
Nas descrições técnicas de bancos de dados relacionais, os conceitos de tabela, linha e coluna
são mais formalmente referidos como relação, tupla e atributo, respectivamente. Usaremos os
termos menos formais neste capítulo.
Usando o navegador, você pode facilmente criar tabelas, inserir dados, editar dados ou
executar tarefas simples, consulte SQL sobre os dados no banco de dados.
Quando criamos uma tabela de banco de dados, devemos informar ao banco de dados com
antecedência os nomes de cada uma das colunas da tabela e o tipo de dados que pretendemos
armazenar em cada coluna. Quando o software de banco de dados conhece o tipo de dados
em cada coluna, ele pode escolher a maneira mais eficiente de armazenar e consultar os dados
com base no tipo de dados.
Você pode ver os vários tipos de dados suportados pelo SQLite no seguinte URL:
http://www.sqlite.org/datatypes.html
O código para criar um arquivo de banco de dados e uma tabela chamada Tracks com duas
colunas em um banco de dados é o seguinte:
import sqlite3
conn = sqlite3.connect('music.sqlite')
cur = conn.cursor()
conn.close()
# Code: http://www.pythonlearn.com/code3/db1.py
A operação de conexão faz uma “conexão” com o banco de dados armazenado no arquivo
music.sqlite3 no diretório atual. Se o arquivo não existir, ele será criado. A razão pela qual isso
é chamado de “conexão” é que às vezes o banco de dados é armazenado em um “servidor de
banco de dados” separado do servidor no qual estamos executando nosso aplicativo. Em
nossos exemplos simples, o banco de dados será apenas um arquivo local no mesmo diretório
do código Python que estamos executando.
Um cursor é como um identificador de arquivo que podemos usar para executar operações
nos dados armazenados no banco de dados. Chamar cursor() é muito semelhante
conceitualmente a chamar open() ao lidar com arquivos de texto.
Uma vez que temos o cursor, podemos começar a executar comandos sobre o conteúdo do
banco de dados usando o método execute().
Os comandos do banco de dados são expressos em uma linguagem especial que foi
padronizada em muitos fornecedores de banco de dados diferentes para nos permitir
aprender uma única linguagem de banco de dados. A linguagem do banco de dados é chamada
Linguagem de Consulta Estruturada ou SQL para ser mais curto.
http://en.wikipedia.org/wiki/SQL
Em nosso exemplo, estamos executando dois comandos SQL em nosso banco de dados. Como
uma convenção, mostraremos as palavras-chave SQL em maiúsculas e as partes do comando
que estamos adicionando (como os nomes das tabelas e colunas) será mostrado em
minúsculas.
O primeiro comando SQL remove a tabela Tracks do banco de dados, se ela existir. Este padrão
é simplesmente para nos permitir executar o mesmo programa para criar as faixas de uma
tabela e outra vez sem causar um erro. Observe que o comando DROP TABLE exclui a tabela e
todo o seu conteúdo do banco de dados.
O segundo comando cria uma tabela chamada Tracks com uma coluna de texto chamada title
e uma coluna inteira chamada plays.
Agora que criamos uma tabela chamada Tracks, podemos colocar alguns dados na tabela
usando a operação SQL INSERT. Mais uma vez, começamos fazendo uma conexão ao banco de
dados e obtendo o cursor. Podemos então executar comandos SQL usando o cursor.
O comando SQL INSERT indica qual tabela estamos usando e então define uma nova linha
listando os campos que queremos incluir (título, reproduções) seguidos pelo VALUES que
queremos colocar na nova linha. Especificamos os valores como pontos de interrogação (?, ?)
para indicar que os valores reais são passados como uma tupla ( ’My Way’, 15 ) como o
segundo parâmetro para a chamada execute().
import sqlite3
conn = sqlite3.connect('music.sqlite')
cur = conn.cursor()
('Thunderstruck', 20))
conn.commit()
print('Tracks:')
print(row)
cur.close()
# Code: http://www.pythonlearn.com/code3/db2.py
Primeiro, INSERT duas linhas em nossa tabela e usamos commit () para forçar os dados a
serem gravado no arquivo de banco de dados.
Em seguida, usamos o comando SELECT para recuperar as linhas que acabamos de inserir do
table. No comando SELECT, indicamos quais colunas desejamos (title, plays) e indicar de qual
tabela queremos recuperar os dados. Depois de executar a instrução SELECT, o cursor é algo
que podemos percorrer em um loop para declaração. Para maior eficiência, o cursor não lê
todos os dados do banco de dados quando executamos a instrução SELECT. Em vez disso, os
dados são lidos em demanda à medida que percorremos as linhas na instrução for.
Tracks:
('Thunderstruck', 20)
Nosso loop for encontra duas linhas, e cada linha é uma tupla Python com o primeiro valor
como o título e o segundo valor como o número de jogadas.
Nota: Você pode ver strings começando com u' em outros livros ou na Internet. Essa foi uma
indicação no Python2 de que as strings são strings Unicode capazes de armazenar conjuntos de
caracteres não latinos. No Python3, todas as strings são strings unicode por padrão.
No final do programa, executamos um comando SQL para EXCLUIR as linhas que acabamos de
criar para que possamos executar o programa repetidamente. O comando DELETE mostra o
uso de uma cláusula WHERE que nos permite expressar uma seleção de critérios para que
possamos pedir ao banco de dados para aplicar o comando apenas às linhas que
correspondem ao critério. Neste exemplo, o critério se aplica a todas as linhas, então
esvaziamos a tabela para que possamos executar o programa repetidamente. Depois que o
DELETE for executado, também chamamos commit() para forçar os dados a serem removidos
do banco de dados.
Para inserir uma linha em uma tabela, usamos o comando SQL INSERT:
A instrução INSERT especifica o nome da tabela e, em seguida, uma lista dos campos/colunas
que você gostaria de definir na nova linha e, em seguida, a palavra-chave VALUES, uma lista de
valores correspondentes para cada um dos campos.
O comando SQL SELECT é usado para recuperar linhas e colunas de um banco de dados. A
instrução SELECT permite especificar quais colunas você gostaria de recuperar bem como uma
cláusula WHERE para selecionar quais linhas você gostaria de ver. Também permite uma
cláusula ORDER BY opcional para controlar a classificação das linhas retornadas.
Observe que, ao contrário do Python, em uma cláusula SQL WHERE usamos um único sinal de
igual para indicar um teste de igualdade em vez de um sinal de igual duplo. Outras operações
lógicas permitidas em uma cláusula WHERE incluem <, >, <=, >=, !=, bem como AND e OR e
parênteses para construir suas expressões lógicas.
Você pode solicitar que as linhas retornadas sejam classificadas por um dos campos da
seguinte forma:
Para remover uma linha, você precisa de uma cláusula WHERE em uma instrução SQL DELETE.
A cláusula WHERE determina quais linhas devem ser excluídas:
É possível ATUALIZAR uma coluna ou colunas dentro de uma ou mais linhas em uma tabela
usando a instrução SQL UPDATE da seguinte forma:
A instrução UPDATE especifica uma tabela e, em seguida, uma lista de campos e valores a
serem alterados após a palavra-chave SET e, em seguida, uma cláusula WHERE opcional para
selecionar as linhas que devem ser atualizadas. Uma única instrução UPDATE mudará todas as
linhas que correspondem à cláusula WHERE. Se uma cláusula WHERE não for especificada, ela
executa o UPDATE em todas as linhas da tabela.
Esses quatro comandos SQL básicos (INSERT, SELECT, UPDATE e DELETE) permitem as quatro
operações básicas necessárias para criar e manter dados.
Nota: Tenha muito cuidado ao correr este programa. Você não deseja extrair muitos dados ou
executar o programa por muito tempo e acabar tendo seu acesso ao Twitter bloqueado.
Um dos problemas de qualquer tipo de programa de indexação é que ele precisa ser capaz de
ser parado e reiniciado muitas vezes e você não quer perder os dados que você recuperou até
agora. Você não quer sempre reiniciar sua recuperação de dados desde o início, então
queremos armazenar os dados à medida que os recuperamos, para que nosso programa
comece de volta e continue de onde parou.
Também rastreamos quantas vezes vimos um determinado amigo no banco de dados para
obter alguma noção de sua "popularidade".
import urllib.error
import twurl
import json
import sqlite3
TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json'
conn = sqlite3.connect('spider.sqlite')
cur = conn.cursor()
cur.execute('''
while True:
acct = cur.fetchone()[0]
except:
continue
print('Retrieving', url)
connection = urlopen(url)
data = connection.read().decode()
headers = dict(connection.getheaders())
print('Remaining', headers['x-rate-limit-remaining'])
js = json.loads(data)
# Debugging
countnew = 0
countold = 0
for u in js['users']:
friend = u['screen_name']
print(friend)
(friend, ))
try:
count = cur.fetchone()[0]
(count+1, friend))
countold = countold + 1
except:
cur.execute('''INSERT INTO Twitter (name, retrieved, friends)
countnew = countnew + 1
conn.commit()
cur.close()
# Code: http://www.pythonlearn.com/code3/twspider.py
Nosso banco de dados está armazenado no arquivo spider.sqlite3 e possui uma tabela
chamada Twitter. Cada linha na tabela do Twitter tem uma coluna para o nome da conta, se
recuperamos os amigos desta conta e quantas vezes isso conta foi "amigo".
Se o usuário pressionar enter, procuramos no banco de dados a próxima conta do Twitter que
ainda não recuperamos, recupere os amigos e status dessa conta, adicione para o banco de
dados ou atualizá-los e aumentar a contagem de amigos.
Depois de recuperar a lista de amigos e status, percorremos todos os usuários e itens no JSON
retornado e recupere o screen_name para cada usuário. Então usamos a instrução SELECT
para ver se já armazenamos esse screen_name no banco de dados e recuperamos a contagem
de amigos (friends) se o registro existe.
countnew = 0
countold = 0
for u in js['users'] :
friend = u['screen_name']
print friend
(friend, ) )
try:
count = cur.fetchone()[0]
cur.execute('UPDATE Twitter SET friends = ? WHERE name = ?',
(count+1, friend) )
countold = countold + 1
except:
countnew = countnew + 1
conn.commit()
Depois que o cursor executa a instrução SELECT, devemos recuperar as linhas. Nós poderiamos
fazer isso com uma instrução for, mas como estamos recuperando apenas uma linha (LIMIT 1),
podemos usar o método fetchone() para buscar a primeira (e única) linha que é o resultado da
operação SELECT. Como fetchone() retorna a linha como uma tupla (mesmo embora haja
apenas um campo), pegamos o primeiro valor da tupla usando para obter a contagem de
amigos atual na contagem variável.
Se esta recuperação for bem-sucedida, usamos a instrução SQL UPDATE com uma cláusula
WHERE para adicionar 1 à coluna de amigos para a linha que corresponde à conta do amigo.
Observe que há dois espaços reservados (isto é, pontos de interrogação) no SQL, e o segundo
parâmetro para o execute() é uma tupla de dois elementos que contém os valores para ser
substituído no SQL no lugar dos pontos de interrogação.
Assim, na primeira vez que o programa é executado e entramos em uma conta do Twitter, o
programa funciona da seguinte forma:
Como esta é a primeira vez que executamos o programa, o banco de dados está vazio e crie o
banco de dados no arquivo spider.sqlite3 e adicione uma tabela chamada Twitter ao banco de
dados. Em seguida, recuperamos alguns amigos e os adicionamos ao banco de dados já que o
banco de dados está vazio.
Neste ponto, podemos querer escrever um descarregador de banco de dados simples para dar
uma olhada no que está em nosso arquivo spider.sqlite3:
import sqlite3
conn = sqlite3.connect('spider.sqlite')
cur = conn.cursor()
count = 0
print(row)
count = count + 1
print(count, 'rows.')
cur.close()
# Code: http://www.pythonlearn.com/code3/twdump.py
Este programa simplesmente abre o banco de dados e seleciona todas as colunas de todos as
linhas na tabela Twitter, então percorre as linhas e imprime cada linha.
Se executarmos este programa após a primeira execução do nosso spider do Twitter acima, a
saída será a seguinte:
('opencontent', 0, 1)
('lhawthorn', 0, 1)
('steve_coppin', 0, 1)
('davidkocher', 0, 1)
('hrheingold', 0, 1)
...
20 rows.
Vemos uma linha para cada screen_name, que não recuperamos os dados para isso
screen_name e todos no banco de dados têm um amigo.
Agora nosso banco de dados reflete a recuperação dos amigos de nossa primeira conta no
Twitter (drchuck). Podemos executar o programa novamente e dizer a ele para recuperar os
amigos da próxima conta “não processada” simplesmente pressionando enter em vez de uma
conta do Twitter do seguinte modo:
Enter a Twitter account, or quit:
Como pressionamos enter (ou seja, não especificamos uma conta no Twitter), o seguinte
código é executado:
if ( len(acct) < 1 ) :
try:
acct = cur.fetchone()[0]
except:
continue
Usamos a instrução SQL SELECT para recuperar o nome do primeiro usuário (LIMIT 1) que
ainda tem o valor "recuperamos este usuário" definido como zero. Também usamos o padrão
fetchone()[0] dentro de um bloco try/except para extrair um screen_name dos dados
recuperados ou enviar uma mensagem de erro e fazer o loop de volta.
connection.read() js = json.loads(data)
Depois de recuperar os dados com sucesso, usamos a instrução UPDATE para definir a coluna
recuperada para 1 para indicar que concluímos a recuperação do amigos desta conta. Isso nos
impede de recuperar os mesmos dados repetidamente e nos mantém progredindo através da
rede de amigos do Twitter.
('opencontent', 1, 1)
('lhawthorn', 1, 1)
('steve_coppin', 0, 1)
('davidkocher', 0, 1)
('hrheingold', 0, 1)
...
('cnxorg', 0, 2)
('knoop', 0, 1)
('kthanos', 0, 2)
('LectureTools', 0, 1)
...
55 rows.
Cada vez que executarmos o programa e pressionarmos enter, ele escolherá a próximo conta
não visitada (por exemplo, a próxima conta será steve_coppin), recupere seus amigos, marque
como recuperados, e para cada um dos amigos de steve_coppin adicione-os ao final do banco
de dados ou atualize sua contagem de amigos se eles já estiverem na base de dados.
http://en.wikipedia.org/wiki/Relational_model
Digamos que para nosso aplicativo de spider do Twitter, em vez de apenas contar os amigos,
queríamos manter uma lista de todos os novos relacionamentos para que pudéssemos
encontrar uma lista de todos que estão seguindo uma conta específica.
Como todos terão potencialmente muitas contas que os seguem, não podemos adicionar uma
única coluna à nossa tabela do Twitter. Então criamos uma nova tabela que mantém o
controle de pares de amigos. O seguinte é uma maneira simples de fazer tal table:
Cada vez que encontramos uma pessoa que drchuck está seguindo, inserimos uma linha no
formulário:
Essa duplicação de dados de string viola uma das melhores práticas para padrões de banco de
dados. Malização que basicamente afirma que nunca devemos colocar os mesmos dados de
string no banco de dados mais de uma vez. Se precisarmos dos dados mais de uma vez,
criamos uma chave numérica para os dados e fazemos referência aos dados reais usando essa
chave.
Em termos práticos, uma string ocupa muito mais espaço do que um inteiro no disco e na
memória do nosso computador, e leva mais tempo do processador para comparar e classificar.
Se tivermos apenas algumas centenas de entradas, o armazenamento e o tempo do
processador pouco importa. Mas se tivermos um milhão de pessoas em nosso banco de dados
e a possibilidade de 100 milhões de links de amigos, é importante poder verificar os dados o
mais rápido possível.
Armazenaremos nossas contas do Twitter em uma tabela chamada Pessoas em vez da tabela
Twitter usada no exemplo anterior. A tabela Pessoas tem uma coluna adicional para
armazenar a chave numérica associada à linha desse usuário do Twitter. SQLite tem um
recurso que adiciona automaticamente o valor da chave para qualquer linha inserida em uma
tabela usando um tipo especial de coluna de dados (INTEGER PRIMARY KEY).
Podemos criar a tabela People com esta coluna id adicional da seguinte forma:
Observe que não estamos mais mantendo uma contagem de amigos em cada linha do People
table. Quando selecionamos INTEGER PRIMARY KEY como o tipo de nossa coluna id, estamos
indicando que gostaríamos que o SQLite gerenciasse esta coluna e atribuísse uma única chave
numérica para cada linha que inserimos automaticamente. Também adicionamos a palavra-
chave UNIQUE para indicar que não permitiremos que o SQLite insira duas linhas com o
mesmo valor para name.
Agora ao invés de criar a tabela parceiras acima, criamos uma tabela chamada Follows com
duas colunas inteiras from_id e to_id e uma restrição na tabela que a combinação de from_id
e to_id deve ser única nesta tabela (ou seja, não podemos inserir linhas duplicadas) em nosso
banco de dados.
Em essência, ao criar esta tabela Follows, estamos modelando um “relacionamento” onde uma
pessoa “segue” outra e a representa com um par de números indicados verificando que (a) as
pessoas estão conectadas e (b) a direção do relacionamento.
import twurl
import json
import sqlite3
TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json'
conn = sqlite3.connect('friends.sqlite')
cur = conn.cursor()
while True:
try:
except:
continue
else:
(acct, ))
try:
id = cur.fetchone()[0]
except:
conn.commit()
if cur.rowcount != 1:
continue
id = cur.lastrowid
connection = urllib.request.urlopen(url)
data = connection.read().decode()
headers = dict(connection.getheaders())
print('Remaining', headers['x-rate-limit-remaining'])
js = json.loads(data)
# Depuração
countnew = 0
countold = 0
for u in js['users']:
friend = u['screen_name']
print(friend)
(friend, ))
try:
friend_id = cur.fetchone()[0]
countold = countold + 1
except:
conn.commit()
if cur.rowcount != 1:
continue
friend_id = cur.lastrowid
countnew = countnew + 1
conn.commit()
cur.close()
# Code: http://www.pythonlearn.com/code3/twfriends.py
Este programa está começando a ficar um pouco complicado, mas ilustra os padrões que
precisamos usar quando estamos usando chaves inteiras para vincular tabelas. O padrões
básicos são:
2. Quando temos uma chave lógica para uma pessoa (ou seja, nome da conta) e precisamos
do valor id para a pessoa, dependendo se a pessoa já está ou não na tabela Pessoas,
precisamos:
Indicamos que a coluna nome na tabela people deve ser ÚNICA. Nós também indicamos que a
combinação dos dois números em cada linha da tabela Follows deve ser único. Essas restrições
nos impedem de cometer erros, como adicionar o mesmo relacionamento mais de uma vez.
Adicionamos a cláusula OR IGNORE à nossa instrução INSERT para indicar que, se INSERT em
particular causara uma violação da regra, o sistema de banco de dados pode ignorar o INSERT.
Estamos usando o banco de dados como uma rede de segurança para garantir que não
façamos algo incorreto inadvertidamente.
Da mesma forma, o código a seguir garante que não adicionemos exatamente o mesmo
Follows duas vezes.
Novamente, simplesmente dizemos ao banco de dados para ignorar nossa tentativa de INSERT
se isso violar a restrição de exclusividade que especificamos para as linhas Follows.
15.8.2 Recuperar e/ou inserir um registro
Quando solicitamos ao usuário uma conta no Twitter, se a conta existir, devemos procurar seu
valor id. Se a conta ainda não existir na tabela Pessoas, devemos inserir o registro e obter o
valor id da linha inserida.
Este é um padrão muito comum e é feito duas vezes no programa acima. Este código mostra
como procuramos o id da conta de um amigo quando extraímos um screen_name de um nó de
usuário no Twitter JSON recuperado.
Com o tempo será cada vez mais provável que a conta já esteja em um banco de dados,
primeiro verificamos se o registro people esta usando uma declaração um SELECT.
Se tudo correr bem dentro da seção try, recuperamos o registro usando fetchone() e, em
seguida, recuperamos o primeiro (e único) elemento da tupla retornada e armazene-a em
amigo_id.
Se o SELECT falhar, o código fetchone()[0] falhará e o controle será transferido para a seção
except.
friend = u['screen_name']
(friend, ) )
try:
friend_id = cur.fetchone()[0]
countold = countold + 1
except:
conn.commit()
if cur.rowcount != 1 :
continue
friend_id = cur.lastrowid
countnew = countnew + 1
Se terminarmos no código except, significa simplesmente que a linha não foi encontrada,
então devemos inserir a linha. Usamos INSERT OR IGNORE apenas para evitar erros e então
chame commit() para forçar o banco de dados a ser realmente atualizado. Após terminar a
gravação, podemos verificar cur.rowcount para ver quantas linhas foram afetadas. Já que
estamos tentando inserir uma única linha, se o número de linhas afetadas for outro de 1, é um
erro.
Se o INSERT for bem-sucedido, podemos examinar cur.lastrowid para descobrir qual valor o
banco de dados atribuído à coluna id em nossa linha recém-criada.
(id, friend_id) )
Observe que deixamos o banco de dados cuidar de nos impedir de “inserir duas vezes” um
relacionamento criando a tabela com uma restrição de exclusividade e, em seguida,
adicionando OR IGNORE para nossa instrução INSERT.
People:
(1, 'drchuck', 1)
(2, 'opencontent', 1)
(3, 'lhawthorn', 1)
(4, 'steve_coppin', 0)
(5, 'davidkocher', 0)
55 rows.
Follows:
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(1, 6)
60 rows.
Você pode ver o id, nome e campos visitados na tabela people e você vê os números de ambas
as extremidades do relacionamento na tabela Follows. Na tabela pessoas, podemos ver que as
três primeiras pessoas foram visitadas e seus dados foram recuperados. Os dados na tabela
Follows indicam que drchuck (usuário 1) é um amigo para todas as pessoas mostradas nas
primeiras cinco linhas. Isso faz sentido porque os primeiros dados que recuperamos e
armazenamos foram os amigos do drchuck no Twitter. Se você fosse imprimir mais linhas da
tabela Follows, você veria os amigos dos usuários 2 e 3 também.
• Uma chave lógica é uma chave que o “mundo real” pode usar para procurar uma linha. Em
nosso modelo de dados de exemplo, o campo de nome é uma chave lógica. É o nome da tela
para o usuário e, de fato, procuramos a linha de um usuário várias vezes no programa usando
o campo nome. Frequentemente, você descobrirá que faz sentido adicionar uma ÚNICO
restrição a uma chave lógica. Como a chave lógica é como procuramos uma linha do mundo
exterior, não faz sentido permitir várias linhas com o mesmo valor na tabela.
• Uma chave primária geralmente é um número que é atribuído automaticamente pela base
de dados. Geralmente não tem significado fora do programa e é usada apenas para vincular
linhas de tabelas diferentes. Quando queremos consultar uma linha em uma tabela,
geralmente procuramos a linha usando a chave primária é a maneira mais rápida de encontrar
a linha. Como as chaves primárias são números inteiros, elas ocupam muito pouco
armazenamento e podem ser comparados ou classificados muito rapidamente. Em nossos
dados modelo, o campo id é um exemplo de chave primária.
• Uma chave estrangeira geralmente é um número que aponta para a chave primária de uma
linha associada em uma tabela diferente. Um exemplo de chave estrangeira em nossos dados
modelo é o from_id.
O SQL usa a cláusula JOIN para reconectar essas tabelas. Na cláusula JOIN você especifica os
campos que são usados para reconectar as linhas entre as tabelas.
A cláusula JOIN indica que os campos que estamos selecionando cruzam tanto o Follows e
tabelas people. A cláusula ON indica como as duas tabelas devem ser unidas. Pegue as linhas
de Seguidores e anexe a linha de Pessoas onde o campo from_id em Follows é o mesmo valor
de id na tabela People.
O resultado do JOIN é criar “linhas” extralongas que possuem tanto os campos de Pessoas e os
campos correspondentes de Seguidores. Onde há mais de uma correspondência entre o
campo id de People e from_id de People, então JOIN cria uma linha para cada um dos pares de
linhas correspondentes, duplicando dados conforme necessário.
O código a seguir demonstra os dados que teremos no banco de dados após o programa spider
do Twitter (acima) foi executado várias vezes.
import sqlite3
conn = sqlite3.connect('friends.sqlite')
cur = conn.cursor()
count = 0
print('People:')
count = count + 1
print(count, 'rows.')
count = 0
print('Follows:')
count = count + 1
print(count, 'rows.')
ON Follows.to_id = People.id
count = 0
count = count + 1
print(count, 'rows.')
cur.close()
# Code: http://www.pythonlearn.com/code3/twjoin.py
python twjoin.py
People:
(1, 'drchuck', 1)
(2, 'opencontent', 1)
(3, 'lhawthorn', 1)
(4, 'steve_coppin', 0)
(5, 'davidkocher', 0)
55 rows.
Follows:
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(1, 6)
60 rows.
(2, 1, 1, 'drchuck', 1)
20 rows.
Em cada uma das “metarows” na última seleção, as duas primeiras colunas são a tabela
seguida pelas colunas de três a cinco da tabela Pessoas. Você também pode ver que a segunda
coluna (Follows.to_id) corresponde à terceira coluna (People.id) em cada uma das “metarows”
unidas.
15.11 Resumo
Este capítulo cobriu muito terreno para lhe dar uma visão geral dos fundamentos usando um
banco de dados em Python. É mais complicado escrever o código para usar um banco de dados
para armazenar dados do que dicionários Python ou arquivos simples, portanto, há poucos
motivos para usar um banco de dados, a menos que seu aplicativo realmente precise dos
recursos de um banco de dados. As situações em que um banco de dados pode ser bastante
útil são:
(1) quando seu aplicativo precisa fazer muitas pequenas atualizações aleatórias dentro de um
grande conjunto de dados.
(2) quando seus dados são tão grandes que não cabem em um dicionário e você precisa
procurar informações repetidamente.
(3) quando você tem um processo de execução longo e que deseja parar e reiniciar e reter os
dados de uma execução.
Você pode construir um banco de dados simples com uma única tabela para atender a muitas
necessidades de aplicativos, mas a maioria dos problemas exigirá várias tabelas e
links/relacionados entre as linhas em tabelas diferentes. Quando você começa a fazer links
entre tabelas, é importante fazer um design cuidadoso e siguir as regras de normalização do
banco de dados para fazer o melhor uso dos recursos do banco de dados. Uma vez que a
principal motivação para o uso de banco de dados é que você tem uma grande quantidade de
dados para lidar, é importante modelar seus dados com eficiência para que seus programas
sejam executados o mais rápido possível.
15.12 Depuração
Um padrão comum quando você está desenvolvendo um programa Python para se conectar a
um banco de dados SQLite será executar um programa Python e verificar os resultados usando
o navegador de banco de dados para SQLite. O navegador permite que você verifique
rapidamente para ver se o seu programa está funcionando corretamente.
Você deve ter cuidado porque o SQLite para evitar que dois programas mudem os mesmos
dados ao mesmo tempo. Por exemplo, se você abrir um banco de dados no navegador e fazer
uma alteração no banco de dados e ainda não pressionou o botão “salvar” no navegador, o
navegador “bloqueia” o arquivo de banco de dados e mantém qualquer outro programa
acessar o arquivo. Em particular, seu programa Python não será capaz de acessar o arquivo se
ele estiver bloqueado.
15.13 Glossário
Atributo - Um dos valores dentro de uma tupla. Mais comumente chamado de “coluna” ou
"campo".
Restrição - Quando dizemos ao banco de dados para impor uma regra em um campo ou uma
linha em um table. Uma restrição comum é insistir que não pode haver valores duplicados em
um campo específico (ou seja, todos os valores devem ser exclusivos).
Cursor - Um cursor permite executar comandos SQL em um banco de dados e recuperar dados
do banco de dados. Um cursor é semelhante a um soquete ou identificador de arquivo para
conexões de rede e arquivos, respectivamente.
Chave estrangeira - Uma chave numérica que aponta para a chave primária de uma linha em
outra mesa. Chaves estrangeiras estabelecem relacionamentos entre linhas armazenadas em
diferentes tabelas.
Índice - Dados adicionais que o software de banco de dados mantém como linhas e inserções
em uma tabela para fazer pesquisas muito rapidamente.
Chave lógica - Uma chave que o “mundo externo” usa para procurar uma determinada linha.
exemplo, em uma tabela de contas de usuário, o endereço de e-mail de uma pessoa pode ser
uma boa candidata como a chave lógica para os dados do usuário.
Normalização - Projetar um modelo de dados para que nenhum dado seja replicado. nós
armazenamos cada item de dados em um local no banco de dados e referenciamos em outro
lugar usando uma chave estrangeira.
Chave primária - Uma chave numérica atribuída a cada linha que é usada para se referir a uma
linha em uma mesa de outra mesa. Frequentemente, o banco de dados é configurado para
automatizar chaves primárias conforme as linhas são inseridas.
Relação - Uma área dentro de um banco de dados que contém tuplas e atributos. Mais
normalmente chamado de “tabela”.
Tupla - Uma única entrada em uma tabela de banco de dados que é um conjunto de atributos.
Mais tipicamente chamado de “linha”.
Capítulo 16
Visualizando dados
Até agora, aprendemos a linguagem Python e depois aprendemos como usar o Python, a rede
e bancos de dados para manipular dados.
Neste capítulo, vamos dar uma olhada em três aplicativos completos que trazem todos essas
coisas juntas para gerenciar e visualizar dados. Você pode usar esses aplicativos como código
de amostra para ajudá-lo a começar a resolver um problema do mundo real.
Cada um dos aplicativos é um arquivo ZIP que você pode baixar e extrair para o seu
computador e executa-lo.
www.pythonlearn.com/code3/geodata.zip
O primeiro problema a resolver é que a API gratuita de geocodificação do Google tem uma
taxa limitada para um determinado número de solicitações por dia. Se você tiver muitos
dados, talvez seja necessário parar e reiniciar o processo de pesquisa várias vezes. Então
dividimos o problema em duas fases.
Execute o programa geoload.py. Este programa lerá as linhas de entrada em where.data e para
cada linha verifique se ela já está no banco de dados. Se não temos os dados para o local, ele
chamará a API de geocodificação para recuperar os dados e armazenar no banco de dados.
Aqui está uma amostra executada após já haver alguns dados no banco de dados:
Found in database Northeastern University
Retrieving http://maps.googleapis.com/maps/api/
geocode/json?sensor=false&address=Monash+University
Retrieving http://maps.googleapis.com/maps/api/
geocode/json?sensor=false&address=Kokshetau+Inst ...
...
Os cinco primeiros locais já estão no banco de dados e, portanto, são ignorados. O programa
varre até o ponto em que encontra novos locais e começa a recuperá-los.
Depois de carregar alguns dados em geodata.sqlite, você pode visualizar os dados usando o
programa geodump.py. Este programa lê o banco de dados e escreve o arquivo where.js com a
localização, latitude e longitude na forma executável Código JavaScript.
...
Technion, Viazman 87, Kesalsaba, 32000, Israel 32.7775 35.0216667
...
O arquivo where.html consiste em HTML e JavaScript para visualizar um mapa do Google. Ele
lê os dados mais recentes em where.js para obter os dados a serem visualizados. Aqui está o
formato do arquivo where.js:
myData = [
...
];
Esta é uma variável JavaScript que contém uma lista de listas. A sintaxe para listar constantes
no JavaScript é muito semelhante ao Python, então a sintaxe deve ser familiar para você.
Basta abrir where.html em um navegador para ver os locais. Você pode passar o mouse sobre
cada alfinete do mapa para encontrar o local que a API de geocodificação retornou para a
entrada do usuário inserido. Se você não conseguir ver nenhum dado ao abrir o arquivo
where.html, talvez tenha que verificar o JavaScript ou o console do desenvolvedor do seu
navegador.
www.pythonlearn.com/code3/pagerank.zip
O primeiro programa (spider.py) rastreia um site e extrai uma série de páginas no banco de
dados (spider.sqlite), registrando os links entre as páginas. você pode reiniciar o processo a
qualquer momento removendo o arquivo spider.sqlite e executando novamente spider.py.
['http://www.dr-chuck.com']
1 http://www.dr-chuck.com/ 12
2 http://www.dr-chuck.com/csev-blog/ 57
Neste exemplo de execução, pedimos que ele rastreie um site e recupere duas páginas. Se
você reiniciar o programa e diger a ele para rastrear mais páginas, ele não rastreará
novamente nenhuma página, já está no banco de dados. Ao reiniciar, ele vai para uma página
aleatória não rastreada e começara aí. Portanto, cada execução sucessiva de spider.py é
aditiva.
['http://www.dr-chuck.com']
3 http://www.dr-chuck.com/csev-blog 57
4 http://www.dr-chuck.com/dr-chuck/resume/speaking.htm 1
5 http://www.dr-chuck.com/dr-chuck/resume/index.htm 13
Você pode ter vários pontos de partida no mesmo banco de dados - dentro do programa, estes
são chamados de “teias”. A aranha escolhe aleatoriamente entre todos os links não visitados
em todas as teias como a próxima página para spider.
4 rows.
Isso mostra o número de links recebidos, a classificação da página antiga, a nova classificação
da página, o id da página e o url da página. O programa spdump.py mostra apenas as páginas
que tenham pelo menos um link de entrada para elas.
Depois de ter algumas páginas no banco de dados, você pode executar o ranking da página nas
páginas usando o programa sprank.py. Você simplesmente informa quantas iterações de
classificação de página correrão.
1 0.546848992536
2 0.226714939664
[(1, 0.559), (2, 0.659), (3, 0.985), (4, 2.135), (5, 0.659)]
Você pode despejar o banco de dados novamente para ver se o page rank foi atualizado:
4 rows.
Você pode executar sprank.py quantas vezes quiser e ele simplesmente refinará a página rank
cada vez que você executá-lo. Você pode até executar sprank.py algumas vezes e depois ir de
spider mais algumas páginas sith spider.py e, em seguida, execute sprank.py para reconverter
os valores de classificação de página. Um mecanismo de pesquisa geralmente executa o
rastreamento e a classificação programas o tempo todo.
Se você deseja reiniciar os cálculos de classificação de página sem respeitá-los nas páginas da
web, você pode usar spreset.py e reiniciar sprank.py.
1 0.546848992536
2 0.226714939664
3 0.0659516187242
4 0.0244199333
5 0.0102096489546
6 0.00610244329379
...
42 0.000109076928206
43 9.91987599002e-05
44 9.02151706798e-05
45 8.20451504471e-05
46 7.46150183837e-05
47 6.7857770908e-05
48 6.17124694224e-05
49 5.61236959327e-05
50 5.10410499467e-05
[(512, 0.0296), (1, 12.79), (2, 28.93), (3, 6.808), (4, 13.46)]
Para cada iteração do algoritmo de classificação de página, ele imprime a alteração média de
classificação página por página. A rede inicialmente é bastante desbalanceada e assim os
valores de classificação da página mudam muito entre as iterações. Mas em algumas iterações
curtas, o page rank converge. Você deve executar o prank.py por tempo suficiente para que a
classificação da página convergam.
Você pode visualizar esses dados abrindo o arquivo force.html em seu navegador da web. Esse
mostra um layout automático dos nós e links. Você pode clicar e arrastar qualquer nó e você
também pode clicar duas vezes em um nó para encontrar a URL que é representada pelo nó.
No mundo real, às vezes você precisa extrair dados de e-mail dos servidores. Que pode levar
algum tempo e os dados podem ser inconsistentes, cheios de erros e precisa de muita limpeza
ou ajuste. Nesta seção, trabalhamos com um aplicativo que é o mais complexo até agora e
extrai quase um gigabyte de dados e visualize-o.
www.pythonlearn.com/code3/gmane.zip
http://gmane.org/export.php
É muito importante que você faça uso responsável dos dados gmane.org adicionando
atrasos no seu acesso aos serviços deles e distribuição de trabalhos de longa duração por um
período de tempo mais longo. Não abuse deste serviço gratuito e estrague-o para o resto de
nós.
Quando os dados de e-mail Sakai foram rastreados usando este software, produziu quase um
Gigabyte de dados e fez várias execuções em vários dias. O arquivo README.txt no ZIP acima
pode ter instruções sobre como você pode baixar um arquivo pre-spidered, cópia do arquivo
content.sqlite para a maioria do corpos de e-mail Sakai para que você não tenha que arranhas
por cinco dias para executar os programas. Se você baixar o pré-conteúdo spidered, você
ainda deve executar o processo de spidering para acompanhar mais mensagens recentes.
http://download.gmane.org/gmane.comp.cms.sakai.devel/51411/51412 3379
http://download.gmane.org/gmane.comp.cms.sakai.devel/51412/51413 9903
http://download.gmane.org/gmane.comp.cms.sakai.devel/51413/51414 349265
http://download.gmane.org/gmane.comp.cms.sakai.devel/51414/51415 3481
http://download.gmane.org/gmane.comp.cms.sakai.devel/51415/51416 0
Às vezes gmane.org está faltando uma mensagem. Talvez os administradores possam deletar
mensagens ou talvez se percam. Se sua spider parar, e parecer que atingiu uma mensagem
ausente, vá para o SQLite Manager e adicione uma linha com a mensagem ausente deixando
todos os outros campos em branco e reinicie gmane.py. Isso vai descolar o processo de
spidering e permitir que ele continue. Essas mensagens vazias serão ignoradas na próxima fase
do processo.
Uma coisa boa é que depois de ter rastreado todas as mensagens e tê-las em content.sqlite,
você pode executar gmane.py novamente para obter novas mensagens conforme elas são
enviadas à lista.
Os dados content.sqlite são bastante brutos, com um modelo de dados ineficiente, e não
comprimido. Isso é intencional, pois permite que você veja content.sqlite no SQLite Manager
para depurar problemas com o processo de spidering. Seria uma ma ideia executar quaisquer
consultas nesse banco de dados, pois elas seriam muito lentas.
Cada vez que gmodel.py é executado, ele exclui e reconstrói index.sqlite, permitindo que você
ajuste seus parâmetros e edite as tabelas de mapeamento em content.sqlite para ajustar os
dados de processo de limpeza. Este é um exemplo de execução de gmodel.py. Imprime uma
linha a cada vez, 250 mensagens de e-mail são processadas para que você possa ver algum
progresso acontecendo, pois isso o programa pode ser executado por um tempo processando
quase um Gigabyte de dados de e-mail.
Loaded allsenders 1588 and mapping 28 dns mapping 1
1 2005-12-08T23:34:30-06:00 ggolden22@mac.com
Os nomes de domínio são truncados em dois níveis para .com, .org, .edu e .net. Outro nomes
de domínio são truncados em três níveis. Então si.umich.edu se torna umich.edu e
caret.cam.ac.uk torna-se cam.ac.uk. Endereços de e-mail também são forçados a diminuir
caso, e alguns dos endereços @gmane.org como o seguinte:
arwhyte-63aXycvo3TyHXe+LvDLADg@public.gmane.org
São convertidos para o endereço real sempre que houver um endereço de e-mail real
correspondente em outra parte do corpo da mensagem.
No banco de dados content.sqlite existem duas tabelas que permitem mapear ambos nomes
de domínio e endereços de e-mail individuais que mudam ao longo da vida da lista de e-mail.
Por exemplo, Steve Githens usou os seguintes endereços de e-mail ao empregos alterados ao
longo da vida da lista de desenvolvedores Sakai:
s-githens@northwestern.edu
sgithens@cam.ac.uk
swgithen@mtu.edu
Podemos adicionar duas entradas à tabela Mapping em content.sqlite para que gmodel.py
mapeie todos os três para um endereço
Você também pode fazer entradas semelhantes na tabela DNSMapping se houver vários
Nomes DNS que você deseja mapear para um único DNS. O seguinte mapeamento foi
adicionado aos dados de Sakai:
iupui.edu -> indiana.edu
portanto, todas as contas dos vários campos da Universidade de Indiana são rastreadas juntas.
Você pode reexecutar o gmodel.py várias vezes enquanto olha para os dados e adicionar
mapeamentos para tornar os dados cada vez mais limpos. Quando terminar, você terá uma
versão bem indexada do e-mail em index.sqlite. Este é o arquivo a ser usado para fazer análise
de dados. Com este arquivo, a análise de dados será muito rápida.
A primeira e mais simples análise de dados é determinar “quem enviou mais e-mails?” e “qual
organização enviou mais correspondências”? Isso é feito usando gbasic.py:
steve.swinsburg@gmail.com 2657
azeckoski@unicon.net 1742
ieb@tfd.co.uk 1591
csev@umich.edu 1304
david.horwitz@uct.ac.za 1184
gmail.com 7339
umich.edu 6243
uct.ac.za 2451
indiana.edu 2258
unicon.net 2055
Observe como gbasic.py é executado muito mais rapidamente em comparação com gmane.py
ou mesmo gmodel.py. Eles estão todos trabalhando nos mesmos dados, mas gbasic.py está
usando os dados compactados e normalizados em index.sqlite. Se você tiver muitos dados
para gerenciar, um processo de várias etapas como o deste aplicativo pode demorar um pouco
mais tempo para desenvolver, mas economizará muito tempo quando você realmente
começar a explorar e visualizar seus dados.
Você pode produzir uma visualização simples da frequência da palavra nas linhas de assunto
no arquivo gword.py:
Isso produz o arquivo gword.js que você pode visualizar usando gword.htm para produzir uma
nuvem de palavras semelhante à do início desta seção.
Uma segunda visualização é produzida por gline.py. Ele calcula a participação de e-mail por
organizações ao longo do tempo.
Top 10 Oranizations
'stanford.edu', 'ox.ac.uk']