Introdução ao Python: História e Características
Introdução ao Python: História e Características
assas
Instituto Superior
de
Engenharia do Porto
3\WKRQ
2
Índice
ÍNDICE
Capítulo 1 Introdução 07
Breve introdução histórica 08
Características do Python 08
Librarias do Python 09
Comparação com outras linguagens 10
Java 10
JavaScript 10
Perl 11
Tcl 11
C++ 11
Empresas/Instituições que usam o Python 11
3
Python
A função range() 33
Cláusulas break, continue e else em ciclos 33
Construção pass 34
Funções 34
Parâmetros com valores por defeito 36
Parâmetros na forma Chave-Valor 37
Listas arbitrárias de argumentos 39
Funções Lambda 39
Strings de documentação 40
Capítulo 6 Módulos 51
O Caminho de busca dos módulos 53
Arquivos Python “Compilados” 54
Módulos Padrão 55
A Função dir() 55
Pacotes 56
Importando * de um pacote 58
Referências num mesmo pacote 59
4
Índice
Capítulo 9 Classes 75
Uma palavra sobre terminologia 76
Escopos e espaços de nomes no Python 77
Sintaxe da definição de Classes 78
Objectos de Classes 79
Instâncias 80
Métodos dos Objectos 80
Observações aleatórias 81
Herança 83
Herança múltipla 83
Variáveis Privadas 84
Particularidades 85
As Excepções podem ser Classes 85
Capítulo 10 Conclusão 87
JPython (o futuro) 88
5
Python
6
Introdução
Introdução
7
Python
Introdução
As linguagens de programação têm sido criadas pelas mais variadas razões. Uma das
mais recentes é o Python, uma linguagem que possui características muito semelhantes às
das linguagens Perl, Awk entre outras.
A linguagem Python é uma linguagem de alto nível, interpretada, orientada a objecto
com uma semântica dinâmica. As suas estruturas de alto nível, combinadas com uma
ligação dinâmica tornam-na muito atractiva para desenvolvimento rápido de aplicações,
assim como, para uso como linguagem de script ou de ligação entre vários componentes.
A sintaxe simples do Python encoraja a reutilização de código, simplificando a
manutenção e a normalização de dados em módulos e pacotes distintos.
Esta linguagem, bem como seu código fonte, encontram-se gratuitamente disponível na
Internet podendo ser consultado por qualquer interessado sem qualquer encargo. Apesar
disso, a linguagem Python é marca registrada do Stichting Mathematisch Centrum de
Amsterdam, com todos os direitos reservados.
Características do Python
Apesar de sua sintaxe simples e clara, Python oferece os seguintes recursos disponíveis
também em linguagens mais complicadas como Java e C++:
• programação orientada a objectos (incluindo herança múltipla, conceito apenas
parcialmente presente em Java);
• excepções, um moderno mecanismo para o tratamento de erros;
• módulos, uma forma inteligente de aceder, organizar e reutilizar código;
• recolha de lixo automática, sistema que elimina os erros causados pelo acumular
de dados inúteis na memória do computador (característica presente também em
Java, mas não em C++);
8
Introdução
Librarias do Python
Como no Java, o Python possui uma grande quantidade de importantes librarias. Algumas
destas librarias são cruciais para a flexibilidade que o Python oferece aos programadores.
Algumas das mais importantes livrarias são:
9
Python
Java
Os programas em Python são geralmente mais lentos que os programas em Java, mas têm
também um período de desenvolvimento muito menor. O tempo que demora a
desenvolver um programa em Python é em média 3-5 vezes mais curto que o mesmo
programa em Java. Esta diferença pode ser atribuída aos dados de alto nível introduzidos
no Python e à sua escrita dinâmica. Por exemplo, um programador de Python, não precisa
de perder tempo na declaração do tipo de argumentos ou na declaração das variáveis, mas
devido à sua escrita em run-time, o run-time no Python tem que trabalhar mais que o do
Java o que o torna mais lento.
Por estas razões o Python pode-se caracterizar como uma linguagem de “ligação (glue)”,
enquanto que o Java caracteriza-se como uma linguagem de baixo nível. De facto as duas
fazem uma excelente combinação, os componentes podem ser desenvolvidos em Java e
combinados de maneira a formar aplicações em Python.
JavaScript
O modelo base de objectos do Python é muito parecido com o do JavaScript. Como o
JavaScript, (e diferente do Java), o Python permite uma programação com funções
simples e variáveis sem serem declaradas. Contudo para o JavaScript é tudo, enquanto
que o Python permite a escrita de programas muito maiores e uma melhor reutilização de
código, através do estilo de programação orientada a objecto onde as classes e a herança
têm um papel preponderante.
10
Introdução
Perl
O Python e o Perl têm uma base muito similar, têm muitas características semelhantes,
mas têm uma filosofia diferente. O Perl está mais virado para permitir tarefas mais
comuns orientadas para a aplicação. O Python por sua vez tenta debruçar-se mais em
apoiar as metodologias de programação mais comuns como o desígnio das estruturas de
dados e a programação orientada a objecto. O Phyton está muito próximo do Perl, mas
raramente lhe ganha no seu domínio original. No entanto o Python tem uma boa
aplicação para além do domínio do Perl.
Tcl
Como o Python, o Tcl é usado como uma linguagem de extensão entre aplicações, bem
como uma simples linguagem de programação. Contudo, o Tcl, guarda todos os tipos de
dados como strings o que o torna muito limitado no tratamento de estruturas de dados.
Além disso o tempo de execução do Tcl, é muito maior que o do Python. As
características do Tcl não permitem que sejam escritos programas muito extensos. Por
isso uma aplicação grande que use o Tcl, geralmente contém extensões escritas em C ou
C++, que são específicas para a dada aplicação, uma aplicação equivalente desenvolvida
em Python pode ser toda escrita em “Python puro”. Claro que, puro desenvolvimento em
Python é muito mais rápido que ter que escrever e fazer o “debug” de um componente em
C ou C++.
C++
Tudo o que foi dito para o Java , também pode ser aplicado ao C++, com a diferença de o
tempo de desenvolvimento de C++ em relação o Python ser 5-10 vezes superior em vez
de 3-5 vezes superior para o Java. Esta grande diferença sugere que, o que um
programador de Python faria em 2 meses, levaria um ano a ser feito por dois
programadores de C++.
11
Python
12
O Interpretador do Python
O Interpretador do Python
13
Python
O Interpretador do Python
Vamos mostrar como usar o interpretador numa máquina Unix
O interpretador é frequentemente instalado como ‘/usr/local/bin/python’ nas máquinas em que
é disponibilizado. Se se adicionar ‘/usr/local/bin’ ao caminho de busca (search path) da
shell de seu Unix torna-se possível iniciá-lo digitando :
python
na shell.
Digitando um caracter EOF() (Control-D on Unix, Control-Z no DOS ou
Windows) directamente no prompt, força o interpretador a sair com status de saída zero.
Se isso não funcionar, pode-se sair do interpretador através da digitação do seguinte:
‘import sys; [Link]()’.
As características de edição de linha não são muito sofisticadas. Sobre Unix, pode-se
instalar a biblioteca readline da GNU, que adiciona facilidades mais elaboradas de edição
e histórico de comandos. Sem esta biblioteca apenas se poderá usar o backspace para
remover caracteres da linha corrente.
O interpretador trabalha de forma semelhante a uma shell de Unix:
• quando disparado com a saída padrão conectada a uma consola de terminal (tty
device), ele lê e executa comandos interactivamente;
• quando disparado com um nome de arquivo como parâmetro ou com
redireccionamento da entrada padrão para um arquivo, o interpretador irá ler e
executar o script contido em tal arquivo.
Uma terceira forma de disparar o interpretador é ‘python -c command [arg] ...’,
que executa o(s) comando(s) especificados na posição command, analogamente a opção
de shell -c. Considerando que comandos Python possuem frequentemente espaços em
branco (ou outros caracteres que sejam especiais para a shell) é aconselhável que o
comando especificado em command esteja dentro de aspas.
Quando um arquivo de script é utilizado, às vezes é útil ser capaz de executá-lo para logo
em seguida entrar em modo interactivo. Este efeito pode ser obtido pela adição do
parâmetro -i antes do nome do script.
Passar Argumentos
O nome do script e subsequentes parâmetros da linha de comando da shell são acessíveis
ao próprio script através da variável [Link], que é uma lista de strings. Essa lista
tem sempre pelo menos um elemento; quando nenhum script ou parâmetro forem
passados para o interpretador, [Link][0] será uma lista vazia. Quando o nome
do script for ’-’ ( significando entrada padrão), o conteúdo de [Link][0] será
’-’. Quando for utilizado -c command, [Link][0] conterá ’-c’. Opções
14
O Interpretador do Python
especificadas após -c command não serão consumidas pelo interpretador mas serão
armazenadas em [Link].
Modo Interactivo
Quando os comandos são lidos a partir da consola (tty), diz-se que o interpretador está em
modo interativo. Nesse modo ele requisita por um próximo comando através do prompt
primário, tipicamente três sinais de “maior que” (‘>>> ’); para linhas de continuação do
comando corrente, o prompt secundário por defeito são três pontos (‘... ’).
O interpretador imprime uma mensagem de boas vindas, informando a sua versão e uma
nota legal de copyright antes de oferecer o primeiro prompt, ex.:
python
Python 1.5.2b2 (#1, Feb 28 1999, 00:02:06) [GCC 2.8.1] on sunos5
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>>
Tratamento de Erros
Quando ocorre um erro, o interpretador imprime uma mensagem de erro e a situação da
pilha (daqui em diante stack trace). No modo interactivo, retorna-se ao prompt primário;
quando a entrada vem de um arquivo, o interpretador aborta sua execução com status de
erro diferente de zero após imprimir o stack trace (Excepções tratadas por um except
num bloco try não são consideradas erros neste contexto). Alguns erros são
incondicionalmente fatais e causam a saída com status diferente de zero; isto se aplica a
inconsistências internas e alguns casos de exaustão de memória. Todas as mensagens de
erro são escritas na saída de erros padrão (standard error), enquanto que a saída dos
demais comandos é direccionada para a saída padrão.
Ao teclar num o caracter de interrupção (tipicamente Control-C ou DEL) no prompt
primário ou secundário cancela a entrada de dados corrente e retorna-se ao prompt
primário. Provocando uma interrupção enquanto um comando está em execução levanta
a excepção KeyboardInterrupt, a qual pode ser tratada em um bloco try.
15
Python
16
Uma introdução informal ao Python
17
Python
Números
O interpretador actua como uma calculadora bem simples: pode-se digitar uma expressão
e o resultado será apresentado após a avaliação da expressão. A sintaxe da expressão é a
usual: operadores +, -, * e / funcionam da mesma forma que nas outras linguagens
tradicionais (por exemplo, Pascal ou C); parênteses podem ser usados para definir
agrupamentos. Por exemplo:
>>> 2+2
4
>>> # Isso é um comentário
... 2+2
4
>>> 2+2 # e um comentário na mesma linha de um comando
4
>>> (50-5*6)/4
5
>>> # Divisão inteira retorna com arredondamento para base
... 7/3
18
Uma introdução informal ao Python
2
>>> 7/-3
-3
Como em C, o sinal de igual (‘=’) é utilizado para atribuição de um valor a uma variável.
O valor da atribuição não é escrito:
>>> width = 20
>>> height = 5*9
>>> width * height
900
Números complexos também são suportados; números imaginários são escritos com o
sufixo ‘j’ ou ‘J’. Números complexos com parte real não nula são escritos como
‘(real+imagj)’, ou podem ser criados pela chamada de função ‘complex(real, imag)’.
>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)
Números complexos são sempre representados por dois números ponto-flutuante, a parte
real e a parte imaginária.
Para extrair as partes de um número z, utilize [Link] e [Link].
>>> a=1.5+0.5j
19
Python
>>> [Link]
1.5
>>> [Link]
0.5
Essa variável especial deve ser tratada somente para leitura pelo usuário. Nunca lhe
atribua explicitamente um valor, caso contrário, estaria a ser criada uma outra variável
(homónima) independente, que mascararia o comportamento mágico da variável especial.
Strings
Além de números, o Python também pode manipular strings, que podem ser expressas de
diversas formas. Elas podem ser delimitadas por plicas ou aspas:
>>> ’spam eggs’
’spam eggs’
>>> ’doesn\’t’
"doesn’t"
>>> "doesn’t"
20
Uma introdução informal ao Python
"doesn’t"
>>> ’"Yes," he said.’
’"Yes," he said.’
>>> "\"Yes,\" he said."
’"Yes," he said.’
>>> ’"Isn\’t," she said.’
’"Isn\’t," she said.’
Strings que contém mais de uma linha podem ser construídas de diversas maneiras.
Terminadores de linha podem ser colocados na string com barras invertidas, ex.:
ola = "Esta é uma string longa contendo\n\
diversas linhas de texto com se faz em C.\n\
Observe que os espaços em branco no inicio da linha são \
significativos.\n"
print ola
Ou, strings podem ser delimitadas por pares de aspas tríplices: " ou ’’’. Neste caso não
é necessário embutir terminadores de linha, pois o texto da string será tratado verbatim.
print """
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
"""
21
Python
Strings podem ser indexadas; como no C, o primeiro índice da string é o 0. Não existe um
tipo separado para caracteres; um caracter é simplesmente uma string unitária. Assim
como na linguagem Icon, substrings podem ser especificadas através da notação slice
(N.d.T: fatiar): dois índices separados por dois pontos.
>>> word[4]
’A’
>>> word[0:2]
’He’
>>> word[2:4]
’lp’
Ao contrário do C, strings não podem ser alteradas em Python. Atribuir para uma posição
(índice) dentro de uma string resultará em erro:
>>> word[0] = ’x’
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn’t support item assignment
>>> word[:1] = ’Splat’
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn’t support slice assignment
Entretanto, criar uma nova string com o conteúdo combinado é fácil e eficiente:
>>> ’x’ + word[1:]
’xelpA’
>>> ’Splat’ + word[4]
’SplatA’
22
Uma introdução informal ao Python
Índices de slice possuem valores por defeito úteis; o primeiro índice se omitido possui
valor por defeito 0, o segundo possui valor por defeito igual ao tamanho da string.
>>> word[:2] # Os dois primeiros caracteres
’He’
>>> word[2:] # Todos menos os dois primeiros caracteres
’lpA’
Índices de slice degenerados são tratados “graciosamente” (N.d.T: este termo indica
robustez no tratamento de erros): um índice muito maior que o comprimento é trocado
pelo comprimento, um limitante superior que seja menor que o limitante inferior produz
uma string vazia como resultado.
>>> word[1:100]
’elpA’
>>> word[10:]
’’
>>> word[2:1]
’’
Índices podem ser números negativos, para iniciar a contagem a partir da direita ao invés
da esquerda. Por exemplo:
>>> word[-1] # O último caracter
’A’
>>> word[-2] # O penúltimo caracter
’p’
>>> word[-2:] # Os dois ´ultimos caracteres
’pA’
>>> word[:-2] # Todos menos os dois últimos caracteres
’Hel’
Note-se que -0 é o mesmo que 0, logo neste caso não se conta a partir da direita!
>>> word[-0] # ( -0 == 0)
’H’
Intervalos fora dos limites da string são truncados, mas não tente isso em indexações com
um único índice (que não seja um slice):
>>> word[-100:]
’HelpA’
>>> word[-10] # error
Traceback (most recent call last):
File "<stdin>", line 1
IndexError: string index out of range
A melhor maneira de se lembrar como os slices funcionam é pensar nos índices como
ponteiros para os espaços entre caracteres, onde a beirada esquerda do primeiro caracter é
23
Python
0. Logo a beirada direita do último caracter de uma string de comprimento n tem índice n,
por exemplo:
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
A primeira fileira de números indica a posição dos índices 0..5 na string; a segunda fileira
indica a posição dos respectivos índices negativos. Um slice de i até j consiste em todos
os caracteres entre as beiradas i e j, respectivamente.
Para índices positivos, o comprimento do slice é a diferença entre os índices, se ambos
estão dentro dos limites da string, ex, o comprimento de word[1:3] é 2.
A função interna (N.d.T: interna == built-in) len() devolve o comprimento de uma
string:
>>> s = ’supercalifragilisticexpialidocious’
>>> len(s)
34
Strings Unicode
A partir de Python 2.0 um novo tipo foi introduzido: o objecto Unicode. Este objecto
pode ser usado para armazenar e manipular dados Unicode e se integra bem aos demais
objectos strings pré existentes de forma a realizar auto-conversões quando necessário.
O Unicode tem a vantagem de prover um único número ordinal para cada caracter usado
em textos modernos ou antigos. Previamente, havia somente 256 números ordinais. Logo,
mapeamentos entre conjuntos de caracteres e os 256 números ordinais precisavam ser
indexados por códigos de página. Isso levou a uma enorme confusão especialmente no
âmbito da internacionalização (tipicamente escrito como ‘i18n’ – ‘i’ + 18 caracteres +
‘n’) de software. Unicode resolve esses problemas ao definir um único código de página
para todos os conjuntos de caracteres.
Criar strings Unicode em Python é tão simples quanto criar strings normais:
>>> u’Hello World !’
u’Hello World !’
O pequeno ‘u’ antes das aspas indica a criação de uma string Unicode . Se você desejar
incluir caracteres especiais na string, você pode fazê-lo através da codificação Python
Unicode-Escape.
>>> u’Hello\u0020World !’
u’Hello World !’
O código de escape \u0020 indica a inserção do caracter Unicode com valor ordinal
0x0020 (o espaço em branco) na posição determinada.
24
Uma introdução informal ao Python
O modo cru (N.d.T: raw) é muito útil para evitar excesso de barras invertidas em
expressões regulares.
Além dessas codificações padrão, Python oferece um outro conjunto de maneiras de se
criar strings Unicode sobre uma codificação padrão.
A função interna unicode() provê acesso a todos os Unicode codecs registrados
(COders and DECoders).
Alguns dos mais conhecidos codecs são : Latin-1, ASCII, UTF-8, and UTF-16. Os dois
últimos são codificações de tamanho variável para armazenar cada caracter Unicode em
um ou mais bytes. A codificação por defeito é ASCII, que trata normalmente caracteres
no intervalo de 0 a 127 mas rejeita qualquer outro com um erro. Quando uma string
Unicode é impressa, escrita em arquivo ou convertida por str(), a codificação padrão é
utilizada.
>>> u"abc"
u’abc’
>>> str(u"abc")
’abc’
>>> u"¨a¨o¨u"
u’\xe4\xf6\xfc’
>>> str(u"¨a¨o¨u")
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)
Para se converter uma string Unicode em uma string 8-bits usando uma codificação
específica, basta invocar o método encode() de objectos Unicode passando como
parâmetro o nome da codificação destino. É preferível utilizar nomes de codificação em
letras minúsculas.
>>> u"¨a¨o¨u".encode(’utf-8’)
’\xc3\xa4\xc3\xb6\xc3\xbc’
Também pode ser utilizada a função unicode() para efectuar a conversão de uma
string em outra codificação.
25
Python
Listas
Python possui diversas estruturas de dados nativas, utilizadas para agrupar outros valores.
A mais versátil delas é a lista (list), que pode ser escrita como uma lista de valores
separados por vírgula e entre colchetes. Mais importante, os valores contidos na lista não
precisam ser do mesmo tipo.
>>> a = [’spam’, ’eggs’, 100, 1234]
>>> a
[’spam’, ’eggs’, 100, 1234]
Da mesma forma que índices de string, índices de lista começam do 0, listas também
podem ser concatenadas e sofrer o operador de slice.
>>> a[0]
’spam’
>>> a[3]
1234
>>> a[-2]
100
>>> a[1:-1]
[’eggs’, 100]
>>> a[:2] + [’bacon’, 2*2]
[’spam’, ’eggs’, ’bacon’, 4]
>>> 3*a[:3] + [’Boe!’]
[’spam’, ’eggs’, 100, ’spam’, ’eggs’, 100, ’spam’, ’eggs’, 100, ’Boe!’]
Ao contrário das strings, que são imutáveis, é possível mudar elementos individuais da
lista:
>>> a
[’spam’, ’eggs’, 100, 1234]
>>> a[2] = a[2] + 23
>>> a
[’spam’, ’eggs’, 123, 1234]
Atribuição à fatias (slices) é possível, e isso pode até alterar o tamanho da lista:
>>> # Replace some items:
... a[0:2] = [1, 12]
>>> a
[1, 12, 123, 1234]
>>> # Remove some:
26
Uma introdução informal ao Python
... a[0:2] = []
>>> a
[123, 1234]
>>> # Insert some:
... a[1:1] = [’bletch’, ’xyzzy’]
>>> a
[123, ’bletch’, ’xyzzy’, 1234]
>>> a[:0] = a # Insert (a copy of) itself at the beginning
>>> a
[123, ’bletch’, ’xyzzy’, 1234, 123, ’bletch’, ’xyzzy’, 1234]
27
Python
1
1
2
3
5
8
28
Uma introdução informal ao Python
29
Python
30
Ferramentas de controle de fluxos
Ferramentas de controle de
fluxos
31
Python
Construção do if
Provavelmente uma das mais conhecidas construções é o if. Por exemplo:
>>> x = int(raw_input("Por favor entre com um numero: "))
>>> if x < 0:
... x = 0
... print ’Negativo mudou para zero’
... elif x == 0:
... print ’Zero’
... elif x == 1:
... print ’Um’
... else:
... print ’Mais’
...
Pode haver zero ou mais secções elif. A secção else é opcional. A palavra-chave
‘elif’ ´e uma abreviação para ‘else if’, e é útil para evitar identação excessiva. Uma
sequência if . . . elif . . . elif . . . substitui as construções switch e case
encontradas nas outras linguagens.
Construção do for
A construção do for em Python difere um pouco do que se está acostumado em C ou
Pascal. Ao invés de se iterar sobre progressões aritméticas (como em Pascal), ou fornecer
ao usuário a habilidade de definir tanto o passo da iteração quanto a condição de parada
(como no C), o for do Python itera sobre os itens de uma sequência (ex.: uma lista ou
uma string), na ordem em que aparecem na sequência. Por exemplo :
>>> # Medindo algumas strings:
... a = [’gato’, ’janela’, ’leite’]
>>> for x in a:
... print x, len(x)
...
gato 4
janela 6
leite 5
Não é seguro modificar a sequência sobre a qual se baseia o ciclo da iteração (isto só
pode acontecer se a sequência for mutável, isto é, uma lista). Se se precisar modificar a
32
Ferramentas de controle de fluxos
lista sobre a qual se está iterando, por exemplo, para duplicar itens seleccionados, você
deve iterar sobre uma cópia da lista ao invés da própria. A notação slice é particularmente
conveniente para isso:
>>> for x in a[:]: # faz uma cópia da lista inteira
... if len(x) > 6: [Link](0, x)
...
>>> a
[’defenestrar’, ’gato’, ’janela’, ’defenestrar’]
A função range()
Pare se poder iterar sobre sequências numéricas, a função interna range()é a resposta.
Ela gera listas contendo progressões aritméticas, ex.:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
O ponto de parada fornecido nunca é gerado na lista; range(10) gera uma lista com
10 valores, exactamente os índices válidos para uma sequência de comprimento 10. É
possível iniciar o intervalo em outro número, ou alterar a razão da progressão:
>>> range(5, 10)
[5, 6, 7, 8, 9]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]
Para se iterar sobre os índices de uma sequência, deve-se combinar o range() com o
len() da seguinte forma:
>>> a = [’Mary’, ’had’, ’a’, ’little’, ’lamb’]
>>> for i in range(len(a)):
... print i, a[i]
...
0 Mary
1 had
2 a
3 little
4 lamb
33
Python
Os ciclos podem ter uma cláusula else, que é executada sempre que o ciclo termina,
quer quando se ciclo se encerra por exaustão da lista (no casodo for), quer quando a
condição se torna falsa (no caso do while), mas nunca quando o ciclo é encerrado por
um break. Isto é exemplificado no próximo exemplo que procura números primos:
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print n, ’equals’, x, ’*’, n/x
... break
... else:
... print n, ’is a prime number’
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
Construção pass
A construção pass não faz nada. Ela pode ser usada quando a sintaxe exige um comando
mas a semântica do programa não requer nenhuma acção. Por exemplo:
>>> while 1:
... pass # Busy-wait para interrupção do teclado
...
Funções
A função que se segue escreve a série de Fibonacci até um limite arbitrário:
>>> def fib(n): # escreve a serie de Fibonacci ate n
... "Print a Fibonacci series up to n"
... a, b = 0, 1
... while b < n:
... print b,
... a, b = b, a+b
...
>>> # Agora invoca a função que acabamos de definir
... fib(2000)
34
Ferramentas de controle de fluxos
A palavra reservada def serve para definir uma função. Ela deve ser seguida do nome da
função, da lista formal de parâmetros entre parênteses e dois pontos.
O corpo da função deve começar na linha seguinte e deve ser identado. Opcionalmente, a
primeira linha do corpo da função pode ser uma string literal, cujo propósito é
documentar a função. A essa string dá-se o nome de docstring.
Existem ferramentas que utilizam docstrings para produzir automaticamente
documentação impressa, on-line, ou ainda permitir que o usuário navegue
interactivamente pelo código. É uma boa prática incluir sempre docstrings nas funções.
A execução da função gera uma nova tabela de símbolos utilizada para as variáveis locais
da função, mais precisamente, toda atribuição a variáveis dentro da função armazena o
valor na tabela de símbolos local. Referências às variáveis são procuradas primeiramente
na tabela local, depois na tabela de símbolos global e finalmente na tabela de símbolos
interna (built-in). Portanto, não se pode atribuir directamente um valor a uma variável
global dentro de uma função (a menos que se utilize a declaração global antes), ainda
que variáveis globais possam ser referenciadas livremente.
Os parâmetros reais (argumentos) de uma chamada da função são introduzidos na tabela
de símbolos local da função chamada, portanto, os argumentos são passados por valor
(onde valor é sempre uma referência para o objecto, não o valor do objecto). Quando uma
função chama outra, uma nova tabela de símbolos é criada para tal chamada.
Uma definição da função introduz o nome da função na tabela de símbolos corrente. O
valor do nome da função possui um tipo que é reconhecido pelo interpretador como uma
função definida pelo usuário. Esse valor pode ser atribuído para outros nomes que
também podem ser usados como funções. Esse mecanismo serve para renomear funções:
>>> fib
<function object at 10042ed0>
>>> f = fib
>>> f(100)
1 1 2 3 5 8 13 21 34 55 89
Pode-se afirmar que fib não é uma função, mas um procedimento. No Python, assim
como no C, procedimentos são apenas funções que não retornam valores. Na verdade,
falando tecnicamente, procedimentos retornam o valor None (é um nome interno). A
escrita do valor None é supressa pelo interpretador se ele estiver sozinho. Para verificar
isso basta:
>>> print fib(0)
None
É muito simples escrever uma função que retorna a lista da série de Fibonacci, ao invés
de imprimi-la:
>>> def fib2(n):
... "Retorna a lista contendo a serie de Fibonacci ate n"
... result = []
35
Python
... a, b = 0, 1
... while b < n:
... [Link](b) # veja abaixo
... a, b = b, a+b
... return result
...
>>> f100 = fib2(100) # invoca
>>> f100 # escreve resultado
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Ainda é possível definir funções com um número variável de argumentos. Existem três
formas que podem ser combinadas.
36
Ferramentas de controle de fluxos
Essa função pode ser chamada de duas formas: ask ok(’Do you really want
to quit?’) ou como ask ok(’OK to overwrite the file?’, 2).
Os valores por defeito são avaliados durante a definição da função, e pela finalidade da
função definida:
i = 5
def f(arg = i): print arg
i = 6
f()
irá imprimir 5.
Aviso importante: Valores por defeito são avaliados apenas uma vez. Isso faz diferença
quando o valor por defeito é um objecto mutável como uma lista ou dicionário. Por
exemplo, a função a seguir acumula os argumentos passados em chamadas subsequentes:
def f(a, l = []):
[Link](a)
return l
print f(1)
print f(2)
print f(3)
Se não se quiser que o valor por defeito seja compartilhado entre chamadas subsequentes,
pode-se reescrever a função:
def f(a, l = None):
if l is None:
l = []
[Link](a)
return l
37
Python
parrot(1000)
parrot(action = ’VOOOOOM’, voltage = 1000000)
parrot(’a thousand’, state = ’pushing up the daisies’)
parrot(’a million’, ’bereft of life’, ’jump’)
Em geral, uma lista de argumentos tem que apresentar todos argumentos posicionais
antes de qualquer um dos seus argumentos chave-valor, onde as chaves têm que ser
escolhidas a partir dos nomes formais dos argumentos.
Não é importante se um dado argumento já possuía valor por defeito ou não. Nenhum
argumento deve receber um valor mais do que uma única vez. Nomes de parâmetros
formais correspondendo a argumentos posicionais não podem ser usados na forma chave-
valor numa mesma chamada. O próximo exemplo ilustra essa limitação.
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: keyword parameter redefined
Quando o último parâmetro formal for **name, ele irá armazenar todos os parâmetros
efectivamente passados para a função, que não correspondiam a parâmetros formais. Isto
pode ser combinado com o parâmetro formal *name que recebe a lista contendo todos
argumentos posicionais que não correspondiam a parâmetros formais. O importante é que
(*name deve ser declarado antes de **name.):
def cheeseshop(kind, *arguments, **keywords):
print "-- Do you have any", kind, ’?’
print "-- I’m sorry, we’re all out of", kind
for arg in arguments: print arg
print ’-’*40
for kw in [Link](): print kw, ’:’, keywords[kw]
38
Ferramentas de controle de fluxos
e naturalmente produziria:
-- Do you have any Limburger ?
-- I’m sorry, we’re all out of Limburger
It’s very runny, sir.
It’s really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
Funções Lambda
Dado os pedidos do público, algumas características encontradas em linguagens de
programação funcionais (como Lisp) foram adicionadas ao Python. Com a palavra-chave
lambda, funções curtas e anónimas podem ser criadas.
Aqui está uma função que devolve a soma de seus dois argumentos: ‘lambda a, b:
a+b’. Funções Lambda podem ser utilizadas em qualquer lugar que exigiria uma função
tradicional. Sintacticamente, funções Lambda estão restritas a uma única expressão.
Semanticamente, ela são apenas açúcar sintáctico para a definição de funções normais.
Assim como definições de funções aninhadas, funções lambda não podem referenciar
variáveis de um escopo mais externo, o que pode ser contornado pelo parcimonioso uso
de argumentos com valores por defeito:
>>> def make_incrementor(n):
... return lambda x, incr=n: x+incr
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
>>>
Strings de documentação
Há uma convenção sobre o conteúdo e formato de strings de documentação.
39
Python
A primeira linha deve ser sempre curta, representando um conciso sumário do propósito
do objecto. Não se deve explicitamente referir ao nome ou tipo do objecto, uma vez que
estas informações estão disponíveis por outros meios (excepto se o nome da função for o
próprio verbo que descreve a finalidade da função). Essa linha deve começar com uma
letra maiúscula e terminar com ponto.
Se existem múltiplas linhas na string de documentação, a segunda linha deve estar em
branco, o sumário deve estar separado do resto da descrição. As linhas seguintes devem
conter um ou mais parágrafos descrevendo as convenções da chamada ao objecto, seus
efeitos colaterais, etc.
O parser do Python não toca na identação de comentários multi-linha. Portanto,
ferramentas que processem strings de documentação precisam lidar com isso (se
desejado). Existe uma convenção para isso. A primeira linha não nula após a linha de
sumário determina a identação para o resto da string de documentação. A partir daí, os
espaços em branco podem ser removidos de todas as linhas da string.
Aqui está um exemplo de uma docstring multi-linha:
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn’t do anything.
... """
... pass
...
>>> print my_function.__doc__
Do nothing, but document it.
No, really, it doesn’t do anything.
40
Estruturas de Dados
Estruturas de Dados
41
Python
Estruturas de Dados
Este capítulo descreve alguns pontos já abordados, mas mais detalhados, e ainda adiciona
outros pontos inéditos.
Listas
O tipo list possui mais métodos. Aqui estão todos os métodos disponíveis para um
objecto lista.
append(x) Adiciona um item ao fim da lista; equivalente a a[len(a):] = [x].
extend(L) Estende a lista adicionando no fim todos os elementos da lista passada
como parâmetro; equivalente a a[len(a):] = L.
insert(i, x) Insere um item em uma posição especificada. O primeiro argumento é
o índice do elemento anterior ao que está para ser inserido, assim [Link](0, x)
insere no início da lista, e [Link](len(a), x) é equivalente a [Link](x).
remove(x) Remove o primeiro item da lista cujo valor é x. Caso o valor x não é
gerado um erro.
pop([i]) Remove o item na posição dada e o retorna o seu valor. Se nenhum item for
especificado, [Link]() remove e retorna o último item na lista.
index(x) Retorna o índice do primeiro item cujo valor é igual ao argumento
fornecido em x, se este valor não existir gera um erro.
count(x) Retorna o número de vezes que o valor x aparece na lista.
sort() Ordena os itens da lista sem gerar uma nova lista.
reverse() Inverte a ordem dos elementos na lista sem gerar uma nova lista.
Um exemplo que utiliza a maioria dos métodos:
>>> a = [66.6, 333, 333, 1, 1234.5]
>>> print [Link](333), [Link](66.6), [Link](’x’)
2 1 0
>>> [Link](2, -1)
>>> [Link](333)
>>> a
[66.6, 333, -1, 333, 1, 1234.5, 333]
>>> [Link](333)
1
>>> [Link](333)
>>> a
[66.6, -1, 333, 1, 1234.5, 333]
>>> [Link]()
42
Estruturas de Dados
>>> a
[333, 1234.5, 1, 333, -1, 66.6]
>>> [Link]()
>>> a
[-1, 1, 66.6, 333, 333, 1234.5]
43
Python
Mais de uma sequência pode ser passada; a função a ser aplicada deve possuir tantos
parâmetros formais quantas sequências forem alimentadas para o ‘map’. Se None for
passado no lugar da função, então será aplicada uma função que apenas devolve os
argumentos recebidos. Dessa forma, ‘map(None, list1, list2)’ é uma forma conveniente
de concatenar listas em uma única. Por exemplo:
>>> seq = range(8)
>>> def square(x): return x*x
...
>>> map(None, seq, map(square, seq))
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]
44
Estruturas de Dados
45
Python
O comando del
Existe uma maneira de remover um item de uma lista a partir de seu índice, ao invés do
seu valor: o comando del. Ele também pode ser utilizado para remover fatias (slices) da
lista. Por exemplo:
>>> a
[-1, 1, 66.6, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.6, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.6, 1234.5]
Referenciar a variável e remove-la posteriormente constitui um erro (pelo menos até que
seja feita uma nova atribuição para a variável).
Tuplos e Sequências
Como podemos observar, listas e strings possuem muitas propriedades em comum como
indexação e operações de slicing. Listas e strings, são dois dos exemplos possíveis de
sequências.
Como o Python é uma linguagem em evolução, outros tipos de sequências podem ser
adicionados. Existe ainda um outro tipo de sequência já presente na linguagem: o tuplo
(tuple).
Um tuplo consiste em uma sequência imutável de valores separados por vírgulas.
>>> t = 12345, 54321, ’hello!’
>>> t[0]
12345
>>> t
(12345, 54321, ’hello!’)
>>> # Tuplos podem ser aninhadas:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, ’hello!’), (1, 2, 3, 4, 5))
46
Estruturas de Dados
Os tuplos são sempre envolvidas por parênteses. Na criação, os tuplos podem ser
envolvidos ou não por parênteses, desde que o contexto não exija os parênteses (como no
caso da tuplo pertencer a uma expressão maior).
Tuplos podem ter os mais diversos usos: pares ordenados, registros de empregados em
uma base de dados, etc.
Tuplos, assim como strings, são imutáveis. Não é possível atribuir valores a itens
individuais de um tupl (pode-se simular o mesmo efeito através de operações de corte e
concatenação). Também é possível criar tuplos contendo objectos mutáveis, como listas.
Um problema especial é a criação de tuplos contendo 0 ou 1 itens: a sintaxe tem certos
truques para acomodar estes casos. Tuplos vazios são construídos por um par de
parênteses vazios. E um tuplo unitário é construído por um único valor e uma vírgula
entre parênteses (sem a vírgula o tuplo não será gerado!):
>>> empty = ()
>>> singleton = ’hello’, # <-- observe a vírgula extra
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
(’hello’,)
Dicionários
Outra estrutura de dados interna de Python, e muito útil, é dicionário. Dicionários são
também chamados de “memória associativa”, ou “vector associativo” . Diferentemente de
sequências que são indexadas por inteiros, os dicionários são indexados por chaves
(keys), que podem ser de qualquer tipo imutável (como strings e inteiros). Tuplos também
podem ser chaves se contiverem apenas strings, inteiros ou outros tuplos. Se o tuplo
contiver, directa ou indirectamente, qualquer valor mutável não poderá ser chave. Listas
não podem ser usadas como chaves porque são mutáveis.
O melhor modelo mental de um dicionário á um conjunto não ordenado de pares chave-
valor, onde as chaves são únicas em uma dada instância do dicionário.
47
Python
Dicionários são delimitados por : {}. Uma lista de pares chave:valor separada por
vírgulas dentro desse delimitadores define a constituição inicial do dicionário. Dessa
forma também será impresso o conteúdo de um dicionário numa secção de depuração.
As principais operações num dicionário são armazenar e recuperar valores a partir de
chaves. Também ´e possível remover um par chave:valor com o comando del. Se você
armazenar um valor utilizando uma chave já presente, o antigo valor será substituído pelo
novo. Se tentar recuperar um valor dada uma chave inexistente será gerado um erro.
O método keys() do dicionário retorna a lista de todas as chaves presentes no
dicionário, em ordem aleatória (se desejar ordená-las basta aplicar o método sort() na
lista devolvida). Para verificar a existência de uma chave, utilize o método has key()
do dicionário.
A seguir, um exemplo de uso do dicionário:
>>> tel = {’jack’: 4098, ’sape’: 4139}
>>> tel[’guido’] = 4127
>>> tel
{’sape’: 4139, ’guido’: 4127, ’jack’: 4098}
>>> tel[’jack’]
4098
>>> del tel[’sape’]
>>> tel[’irv’] = 4127
>>> tel
{’guido’: 4127, ’irv’: 4127, ’jack’: 4098}
>>> [Link]()
[’guido’, ’irv’, ’jack’]
>>> tel.has_key(’guido’)
1
Condições
As condições de controle utilizadas no while e if acima podem conter outros
operadores além de comparações.
Os operadores de comparação in e not in verificam se um valor ocorre (ou não
ocorre) em uma dada sequência.
Os operadores is e is not comparam se dois objectos são na verdade o mesmo
objecto; o que só é significativo no contexto de objectos mutáveis, como listas. Todos
operadores de comparação possuem a mesma precedência, que é menor do que a
prioridade dos operadores numéricos.
Comparações podem ser encadeadas: a < b == c testa se a é menor que b e ainda
por cima se b é igual a c.
Comparações podem ser combinadas através de operadores boleanos and e or, e
negados através de not. Estes possuem menor prioridade que os demais operadores de
48
Estruturas de Dados
Observe que no Python, ao contrário do C, a atribuição não pode ocorrer dentro de uma
expressão. Programadores de C podem resmungar, mas isso evita toda uma classe de
problemas frequentemente encontrados nos programas C: digitar = numa expressão
quando a intenção era ==.
49
Python
Tipos numéricos mistos são comparados de acordo com seus valores numéricos, logo 0 é
igual a 0.0, etc.
50
Módulos
Módulos
51
Python
Módulos
Se se sair do interpretador do Python e entrar novamente, todas as definições de funções e
variáveis serão perdidas.
Logo, se se desejar escrever um programa que dure é melhor preparar o código num
editor de texto. Quando estiver pronto, corra-se o interpretador sobre o arquivo fonte
gerado. A isto chama-se gerar um script.
Á medida que os programas crescem, pode ser desejável dividi-los em vários arquivos
para facilitar a manutenção. Talvez até se queira reutilizar uma função sem copiar a sua
definição a cada novo programa.
Para permitir isto, Python possui uma maneira de depositar definições num arquivo e
posteriormente reutilizá-las num script ou secção interactiva do interpretador. Esse
arquivo é denominado módulo. As definições de um módulo podem ser importadas por
outros módulos ou no módulo principal.
Um módulo é um arquivo contendo definições e comandos Python. O nome do arquivo
recebe o sufixo ‘.py’.
Dentro de um módulo, seu nome (uma string) está disponível na variável global
__name__ . Por exemplo, crie o arquivo ‘[Link]’ no directório corrente com o seguinte
conteúdo:
# Módulo Sequências de Fibonacci
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while b < n:
print b,
a, b = b, a+b
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while b < n:
[Link](b)
a, b = b, a+b
return result
52
Módulos
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
’fibo’
Isso não introduz o nome do módulo importado na tabela de símbolos local, mas sim o
nome da função directamente.
Existe ainda uma variante que permite importar directamente todos os nomes definidos
em um dado módulo.
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Isso importa todos os nomes excepto aqueles iniciados por um sublinhado (_).
53
Python
54
Módulos
Módulos Padrão
O Python possui um biblioteca padrão de módulos, descrita em um documento em
separado, a Python Library Reference. Alguns módulos estão embutidos no interpretador;
estes possibilitam acesso a operações que não são parte do núcleo da linguagem, seja por
eficiência ou para permitir o acesso a chamadas de sistema. O conjunto presente destes
módulos é configurável, por exemplo, o módulo amoeba só está disponível em sistemas
que suportam as primitivas do Amoeba. Existe um módulo que requer especial atenção:
sys, que é embutido em qualquer interpretador Python. As variáveis sys.ps1 e
sys.ps2 definem as strings utilizadas como prompt primário e secundário:
>>> import sys
>>> sys.ps1
’>>> ’
>>> sys.ps2
’... ’
>>> sys.ps1 = ’C> ’
C> print ’Yuck!’
Yuck!
C>
A Função dir()
A função interna dir() é utilizada para se descobrir que nomes são definidos por um
módulo. Ela retorna uma lista ordenada de strings:
>>> import fibo, sys
>>> dir(fibo)
[’__name__’, ’fib’, ’fib2’]
>>> dir(sys)
[’__name__’, ’argv’, ’builtin_module_names’, ’copyright’, ’exit’,
55
Python
Observe-se que são listados os nomes dos mais diversos tipos: variáveis, módulos,
funções, etc.
dir() não lista nomes de funções ou variáveis internas. Esse nomes estão definidos no
módulo padrão __builtin__ :
>>> import __builtin__
>>> dir(__builtin__)
[’AccessError’, ’AttributeError’, ’ConflictError’, ’EOFError’, ’IOError’,
’ImportError’, ’IndexError’, ’KeyError’, ’KeyboardInterrupt’,
’MemoryError’, ’NameError’, ’None’, ’OverflowError’, ’RuntimeError’,
’SyntaxError’, ’SystemError’, ’SystemExit’, ’TypeError’, ’ValueError’,
’ZeroDivisionError’, ’__name__’, ’abs’, ’apply’, ’chr’, ’cmp’, ’coerce’,
’compile’, ’dir’, ’divmod’, ’eval’, ’execfile’, ’filter’, ’float’,
’getattr’, ’hasattr’, ’hash’, ’hex’, ’id’, ’input’, ’int’, ’len’, ’long’,
’map’, ’max’, ’min’, ’oct’, ’open’, ’ord’, ’pow’, ’range’, ’raw_input’,
’reduce’, ’reload’, ’repr’, ’round’, ’setattr’, ’str’, ’type’, ’xrange’]
Pacotes
Pacotes são uma maneira de estruturar espaços de nomes para módulos utilizando a
sintaxe de “separação por ponto”. Como exemplo, o módulo A.B designa um sub-
módulo chamado ‘B’ num pacote denominado ‘A’. O uso de pacotes permite aos autores
de grupos de módulos (como NumPy ou PIL) não terem que se preocupar com a colisão
entre os nomes de seus módulos e os nomes de módulos de outros autores.
Suponhamos que se desejava projectar uma colecção de módulos (um “pacote”) para o
gerar uniformemente arquivos de som. Existem muitos formatos diferentes (normalmente
identificados pela extensão do nome de arquivo, ex. ‘.wav’, ‘.aiff’, ‘.au’), de forma que
você pode precisar criar e manter uma crescente colecção de módulos de conversão entre
formatos. Ainda podem existir muitas operações diferentes passíveis de aplicação sobre
os arquivos de som (ex. mix, eco, equalização, efeito stereo artificial). Logo,
possivelmente estaríamos a escrever uma interminável colecção de módulos para aplicar
estas operações. Aqui está uma possível estrutura para o pacote (expressa em termos de
um sistema hierárquico de arquivos):
Sound/ Top-level package
56
Módulos
Os arquivos ‘__init__.py’ são necessários para que o Python trate os directórios como um
conjunto de módulos. Isso foi feito para evitar directórios com nomes comuns, como
‘string’, de inadvertidamente esconder módulos válidos que ocorram a posteriori no
caminho de busca. No caso mais simples, ‘__init__.py’ pode ser um arquivo vazio. Porém,
ele pode conter código de inicialização para o pacote ou gerar a variável __all__, que
será descrita depois.
Usuários do pacote podem importar módulos individuais, por exemplo:
import [Link]
Assim carrega-se o módulo sem necessidade de prefixação na hora do uso. Logo, pode
ser utilizado como se segue:
[Link](input, output, delay=0.7, atten=4)
Também é possível importar directamente uma única variável ou função, como em:
from [Link] import echofilter
57
Python
Note-se que ao utilizar from package import item, o item pode ser um sub-pacote,
sub-módulo, classe, função ou variável. O comando import primeiro testa se o item
está definido no pacote, senão assume que é um módulo e tenta carregá-lo. Se falhar em
encontrar o módulo uma excepção ImportError é levantada.
Em oposição, na construção import [Link], cada item, com
excepção do último, deve ser um pacote. O último pode ser também um pacote ou
módulo, mas nunca uma entidade contida num módulo.
Importando * de um pacote
O que acontece quando um usuário escreve from [Link] import *?
Idealmente, poder-se-ia esperar que todos os sub-módulos presentes no pacote fossem
importados. Infelizmente, essa operação não funciona muito bem nas plataformas Mac ou
Windows, onde não existe distinção entre maiúsculas ou minúsculas nos sistema de
arquivos. Nestas plataformas não há como saber como importar o arquivo ‘[Link]’,
deveria ser com o nome echo, Echo ou ECHO (por exemplo, o Windows 95 tem o
irritante hábito de colocar a primeira letra em maiúsculas). A restrição de nomes de
arquivo em DOS com o formato 8+3 adiciona um outro problema na hora de se utilizar
arquivos com nomes longos.
A única solução é o autor do pacote fornecer um índice explícito do pacote. O comando
de importação utiliza a seguinte convenção: se o arquivo ‘__init__.py’ do pacote define-se
a lista chamada __all__ , então esta lista indica os nomes dos módulos a serem
importados quando o comando from package import * é encontrado.
Fica a cargo do autor do pacote manter esta lista actualizada, inclusive fica ao seu critério
excluir inteiramente o suporte a importação directa de todo o pacote através do from
package import *. Por exemplo, o arquivo ‘Sounds/Effects/__init__.py’ poderia conter
apenas:
__all__ = ["echo", "surround", "reverse"]
Isso significaria que from [Link] import * iria importar apenas os três
sub-módulos especificados no pacote Sound.
Se __all__ não estiver definido, o comando from [Link] import *
não irá importar todos os sub-módulos do pacote [Link] no espaço de
nomes correntes. Há apenas garantia que o pacote [Link] foi importado
(possivelmente executou o seu código de inicialização ‘__init__.py’) juntamente com os
nomes definidos no pacote. Isso inclui todos os nomes definidos no ‘__init__.py’ bem
como em qualquer sub-módulo importado a partir deste. Por exemplo:
import [Link]
import [Link]
from [Link] import *
58
Módulos
59
Python
60
Entrada e Saída
Entrada e Saída
61
Python
Entrada e Saída
Existem diversas maneiras de se apresentar a saída (output) de um programa. Os dados
podem ser impressos em forma imediatamente legível, ou escritos num arquivo para uso
futuro. Este capítulo vai discutir algumas das possibilidades.
Formatação de Saída
Até agora nós encontramos duas maneiras de escrever valores: através de expressões e
pelo comando print (uma terceira maneira é utilizar o método write() dos
objectos de arquivo; a saída padrão pode ser referenciada como [Link]).
Frequentemente deseja-se um controle maior sobre a formatação de saída do que
simplesmente imprimindo valores separados por espaços. Existem duas formas. A
primeira manipular a string através de recortes (slicing) e concatenação. O módulo
padrão string contém algumas rotinas úteis a esta finalidade. A segunda maneira é
utilizar o operador %.
O operador % interpreta o argumento à esquerda como uma string de formatação de um
sprintf() aplicada ao argumento à direita do operador. O resultado é uma string
formatada.
Permanece a questão: como converter valores para strings? Por sorte, o Python possui
uma maneira de converter qualquer valor para uma string: basta submetê-lo à função
repr(), ou simplesmente escrevê-lo entre aspas reversas (‘‘). Alguns exemplos:
>>> x = 10 * 3.14
>>> y = 200*200
>>> s = ’The value of x is ’ + ‘x‘ + ’, and y is ’ + ‘y‘ + ’...’
>>> print s
The value of x is 31.4, and y is 40000...
>>> # Aspas reversas também funcionam em outros tipos alem de números:
... p = [x, y]
>>> ps = repr(p)
>>> ps
’[31.400000000000002, 40000]’
>>> # Converter uma string adiciona barras invertidas e aspas
... hello = ’hello, world\n’
>>> hellos = ‘hello‘
>>> print hellos
’hello, world\n’
>>> # O argumento de aspas reversas pode ser um tuplo
... ‘x, y, (’spam’, ’eggs’)‘
"(31.400000000000002, 40000, (’spam’, ’eggs’))"
62
Entrada e Saída
63
Python
Existe ainda a função [Link]() que preenche uma string numérica com zeros
à esquerda. Ela entende sinais positivos e negativos.
>>> import string
>>> [Link](’12’, 5)
’00012’
>>> [Link](’-3.14’, 7)
’-003.14’
>>> [Link](’3.14159265359’, 5)
’3.14159265359’
Se houver mais do que um formato, então o argumento à direita deve ser um tuplo com os
valores de formatação.
Exemplo:
>>> table = {’Sjoerd’: 4127, ’Jack’: 4098, ’Dcab’: 7678}
>>> for name, phone in [Link]():
... print ’%-10s ==> %10d’ % (name, phone)
...
Jack ==> 4098
Dcab ==> 7678
Sjoerd ==> 4127
A maioria dos formatos funciona da mesma maneira que em C, e exigem que se passe o
tipo apropriado. Entretanto, em caso de erro ocorre uma excepção e não uma falha do
sistema operativo.
O formato %s é mais relaxado: se o argumento correspondente não for um objecto
string, então ele é convertido para string pela função interna str(). Existe um suporte
para o modificador * determinar o comprimento ou precisão num argumento inteiro em
separado. Os formatadores (em C) %n e %p também são suportados.
Se se possuir uma string de formatação muito longa, seria bom referenciar as variáveis de
formatação por nome, ao invés de por posição. Isso pode ser obtido passando um
dicionário como argumento à direita e prefixando campos na string de formatação com
%(name)format.
>>> table = {’Sjoerd’: 4127, ’Jack’: 4098, ’Dcab’: 8637678}
>>> print ’Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d’ % table
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
Isso é particularmente útil em combinação com a nova função interna vars(), que
retorna um dicionário contendo todas as variáveis locais.
64
Entrada e Saída
65
Python
>>> [Link]()
’Segunda linha do arquivo\n’
>>> [Link]()
’’
O módulo pickle
66
Entrada e Saída
Existem outras variações desse processo úteis quando se precisa aplicar sobre muitos
objectos ou o destino da representação string não é um arquivo. Utilizar o módulo
pickle é a forma padrão de tornar objectos Python persistentes, permitindo a
reutilização dos mesmos entre diferentes programas, ou pelo mesmo programa em
diferentes sessões de utilização. A representação da string dos dados é tecnicamente
chamada objecto persistente, como já foi visto. Justamente porque o módulo pickle é
amplamente utilizado, vários autores que escrevem extensões para Python tomam o
cuidado de garantir que novos tipos de dados sejam compatíveis com esse processo.
67
Python
68
Erros e Excepções
Erros e Excepções
69
Python
Erros e Excepções
Até agora mensagens de erro foram apenas mencionadas. Existem pelo menos dois tipos
distintos de erros: erros de sintaxe e excepções.
Erros de sintaxe
Erros de sintaxe, também conhecidos como erros de parse, são provavelmente os mais
frequentes entre aqueles que ainda estão aprendendo Python:
>>> while 1 print ’Hello world’
File "<stdin>", line 1
while 1 print ’Hello world’
ˆ
SyntaxError: invalid syntax
O parser repete a linha inválida e apresenta uma pequena ‘sete (^)’ apontando para o
ponto da linha em que o erro foi encontrado. O erro é detectado pelo token que precede a
seta. No exemplo, o erro foi detectado na palavra reservada print, uma vez que faltam
os dois pontos (‘:’). O nome do arquivo e número da linha são impressos para que se
possa verificar melhor onde ocorreu o erro no texto do script.
Excepções
Mesmo que um comando ou expressão estejam sintacticamente correctos, talvez ocorra
um erro na hora de sua execução. Erros detectados durante a execução são chamados
excepções e não são necessariamente fatais. A maioria das excepções não são tratadas e
acabam resultando em mensagens de erro:
>>> 10 * (1/0)
Traceback (most recent call last):
File "<stdin>", line 1
ZeroDivisionError: integer division or modulo
>>> 4 + spam*3
Traceback (most recent call last):
File "<stdin>", line 1
NameError: spam
>>> ’2’ + 2
Traceback (most recent call last):
File "<stdin>", line 1
TypeError: illegal argument type for built-in operation
A última linha da mensagem de erro indica o que aconteceu. Excepções surgem com
diferentes tipos, e o tipo é impresso como parte da mensagem . Os tipos no exemplo são:
ZeroDivisionError, NameError e TypeError. A string impressa como sendo
70
Erros e Excepções
o tipo da excepção é o nome interno da excepção que ocorreu. Isso é verdade para todas
excepções pré-definidas em Python, mas não é necessariamente verdade para excepções
definidas pelo usuário.
O resto da linha é detalhe que depende do tipo da excepção ocorrida.
A parte anterior da mensagem de erro apresenta o contexto onde ocorreu a excepção.
Essa informação é denominada stack backtrace. Em geral, contém uma lista de linhas do
código fonte, sem apresentar, no entanto, valores lidos da entrada padrão.
O documento Python Library Reference lista as excepções pré-definidas e os seus
significados.
71
Python
que tenham ocorrido no interior de outro tratador num mesmo try. Um tratador pode ser
sensível a múltiplas excepções, desde que as especifique num tuplo:
... except (RuntimeError, TypeError, NameError):
... pass
A última cláusula except pode omitir o nome da excepção, servindo como uma
máscara genérica. Esse recurso de ser utilizado com extrema cautela, uma vez que isso
pode esconder erros do programador e do usuário. Também pode ser utilizado para
imprimir uma mensagem de erro, ou re-elevar (re-raise) a excepção de forma que um
“chamador” também possa tratá-la.
import string, sys
try:
f = open(’[Link]’)
s = [Link]()
i = int([Link](s))
except IOError, (errno, strerror):
print "I/O error(%s): %s" % (errno, strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
A construção try . . . except possui uma cláusula else opcional, que quando presente, deve
ser colocada depois de todas as outras cláusulas. É útil para um código que precisa ser
executado se nenhuma excepção foi levantada. Por exemplo:
for arg in [Link][1:]:
try:
f = open(arg, ’r’)
except IOError:
print ’cannot open’, arg
else:
print arg, ’has’, len([Link]()), ’lines’
[Link]()
72
Erros e Excepções
... spam()
... except NameError, x:
... print ’name’, x, ’undefined’
...
name spam undefined
Se uma excepção possui argumento, ele é impresso ao final do detalhe de expressões não
tratadas (unhandled exceptions).
Além disso, tratadores de excepções são capazes de capturar excepções que tenham sido
levantadas no interior de funções invocadas na cláusula try. Por exemplo:
>>> def this_fails():
... x = 1/0
...
>>> try:
... this_fails()
... except ZeroDivisionError, detail:
... print ’Handling run-time error:’, detail
...
Handling run-time error: integer division or modulo
Levantando Excepções
A palavra reservada raise permite ao programador forçar a ocorrência de um
determinado tipo de excepção. Por exemplo:
>>> raise NameError, ’HiThere’
Traceback (most recent call last):
File "<stdin>", line 1
NameError: HiThere
73
Python
Muitos módulos padrão utilizam-se disto para reportar erros que ocorrem no interior das
funções que definem.
Acções de limpeza
A construção try possui outra cláusula opcional, cuja finalidade é permitir a
implementação de acções de limpeza, que devem ser sempre executadas
independentemente da ocorrência de excepções. Como no exemplo:
>>> try:
... raise KeyboardInterrupt
... finally:
... print ’Goodbye, world!’
...
Goodbye, world!
Traceback (most recent call last):
File "<stdin>", line 2
KeyboardInterrupt
A cláusula finally é sempre executada, que ocorra quer não uma excepção. Quando
ocorre a excepção, é como se a excepção fosse sempre levantada após a execução do
código na cláusula finally. Mesmo que haja um break ou return dentro do try,
ainda assim o finally será executado.
A construção try pode ser seguida da cláusula finally ou de um conjunto de
cláusulas except, mas nunca ambas. Essas opções são mutuamente exclusivas.
74
Classes
Classes
75
Python
Classes
O mecanismo de classes no Python foi adicionado à linguagem de forma a minimizar a
sobrecarga sintáctica e semântica. É uma mistura de mecanismos equivalentes
encontrados em C++ e Modula-3. Assim como é válido para módulos, classes em Python
não impõem barreiras entre o usuário e a definição. Contudo, dependem da
“cordialidade” do usuário para não quebrar a definição. Todavia, as características mais
importantes de classes foram asseguradas: o mecanismo de herança permite uma base de
classes múltiplas, uma classe derivada pode sobrescrever quaisquer métodos de uma
classe ancestral, um método pode invocar outro método homónimo de uma classe
ancestral. E mais, objectos podem armazenar uma quantidade arbitrária de dados
privados.
Na terminologia de C++, todos os membros de uma classe (incluindo dados) são public, e
todos as funções membro são virtual. Não existem construtores ou destrutores especiais.
Como em Modula-3, não existem atalhos para referenciar membros do objecto de dentro
dos seus métodos. Um método (função de uma classe) é declarado com um primeiro
argumento explícito representando o objecto (instância da classe), que é fornecido
implicitamente pela invocação.
Como em Smalltalk (e em Java), classes são objectos. Mas no Python, todos os tipos de
dados são objectos, o que fornece uma semântica para importação e renomeamento
(rename). Ainda como em C++ ou Modula-3, tipos pré definidos não podem ser
utilizados como classes base para extensões de usuário por herança. Como em C++, mas
diferentemente de Modula-3, a maioria dos operadores (aritméticos, indexação, etc)
podem ser redefinidos para instâncias da classe.
76
Classes
77
Python
78
Classes
Quando se fornece uma definição de uma classe, um novo espaço de nomes é criado.
Todas as atribuições de variáveis são vinculadas a este escopo local. Em particular,
definições de funções também são armazenadas neste escopo.
Quando termina o processamento de uma definição de uma classe (normalmente, sem
erros), um objecto da classe é criado. Este objecto encapsula o conteúdo do espaço de
nomes criado pela definição da classe. O escopo local activo antes da definição da classe
é restaurado, e o objecto classe é vinculado a este escopo com o nome dado a classe.
Objectos de Classes
Objectos de Classes suportam dois tipos de operações: referências a atributos e
instanciação.
Referências a atributos da classe utilizam a sintaxe padrão utilizada para quaisquer
referências a atributos no Python: [Link]. Os atributos válidos são todos os nomes
presentes no espaço de nomes da classe quando o objecto classe foi criado. Portanto, se a
definição da classe era:
class MyClass:
"Um exemplo simples de classe"
i = 12345
def f(x):
return ’hello world’
cria uma nova instância da classe e atribui o objecto resultante a variável local x.
A operação de instanciação (“calling” um objecto de classe) cria um objecto vazio.
Muitas classes preferem criar um novo objecto num estado inicial pré determinado. Para
tanto, existe um método especial que pode ser definido pela classe, __init__(), veja:
def __init__(self):
[Link] = []
79
Python
Instâncias
Agora, o que podemos fazer com as instâncias ? As únicas operações reconhecidas pelas
instâncias são referências a atributos. Existem dois tipos de nomes de atributos válidos.
O primeiro chama-se de atributos-de-dados, que correspondem a “variáveis da instância”
em Smalltalk, e a “membros” em C++. Atributos de dados não precisam ser declarados.
Assim como variáveis locais, eles passam a existir na primeira vez em que é feita uma
atribuição. Por exemplo, se x é uma instância de MyClass criada acima, o próximo
bocado de código irá imprimir o valor 16, sem deixar rastro (por causa do del):
[Link] = 1
while [Link] < 10:
[Link] = [Link] * 2
print [Link]
del [Link]
O segundo tipo de referência aos atributos das instâncias são métodos. Um método é uma
função que “pertence a” uma instância (em Python, o termo método não é aplicado
exclusivamente às instâncias de classes: outros tipos de objectos também podem ter
métodos; por exemplo, objectos listas possuem os métodos: append, insert, remove, sort,
etc). Nomes de métodos válidos de uma instância dependem de sua classe. Por definição,
todos atributos de uma classe que são funções equivalem a um método presente nas
instâncias. No nosso exemplo, x.f é uma referência de método válido já que
MyClass.f é uma função, enquanto x.i não é, já que MyClass.i não é uma
função.
Entretanto, x.f não é o mesmo que MyClass.f — o primeiro é um método de um
objecto, o segundo é um objecto função.
80
Classes
Observações aleatórias
Atributos de dados sobrescrevem atributos métodos homónimos. Para evitar conflitos de
nome acidentais, que podem gerar bugs de difícil rastreio em programas extensos, é sábio
utilizar algum tipo de convenção que minimize conflitos, como colocar nomes de
métodos com inicial maiúscula, prefixar atributos de dados com uma string única (quem
sabe “ ”), ou simplesmente utilizar substantivos para atributos e verbos para métodos.
Os atributos de dados podem ser referenciados por métodos da própria instância, bem
como por qualquer outro usuário do objecto. Em outras palavras, classes não servem para
implementar tipos puramente abstractos de dados.
De fato, nada no Python torna possível assegurar o encapsulamento de dados. Tudo é
convenção. Por outro lado, a implementação do Python, escrita em C, pode esconder
completamente detalhes de um objecto ou regular seu acesso se necessário. Isto pode ser
utilizado por extensões ao Python escritas em C.
Os clientes devem utilizar atributos de dados com cuidado, pois podem baralhar
invariantes mantidos pelos métodos ao esbarrar nos seus atributos. Portanto, os clientes
podem adicionar à vontade atributos de dados para uma instância sem afectar a validade
dos métodos, desde que seja evitado o conflito de nomes. Novamente, uma convenção de
nomenclatura poupa muita dor de cabeça.
81
Python
Não existe um atalho para referenciar atributos de dados (ou métodos) de dentro de um
método. Isso na verdade aumenta a legibilidade dos métodos: não há como confundir
uma variável local com uma instância global ao dar uma olhadela num método
desconhecido.
Por convenção, o primeiro argumento de qualquer método é frequentemente chamado
self. Isso não é nada mais do que uma convenção, self não possui nenhum
significado especial em Python. Observe que ao seguir a convenção, o código torna-se
legível por uma grande comunidade de desenvolvedores de Python e potencialmente
poder-se-á vir a beneficiar de ferramentas feitas por outra pessoa que se baseie na
convenção.
Qualquer função que seja também atributo de classe define um método nas instâncias
desta classe. Não é necessário que a definição da função esteja textualmente embutida na
definição da classe. Atribuir um objecto função a uma variável local da classe é válido.
Por exemplo:
# Função definida fora da classe
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return ’hello world’
h = g
Os métodos podem referenciar nomes globais da mesma forma que funções ordinárias. O
escopo global associado a um método é o módulo contendo sua definição da classe (a
classe propriamente dita nunca é usada como escopo global!). Ainda que seja raro
encontrar a necessidade de utilizar dados globais num método, há diversos usos legítimos
do escopo global. Por exemplo, funções e módulos importados no escopo global podem
ser usados por métodos, bem como as funções e classes definidas no próprio escopo
global. Provavelmente, a classe contendo o método em questão também foi definida neste
escopo global.
82
Classes
Herança
Obviamente, uma característica da linguagem não seria digna do nome “classe” se não
suportasse herança. A sintaxe para uma classe derivada se parece com:
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
A execução de uma definição de uma classe derivada procede da mesma forma que a de
uma classe base. Quando o objecto classe é construído, a classe base é lembrada. Isso é
utilizado para resolver referências a atributos. Se um atributo requisitado não for
encontrado na classe, ele é procurado na classe base. Essa regra é aplicada
recursivamente se a classe base por sua vez for derivada de outra.
Não existe nada de especial sobre instanciação de classes derivadas.
DerivedClassName() cria uma nova instância da classe. As referências a métodos
são resolvidas da seguinte forma: o atributo correspondente é procurado através da cadeia
de derivação, e referências a métodos são válidas desde que produzam um objecto do tipo
função.
Classes derivadas podem sobrescrever métodos das suas classes base. Uma vez que
métodos não possuem privilégios especiais quando invocam outros métodos no mesmo
objecto, um método na classe base que invocava um outro método da mesma classe base,
pode efectivamente acabar invocando um método sobreposto por uma classe derivada.
Para programadores C++ isso significa que todos os métodos em Python são
efectivamente virtual.
Um método que subscreva outro numa classe derivada pode desejar na verdade estender,
ao invés de substituir, o método sobrescrito de mesmo nome na classe base. A maneira
mais simples de implementar esse comportamento é chamar directamente a classe base
‘[Link](self, arguments)’. O que pode ser útil para
os usuários da classe também. Note-se que isso só funciona se a classe base for definida
ou importada directamente no escopo global.
Herança múltipla
O Python também suporta uma forma limitada de herança múltipla. Uma definição de
classe que herda de várias classes bases é:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
83
Python
.
.
.
<statement-N>
A única regra que precisa ser explicada é a semântica de resolução para as referências a
atributos de classes. É feita uma busca em profundidade da esquerda para a direita. Logo,
se um atributo não é encontrado em DerivedClassName, ele é procurado em Base1,
e recursivamente nas classes bases de Base1, e apenas se não for encontrado lá a busca
prosseguirá em Base2, e assim sucessivamente.
Para algumas pessoas a busca em largura – procurar antes em Base2 e Base3 do que
nos ancestrais de Base1 — parece mais natural. Entretanto, seria preciso conhecer toda
a hierarquia de Base1 para evitar um conflito com um atributo de Base2. Enquanto a
busca em profundidade não diferencia o acesso a atributos directos ou herdados de
Base1.
É sabido que o uso indiscriminado de herança múltipla é o pesadelo da manutenção,
sobretudo pela confiança do Python na adopção de uma convenção de nomenclatura para
evitar conflitos. Um problema bem conhecido com herança múltipla é quando há uma
classe derivada de outras que por sua vez possuem um ancestral em comum.
Ainda que seja perfeitamente claro o que acontecerá (a instância irá possuir uma única
cópia dos atributos de dados do ancestral comum), não está claro se a semântica é útil.
Variáveis Privadas
Existe um suporte limitado a identificadores privados em classes. Qualquer identificador
no formato __spam (no mínimo dois caracteres ‘ ’ no prefixo e no máximo um como
sufixo) é realmente substituído por classname_spam, onde classname é o nome
da classe corrente. Essa construção independe da posição sintáctica do identificador, e
pode ser usada para tornar privadas: instâncias, variáveis de classe e métodos. Pode haver
truncamento se o nome combinado extrapolar 255 caracteres. Fora de classes, ou quando
o nome da classe só tem ‘ ’, não se aplica esta construção.
Este procedimento visa oferecer a classes uma maneira fácil de definir variáveis de
instância e métodos “privados”, sem ter que se preocupar com outras variáveis de
instância definidas em classes derivadas ou definidas fora da classe. Apesar da regra de
nomenclatura ter sido projectada para evitar “acidentes”, ainda é possível o acesso e a
manipulação de entidades privadas. O que é útil no caso dos “debugers”, talvez a única
razão pela qual essa característica ainda não tenha sido suprimida (detalhe: derivar uma
classe com o mesmo nome da classe base torna possível o uso de seus membros privados!
Isso pode ser corrigido em versões futuras).
O código passado para exec, eval() ou evalfile() não considera o nome da
classe que o invocou como sendo a classe corrente. O modificador global funciona de
maneira semelhante, quando se está restrito ao código que foi byte-compilado em
conjunto. A mesma restrição aplica-se aos comandos getattr(), setattr() e
delattr(), e a manipulação directa do dicionário dict .
84
Classes
Aqui está um exemplo de uma classe que implementa os seus próprios métodos
getattr () e setattr (), armazenando todos os atributos em variáveis privadas.
Da forma como foi codificado este exemplo, ele irá funcionar até em versões de Python
em que esta característica ainda não havia sido implementada.
class VirtualAttributes:
__vdict = None
__vdict_name = locals().keys()[0]
def __init__(self):
self.__dict__[self.__vdict_name] = {}
def __getattr__(self, name):
return self.__vdict[name]
def __setattr__(self, name, value):
self.__vdict[name] = value
Particularidades
Às vezes, é útil ter um tipo semelhante ao “record” de Pascal ou ao “struct” de C. Uma
definição de classe vazia atende esse propósito:
class Employee:
pass
john = Employee() # Cria um registro vazio de Empregado
# Preenche os campos do registro
[Link] = ’John Doe’
[Link] = ’computer lab’
[Link] = 1000
Um código em Python que espera um tipo abstracto de dados em particular, pode receber
ao invés do tipo abstracto uma classe (que emula os métodos que aquele tipo suporta).
Por exemplo, se se tem uma função que formata dados num objecto arquivo, pode-se
definir uma classe com os métodos read() e readline() que utiliza um buffer ao
invés do arquivo propriamente dito.
Os métodos de instância são objectos, e podem possuir atributos também.
Na primeira forma, instance deve ser uma instância de Class ou de uma classe
derivada dela. A segunda forma é um atalho para:
raise instance.__class__, instance
85
Python
Uma cláusula de excepção pode listar tanto classes como strings. Uma classe numa
cláusula de excepção é compatível com a excepção se é a mesma classe prevista na
cláusula ou ancestral dela (não o contrário, se na cláusula estiver uma classe derivada não
irá haver casamento com excepções base levantadas). No exemplo a seguir será impresso
B, C, D nessa ordem:
class B:
pass
class C(B):
pass
class D(C):
pass
for c in [B, C, D]:
try:
raise c()
except D:
print "D"
except C:
print "C"
except B:
print "B"
86
Conclusão
Conclusão
87
Python
Conclusão
Python tem um papel de integração importante no desenvolvimento de grandes
aplicações com uma probabilidade de vida longa. Permite uma resposta rápida nas
mudanças das necessidades do utilizador, que requer uma adaptação da lógica da
aplicação, sem mudar os componentes subjacentes fundamentais. Também, permite uma
adaptação rápida da aplicação, a mudanças nos componentes subjacentes.
JPython (o futuro)
Uma nova implementação do Python, escrito em 100% Java, denominado de JPython está
correntemente a ser desenvolvido. JPython é uma implementação total da linguagem
Python, que permite acesso directo às classes do Java. O código em Java também pode
utilizar as classes do Python (isto é importante para “Callbacks”, por exemplo).
O argumento principal do JPython é: faz para o Java aquilo que o Python já fazia para o
C/C++. A integração do JPython com o Java é superior à integração entre o Python e
C++: devido ao efeito “Reflection API” do Java, JPython pode usar arbitrariamente
classes do Java sem a ajuda de um gerador “wrapper” como o SWIG.
88