Translation(s): English - Português


Este é um resumo do Tutorial sobre Python via IRC no #debian-women em 11 de fevereiro de 2006.

Esta versão do tutorial não é uma transcrição direta do log do IRC. Em vez disso, foi expandido um pouco em alguns pontos, então se você participou do tutorial pelo IRC, você pode ainda ler este. A estrutura do tutorial foi assim, eu dava exemplos e dizia alguma coisa sobre eles, e então havia perguntas e discussões até que passávamos para a seguinte.

Sobre Python em geral

Do Python FAQ:

Python é uma linguagem de programação interpretada, interativa e orientada a objetos. Ela incorpora módulos, exceções, tipagem dinâmica, alto nível de tipos de dados dinâmicos e classes.

Interpretada significa, na prática, que você pode executar programas em Python armazenados em arquivos sem precisar compilar primeiro, eles são similares a shell script nisso, e diferentes de programas em C.

Interativa significa que você pode iniciar o interpretador Python e começar a escrever instruções, uma por vez, e executá-las e imprimir alguns resultados. Aquele que for familiar com Lisp's Read-Eval-Print Loop (REPL) será familiar com este. Ditto for BASIC.

Orientada à objeto significa que Python favorece a POO, mas ele não força isso. Python é mais brando sobre paradigmas que, por exemplo, Java.

Das outras coisas da lista de FAQ, "tipagem dinâmica" seja talvez a mais interessante. Isto causa um pouco de choque para aqueles conhecem apenas linguagens como C ou Java, que são de tipagem estática: variáveis têm um tipo que é explicitamente declarado, e portanto cada expressão também tem um tipo que pode ser analisado na hora de compilar. Portanto, o compilador pode encontrar alguns erros antes do programa começar.

Em tipagem dinâmica, variáveis não têm tipo, têm valores. Uma variável pode ser "bound" para diferentes tipos de variáveis em diferentes pontos no tempo, e portanto todo tipo é verificado em tempo de execução. Isto deixa algumas coisas mais fáceis de fazer, mas pode tornar difícil encontrar erros de tipagem.

Tipagem dinâmica tende a ser boa para programas de tamanho pequeno a médio, de rápido desenvolvimento e prototipagem. Tipagem estática é melhor para grandes programas.

Python é frequentemente descrito como uma linguagem de script, mas isto não significa que não seja uma linguagem de finalidade geral. Python, como Perl, é frequentemente usada para tarefas rápidas, e é boa para isso porque é de alto-nível e interpretada, e tem algumas características e bibliotecas para certos tipos de tarefas de administração de sistemas. Ao mesmo tempo, é muitas vezes usada para desenvolvimento de aplicações reais.

O programa hello world

# Salve o arquivo "hello.py" e execute com "python hello.py"
print "hello, world"

Salve o arquivo acima chamado "hello.py", e execute-o com o comando "python hello.py". Se isso funcionar, então você sabe que tem Python instalado e funcionando, e sabe como usá-lo.

A primeira linha é um comentário: começa com uma cerquilha ("#"), e continua até o final da linha.

A segunda linha é uma simples instrução que imprime uma string. "print" é a maneira mais simples de enviar uma saída para a saída padrão. Você pode enviar para a saída qualquer número de valores, somente separe-os por vírgulas, e lá estarão espaços entre os valores.

Argumentos da linha de comando

#Execute isto como: python hello2.py seunome
import sys
print "saudações,", sys.argv[1]

Nós temos aqui uma maneira de importar um módulo de biblioteca, e uma forma de acessar os argumentos da linha de comando. "sys" é um dos módulos da biblioteca padrão do Python. Neste módulo há um array, ou uma lista, chamada argv, que contém os argumentos de linha de comando do Python, similar ao argv de argumentos do C da função main.

Listas (ou arrays) começam indexando do zero. Assim, sys.argv[0] é o primeiro argumento de linha de comando; como em C, este é o nome do programa que está sendo executado. sys.argv[1] é o primeiro argumento. Note desde já que Python é dinamicamente tipado, elementos de listas não precisam ser do mesmo tipo.

Execute o programa como "python hello2.py querida", e ele imprimirá na saída "saudações, querida".                                        

Se você não der a ele um argumento, o programa tentará usar o sys.argv[1] quando este não existir, isto causará um erro na execução, uma exceção, e o Python interpretará uma longa saída com uma mensagem de erro. Como essa:

liw@esme$ python hello2.py
greetings,
Traceback (most recent call last):
File "hello2.py", line 3, in ?
print "greetings,", sys.argv[1]
IndexError: list index out of range

A exceção traceback tem um registro (2 linhas) por entrada na pilha, no lugar que a exceção foi levantada no fundo (i.e., no topo do programa principal).

Lendo isto cuidadosamente e analisando o que foi chamado, você pode (normalmente!) descobrir o que estava errado. É possível para um programa pegar exceções.

if

Nós continuamos sendo extremamente afeiçoados a exemplos do "hello, world".

#Execute isto como: python hello3.py seunome
import sys
print "saudações,",
if len(sys.argv) == 2:

    print sys.argv[1]

else:

    print "meu amigo sem nome"

Uma vírgula depois do último argumento para o "print" garantirá a impressão numa nova linha.

"len(foo)" retorna o tamanho de uma lista "foo", que é o número de elementos dela. Índices, consequentemente, vão de 0 a len(foo)-1. len() é muito rápido, constant-time function. Nós usamos len para verificar se há um argumento dado pela linha de comando, senão nós substituímos por uma saudação padrão. A outra grande coisa sobre este exemplo é o comando "if". Aqui nós vamos aprender sobre o uso da indentação para marcar blocos do Python.

O "then" e "else", partes do comando "if" são ambos, mais marcados com indentação que o comando "if". O Python não tem marcação de blocos explícita, ela é feita com indentação. Um bloco é uma série de comandos com a mesma indentação; linhas vazias e comentários são ignorados, é claro.

Tabs são expandíveis, por padrão cada tem 8 espaços, mas isso é configurável. Usar qualquer outro tamanho pode facilmente causar problemas quando compartilhar código com outras pessoas. Programadores Python preferem usar somente espaços e não tabs.

"if" e outros comandos que utilizam blocos terminam com dois pontos. This is a stylistic issue. Você deve colocar os dois pontos lá, e ocasionalmente isto ajuda o parser a pegar erros de sintaxe.

É possivel colocar vários comandos em uma linha separando-os por um ponto-e-vírgula, mas isto é considerado um péssimo estilo.

while

Mais um exemplo de "hello".

# Execute isto como: python hello4.py nome1 nome2 nome3 ...
import sys
print "saudações,",
if len(sys.argv) == 1:

    print "meu amigo sem nome"

elif len(sys.argv) == 2:

    print sys.argv[1]

else:

    i = 1
    last_index = len(sys.argv) - 1
    while i < last_index:
        print sys.argv[i] + ",",
        i = i + 1
    print "and", sys.argv[last_index]

Neste exemplo nós pegamos variáveis, "elif", e "while". Variáveis trabalham muito bem como você espera. Variáveis não são declaradas, mas é um erro usar uma variável que ainda não foi atribuída no escopo local, ou nos escopos próximos.

Uma atribuição cria uma variável local (é possível usar variáveis globais, mas nós pularemos isso agora) Assim, um tipo no último comando do while acima muda isto para "i = j + 1" faria com que o Python levantasse uma exceção, mas "j = i + 1" funcionaria, causando um loop infinito?

Quando eu digo "é atribuído um valor à uma variável", o que eu realmente quero dizer é que uma variável recebe uma referência do valor. Todas as variáveis são referências.

"elif" é uma contração de "else if", e deveria ser clara do mesmo modo. Não há o comando "switch" no Python, no lugar dele um longo comando "if: ... elif: ... elif: ... else: ..." é usado. Todos os operadores inteiros funcionam:

 +, -, *, /, %, <, >, <=, >=, ==, !=.

Não existe os operadores ++ ou -- e += e similares somente são usados em comandos de atribuição (atribuições nunca são expressões em Python).

Alguns dos operadores são utilizados também para outros tipos. Por exemplo, + também funciona como concatenador de string quando ambos os operandos são strings.

Para "if", "while", e outros contextos onde um valor booleano é requerido, os valores False, 0, 0.0, "", e None, alguns outros valores "vazios", são tratados como falso, tudo mais como verdadeiro.

for

Mais saudações

#Execute isso como: python hello5.py nome1 nome2 nome3 ...
import sys
print "saudações,",
if len(sys.argv) == 1:

    print "meu amigo sem nome"

elif len(sys.argv) == 2:

    print sys.argv[1]

else:

    for nome in sys.argv[1:-1]:
        print nome + ",",
    print "and", sys.argv[-1]

A novidade aqui é o loop "for", que interage sobre uma sequência de valores, como uma lista. À "nome" é atribuído o valor de cada argumento da linha de comando, e então o bloco de dentro do "for" é executado. Isto tende a ser mais conveniente do que fazer indexação explícita com "while".

A outra coisa divertida é o uso de slices (fatias). Slices são uma maneira de criar uma nova lista de elementos a partir de outra lista. Dada uma lista "foo", "foo[i]" é o elemento com índice i, "foo[a:b]" é uma nova lista com todos os elementos até o índice a, mas não inclui o índice b. Para diversão extra, i, a, e b podem todos ser negativos, nesse caso seus índices se posicionam no fim da lista, então "foo[-1]" é o último elemento. Assim, "sys.argv[1:-1]" é todos os argumentos da linha de comando, do primeiro depois do nome do programa, mas não inclui o último.

O índice a e b podem também estar faltando; neste caso, o final correspondente do fim da lista é usado. "foo[a:]" é tudo do índice a até o fim da lista. "foo[b:]" é tudo do começo da lista, mas não inclui o índice b. "foo[:]" é uma cópia da lista toda.

Funções

As saudações nunca acabam, não é?

#Execute isso como: python hello6.py nome1 nome2 nome3 ...
import sys

def greet(saudacao, nomes):
    print saudacao + ",",
    if not nomes:
        print "meu amigo sem nome"
    elif len(nomes) == 1:
        print nomes[0]
    else:
        for name in nomes[:-1]:
            print nome + ",",
        print "and", nomes[-1]

greet("Olá", sys.argv[1:])

Aqui nós vemos como uma função é definida. Veja que os nomes dos argumentos (se tiver algum) são declarados, mas não seus tipos, nenhum é de retorno. Toda tipagem é dinâmica no Python.

Veja também que a função pega a lista de nomes a ser cumprimentada, and sys.argv começa com o nome do programa, então o programa principal tira-o fora com um slice quando chama a função.

hashbanging

Meu saco de programas helloworld é infinito!

import sys

def greet(saudacao, nomes):

    print greeting + ",",
    if not nomes:
        print "meu amigo sem nome"
    elif len(nomes) == 1:
        print nomes[0]
    else:
        for name in nomes[:-1]:
            print name + ",",
        print "e", nomes[-1]

def main():

    greet("Olá", sys.argv[1:])

main()

Isto é como fazer um script Python que execute como qualquer comando, sem prefixar o comando com "python". Somente salve isto num arquivo "hello7", chmod +x o arquivo, e então execute-o com "./hello7".

O programa main do Python é normalmente colocado numa função (frequentemente chamada "main"). A função é então chamada diretamente ou, melhor, assim:

if __name__ == "__main__":

    main()

"name" é uma variável especial do Python que tem o valor "main" se o arquivo Python é executado diretamente. Isto permite que o arquivo seja usado com um módulo Python (i.e., com "import") sem chamar o programa principal. Isto também pode ser usado para chamar unit testing.

I/O

Eu acho que devemos ser muito educados agora.

import sys

line_count = 0
while True:

    line = sys.stdin.readline()
    if not line:
        break
    line_count += 1

sys.stdout.write("%d lines\n" % line_count)

Este programa conta o número de linhas na entrada padrão.

"sys.stdin", "sys.stdout", e "sys.stderr" são objetos de arquivos que correspondem a entrada, saída e fluxo de erros padrão.

Objetos de arquivo têm um método ".readline()" que lê e retorna a próxima linha, incluindo uma nova linha ou uma string vazia se for EOF.

Similarmente, ".write()" é um método de objeto de arquivo que escreve uma string num arquivo; ele não adiciona uma nova linha.

"if not line" testa se a variável linha é falsa ou não; é falsa se ela é uma string vazia (desde que tenha um valor string). Assim, a condição é verdadeira no fim do arquivo. "break" então pula para fora do innermost loop.

O "while True: data = f.read(); if not data: break" padrão é uma maneira comum de entrada num loop. Quando o primeiro operando do % operador é uma string, ele funciona como o sprinf no C. O primeiro operando atua como o formato da string, and "%s" é substituído pelo valor da string, "%d" com um valor inteiro, etc. Os valores são pegos do segundo operando, que pode ser um simples valor, se houver somente um %algumacoisa no formato string, ou uma sequência de valores dentro de parênteses se forem vários.

Manipulação de string

Nós não estamos voltando ao hello, world.

import sys

def count_words(str):

    word_count = 0
    i = 0
    in_word = False
    while i < len(str):
        c = str[i]
        is_word_char = (c >= "a" and c <= "z") or (c >= "A" and c <= "Z")
        if in_word:
            if not is_word_char:
                in_word = False
        else:
            if is_word_char:
                in_word = True
                word_count += 1
        i += 1
    return word_count

def main():

    line_count = 0
    word_count = 0
    byte_count = 0

    while True:
        line = sys.stdin.readline()
        if not line:
            break
        byte_count += len(line)
        line_count += 1
        word_count += count_words(line)

    sys.stdout.write("%d words, %d lines, %d bytes\n" %
                     (word_count, line_count, byte_count))

main()

Este programa conta palavras, definidas com letras ou dígitos. Este é o maior exemplo ainda, e ele é também muito, muito feio. Nós faremos um mais bonito logo.

Strings podem ser usadas (em parte) como listas: "len(str)" é o tamanho da string, "str[i]" é o caracter no índice, "str[a:b]" também funciona como esperado. Não há um tipo de caracter separado; strings de caracteres simples são usadas como alternativa.

Strings podem ser comparadas com <, <=, e assim por diante; a comparação é baseada nos valores dos bytes (desde que strings sejam strings de bytes; nós chegaremos em unicode mais tarde).

A última linha do main() mostra maneira de estender comandos Python para múltiplas linhas: se uma expressão entre parênteses é muito longa, só quebre-a para a próxima linha, e tudo funcionará automaticamente. A outra maneira é usar uma barra invertida no fim da linha.

A parte feia deste código é que ele é muito específico para ASCII, quando deveria diferenciar o locale, e também não há ganho em usar "while" no loop sobre os caracteres de uma string, já que "for" também funciona.

Strings Unicode

Anúncio: eu não sou muito bom em manipulação Unicode, seja em geral ou em Python.

Caracteres Unicode são maiores que 8 bits (e você não precisa se preocupar com o quão grande ele é exatamente quando estiver usando Python). Python tem um tipo de string separado para strings Unicode. Elas funcionam muito bem como as strings normais (que são strings de bytes), mas para I/O você precisa convertê-las de e para strings de byte, usando algum tipo de codificação. A codificação depende de vários fatores, mas frequentemente é indicado usar uma codificação baseada no atual locale.

Observe que uma string Unicode do Python Unicode não é uma string UTF-8. UTF-8 é uma das codificações usadas para I/O (e armazenamento).

No código fonte, 'u"Copyright \u00A9 2006 Lars Wirzenius"' é uma string Unicode contendo os caracteres de copyright. Você não pode escrever caracteres non-ASCII dentro do código Python sem dizer ao interpretador Python que codificação e caracteres serão (eu não sei como).

"sys.stdin.readline" retorna uma string normal, que nós chamaremos de "s" aqui. "s.decode(enc)" decodifica s dentro de uma string Unicode ("u") usando alguma codificação. "u.encode(enc)" codifica em outra direção, de Unicode para string normal. "enc" pode ser "utf-8", por exemplo. "locale.getpreferredencoding()" retorna a codificação preferida para o atual locale.

Contador de palavras revisitado

Vamos aplicar o que aprendemos para contar palavras

import locale
import sys

def count_words(str):

    word_count = 0
    in_word = False
    for c in str:
        if in_word and not c.isalnum():
            in_word = False
        elif not in_word and c.isalnum():
            in_word = True
            word_count += 1
    return word_count

def main():

    locale.setlocale(locale.LC_ALL, "")

    line_count = 0
    word_count = 0
    char_count = 0

    while True:
        line = sys.stdin.readline()
        if not line:
            break
        line = line.decode(locale.getpreferredencoding())
        char_count += len(line)

        line_count += 1 

        word_count += count_words(line)

    sys.stdout.write("%d words, %d lines, %d chars\n" %
                     (word_count, line_count, char_count))

main()

Além da discussão acima sobre Unicode, a linha 'locale.setlocale(locale.LC_ALL, "")' é necessária para ativar as configurações do locale.

Mais jogo de palavras: imprimir todas as palavras

Vamos escrever palavras.

import locale
import sys

def split_words(str):

    words = []
    word = None
    for c in str + " ":
        if word:
            if c.isalnum():
                word += c
            else:
                words.append(word)
                word = None
        else:
            if c.isalnum():
                word = c
    return words

def main():

    locale.setlocale(locale.LC_ALL, "")
    encoding = locale.getpreferredencoding()

    while True:
        line = sys.stdin.readline()
        if not line:
            break
        line = line.decode(encoding)
        for word in split_words(line):
            sys.stdout.write("%s\n" % word.encode(encoding))

main()

Uma lista vazia é escrita como "[]". Uma lista não vazia pode ser escrita como esta: '[1, 2, 3, "hello"]'. "list.append(item)" modifica a lista no lugar e adiciona um novo item no fim. Listas podem ser concatenadas: "[1,2] + [3,4]" nos dá "[1,2,3,4]".

A função split_words cria novas listas (e novas strings) indiscriminadamente, elas não são freed em qualquer lugar do programa; Python faz a coleta de lixo, que é uma coisa muito boa de se ter.

The 'str + " "' thing in split_words is there so that there is a guaranteed non-isalnum character so that if the line ends with a word (no newline at the end) it is still counted correctly.

Frequências de palavras: dicionários!

Vamos contar a frequência das palavras.

import locale
import sys

def split_words(str):

    words = []
    word = None
    for c in str + " ":
        if word:
            if c.isalnum():
                word += c
            else:
                words.append(word)
                word = None
        else:
            if c.isalnum():
                word = c
    return words

def main():

    locale.setlocale(locale.LC_ALL, "")
    encoding = locale.getpreferredencoding()

    counts = {}

    while True:
        line = sys.stdin.readline()
        if not line:
            break
        line = line.decode(encoding)
        for word in split_words(line):
            word = word.lower()
            if counts.has_key(word):
                counts[word] += 1
            else:
                counts[word] = 1

    words = counts.keys()
    words.sort()
    for word in words:
        sys.stdout.write("%d %s\n" % (counts[word], word.encode(encoding)))

main()

As mudanças estão no programa principal. As tabelas hash do Python (ou mapas hash) são chamadas de dicionários. Um dicionário vazio: "{}". Um não vazio: '{ "foo": 0, "bar": 1 }'. "dict[key]" é o valor armazenado em uma dada chave. Chaves podem ser números, strings, ou vários outros tipos que Python saiba como calcular um valor hash.

"dict.has_key(key)" é True se "dict[key]" existe (foi atribuído). Alternativamente "key in dict". "dict.keys()" é uma lista não classificada de todas as chaves. O método string ".lower()" converte para minúsculas, retornando a nova string (a original não é modificada; strings não podem ser modificadas em Python). Similarmente, ".upper()" converte para maiúsculas.

"list.sort()" classifica no lugar (a lista original é modificada, não retorna a lista classificada, ou algum outro valor).

Vamos ter alguma classe

Vamos ver como classes e objetos são usados em Python.

import locale
import sys

class [:Portuguese/WordFreqCounter:WordFreqCounter]

    def __init__(self):
        self.counts = {}

    def count_word(self, word):
        word = word.lower()
        if self.counts.has_key(word):
            self.counts[word] += 1
        else:
            self.counts[word] = 1

    def print_counts(self, file):
        encoding = locale.getpreferredencoding()
        words = self.counts.keys()
        words.sort()
        for word in words:
            file.write("%d %s\n" %
                       (self.counts[word], word.encode(encoding)))

def split_words(str):

    words = []
    word = None
    for c in str + " ":
        if word:
            if c.isalnum():
                word += c
            else:
                words.append(word)
                word = None
        else:
            if c.isalnum():
                word = c
    return words

def main():

    locale.setlocale(locale.LC_ALL, "")
    encoding = locale.getpreferredencoding()

    counter = [:Portuguese/WordFreqCounter:WordFreqCounter])

    while True:
        line = sys.stdin.readline()
        if not line:
            break
        line = line.decode(encoding)
        for word in split_words(line):
            counter.count_word(word)

    counter.print_counts(sys.stdout)

main()

Neste exemplo, nós colocamos o dicionário dentro da classe. Isto não importa realmente em um programa pequeno como esse, se nós temos uma classe personalizada ou um dicionário sem formatação, mas faremos isto com a finalidade de demonstrar.

"class" começa a definição de classe. Uma classe é instanciada dizendo "ClassName)" (com argumentos, se tiver algum, ao construtor dentro dos parênteses).

Métodos são definidos como funções dentro da classe, i.e., eles precisam ser indentados de acordo com a linha da classe. Métodos são diretos, exceto para o primeiro argumento, habitualmente chamado "self", que é uma refência à instância da classe (objeto) que os chama.

Assim, quando você chama "counter.count_word(word)", o primeiro argumento do método ("self") é limitado para "counter", e o segundo argumento ("word") é limitado para "word" (no contexto de quem chama).

Não há nenhuma maneira implícita para referenciar outros métodos ou atributos do objeto ou classe, você precisa ir sempre via "self".

O nome especial do método "init" indica o construtor. Isto é chamado quando o objeto é criado.

Simplificando ligeiramente, não há controle de acesso a atributos e em métodos do objeto no Python. Tudo é "public", na terminologia do C++.

Módulos

Primeiro o arquivo wordstuff.py:

import locale

class [:Portuguese/WordFreqCounter:WordFreqCounter]

    def __init__(self):
        self.counts = {}

    def count_word(self, word):
        word = word.lower()
        if self.counts.has_key(word):
            self.counts[word] += 1
        else:
            self.counts[word] = 1

    def print_counts(self, file):
        encoding = locale.getpreferredencoding()
        words = self.counts.keys()
        words.sort()              
        for word in words:
            file.write("%d %s\n" %
                       (self.counts[word], word.encode(encoding)))

def split_words(str):

    words = []
    word = None
    for c in str + " ":

        if word:

            if c.isalnum():
                word += c
            else:
                words.append(word)
                word = None
        else:
            if c.isalnum():

                word = c

    return words

E então o arquivo freq3.py:

import locale
import sys

from wordstuff import [:Portuguese/WordFreqCounter:WordFreqCounter] split_words

def main():

    locale.setlocale(locale.LC_ALL, "")
    encoding = locale.getpreferredencoding()

    counter = [:Portuguese/WordFreqCounter:WordFreqCounter])

    while True:
        line = sys.stdin.readline()
        if not line:
            break
        line = line.decode(encoding)
        for word in split_words(line):
            counter.count_word(word)

    counter.print_counts(sys.stdout)

if __name__ == "__main__":

    main()

freq3.py é o programa principal e usa wordstuff.py como um módulo, e importa somente certos nomes dele. Esses nomes podem ser consultados sem prefixá-los com o nome do módulo. Potencialmente, cada arquivo Python é um módulo que pode ser importado por outro arquivo. Módulos são procurados em $PYTHONPATH; olhe a documentação para mais detalhes. Usualmente você não precisa se preocupar em configurar $PYTHONPATH se as coisas foram instaladas da forma correta.

Próximo passo

Leia o tutorial em http://python.org. Dê uma olhada na biblioteca de referência e brinque com alguma coisa interessante que você encontre lá. Escreva programas, leia programas.