Python@FURG |
Texto apresentado em palestra do Grupo de Interesse em Linguagens de Programação da Fundação Universidade Federal do Rio Grande (GRULING), 1998.
O presente texto procura resumir os temas abordados em [1] incorporando exemplos mais práticos e fazendo refrências as demais referências bibliográficas.
Palavras-chave: linguagens de programação,
linguagens de Script, Python.
A sintaxe simples do Python eoncoraja 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, se encontram gratuitamente disponível na Internet podendo ser vasculhados por qualquer interessado sen ônus algum. Apesar disto, a linguagem Python é marca registrada do Stichting Mathematisch Centrum de Amsterdam. Todos os direitos reservados.
A linguagem Python foi desenvolvida pelo holandês Guido Van Rossun, no final de 1990. Segundo Van Rossum, a linguagem surgiu enquanto este passava o tempo entre o Natal de 1990 e o ano novo de 1991, mexendo na linguagem ABC, a qual ele havia participado do grupo que a desenvolvera. Já no começo de 1991, Van Rossum já havia feito uma especificação bastante próxima a esta feita neste texto.
Hoje a linguagem Python vem sendo utilizada por milhares de pessoas ao redor do mundo, sendo sustentada por uma fundação, a CNRI, e por um sem número de voluntários ao redor do mundo, unidos via Internet, formandoa Python Software Activity (PSA). Neste momento está sendo proposta a criação de um movimento chamado Python Consortium que tem por objetivo passar o fomento da linguagem para um pool de empresas e instituições de ensino e pesquisa. Esta proposta está sendo apresentada na Sétima conferência Internacional da Linguagem Python que aconteceu agora em novembro, em Houston, Texas.
De volta ao artigo, vamos à seguir iniciar o trabalho de análise
léxica da linguagem. Você observará que o texto não
será baseado em metodologias formais de especificação
de linguagens, como a BNF, dand portanto, margens para ambiguidades. Mas
como o texto é de caráter ilustrativo o autor escolheu a
linguagem natural como o melhor formato para apresentá-lo.
O interpretador Python interpreta senteças recebidas de algum
dispositivo de entrada (console ou arquivo), Esta entrada é lida
pelo analizador léxico que divide o código recebido em tokens,
repassando-o para o parser que interpreta o programa.
O Python é totalmente definido utilizando a tabela ASCII de 7
bits.
Um programa em Python é dividido em linhas lógicas.
Estas linhas lógicas são separadas pelo token NEWLINE e pode
ser construída por uma ou mais linhas físicas. Estas linhas
físicas são trechos de programas divididos pelo caractere
ENTER.
Uma linha lógica não pode ultrapassar uma linha física com exceção de dois casos especiais. O primeiro caso é o ajuntamento explícito de linhas quando um caractere de barra invertida é posto no final da linha.
soma = a + b + c + d + e + f + g \
h + i + j + k + l + m
O segundo é o ajuntamento implícito de linhas que ocorre dentro de expressões delimitadas por colchetes, parênteses ou chaves, como no exemplo abaixo.
dias_da_semana = ['dom','seg','ter',
'qua','qui','sex','sab']
Os comentários são identificados pelo símbolo hash (#). todo o conteúdo de uma linha que estiver a direita deste símbolo é desconsiderado. O comentário só vale na linha que contém o hash. As linhas totalmente em branco são disconsideradas pelo interpretador.
Antes que a primeira linha do arquivo seja lida, um zero é posto numa pilha, este zero não mais sairá da pilha. Os números postos na pilha irão sempre crescer do fundo até o topo da pilha, ou seja, cada novo valor na pilha é sempre maior que o valor anterior. No começo de cada linha lógica, o nível de identação é comparado como o número do topo da pilha. Se este número for igual, a pilha é permanece inalterada, Se o número for maior, a pilha recebe o valor do nível de identação da linha e um delimitador INDENT é adicionado. Se o nível de indentação for menor que o valor da pilha, a pilha é sucessivamente desempilhada até que se encontre na pilha o valor do nível da linha. e este valor não for encontrado o interpretador acusa um erro de sintaxe. Para cada valor que sai da pilha é adicionado um identificador DEDENT.
À seguir um programa onde são mostrados os delimitadores de linhas e blocos.
def
perm(1):
NEWLINE
# Compute the list for all permutations of 1
INDENT if
len(l)<=1:
NEWLINE
INDENT return[1]
NEWLINE
DEDENT r=[]
NEWLINE
for i in range(len(l)):
NEWLINE
INDENT s=l[:i]+
\
l[i+1:]
NEWLINE
p=perm(s)
NEWLINE
for x in p:
NEWLINE
INDENT
r.append (l[i:i+1]+x) NEWLINE
DEDENT
DEDENT return r
DEDENT
Vemos agora um exemplo com vário erros de identação:
def perm(l):
# primeira linha identada
for i in
range (len(l)): # não identada
s=l[:i]+l[i+1:]
p = perm (s)
# identação inesperada
for
x in p:
r.append(l[i:i+1]+x)
return r
# dedentação inconsistente
and assert break class
continue
def del
elif else except
exec finally for
from global
if import in
is lambda
not or
pass print raise
return try while
@ $ ?
Objetos são a abstração do Python para todas
as estruturas de dados. Todo programa em Python é composto por objetos
ou por relação entre objetos.
Todo objeto tem uma identidade, que lhe é atribuída na sua criação e não pode ser mudada. O tipo do objeto també é imutável. Este tipo define as operações que podem ser efetuadas neste objeto. Os objetos também possuem um valor que pode ser de tipo mutável (listas, tuplas, etc.) ou imutável (números e strings).
Os objetos de Python, uma vez criados, não podem ser destruídos. O que ocorre normalmente é que o interpretador possui um serviço de limpeza automática de memória que finaliza todo o objeto que não é mais alcançável. Por exemplo: suponha um objeto ``a'' que representa uma grande estrutura de dados. Se a este objeto for atribuído um objeto de tamanho pequeno, como por exemlo um inteiro, toda aquela estrutura de dados a ele associado anteriormente é finalizada e o espaço de memória é liberado. Esta função é extensível à tipos mais complexos como arquivos, apesar de que sua utilização não é aconselhada pelos prórpios criadores da linguagem devido ao baixo nível de abstração que oferece.
Veremos à seguir os tipos padão da linguagem Python. Devido a característica aberta da linguagem, estes tipos podem ser extendidos com extensões da linguagem em C.
...-1000,-1001,...,-3,-2,-1,0,1,2,3,...,1000,1001,...
0100 # octal
0x12 # hexadecimal
767468641767451361273676485352135L
fatorial (10000L) #acredite, eh BEM maior
do que todo este texto.
>> complex (1,2)
(1+2j)
>> 3 + 1j*3
(3+3j)
a = [i:j]
rertorna todos os elementos cujos índices estão compreendidos no intervalo i <= k < j.
'Isto eh uma string'
``Isto tambem eh uma string''
``That's cool!''
'''Isto eh uma string de tamanho ilimitado'''
'Isto eh uma string como um carctere <ENTER>\n'
r'Isto eh uma string com uma barra invertida
e um n \n'
(1, 2.3, [3,4,5], 'abacaxi')
[1,2,3]
['a', 0, 124111122L]
[[1,2],[3,4],[5,6]]
{'nome': 'Jose' , 'idade':54 , 23:[1,2,3,4,5] , 3.14:None}
a = ``Rolling ``
a = a + ``Stones''
Quando fazemos uma atribuição à uma string estamos redefinindo o seu valor, ou seja, na primeira linha o objeto ``a'' recebe a string `` Rolling ``, que por sua vez é uma constante (ou um objeto imutável na terminologia adotada pelo Python). Na segunda expressão, o objeto recebe o valor de ``a'', ou seja, a constante ``Rolling ``, concatenada a constante ``Stones'', que são, na verdade, um novo objeto. Desta forma o objeto string não é mutável!
Na sentença à seguir ocorre uma opreração completamente diferente.
a = [1,2]
a = a + [3,4]
Neste caso o objeto ``a'' recebe na primeira expressão, a lista [1,2] que não é uma constante e sim uma construção composta de dois objetos imutáveis, ou em termos de implementação, um conjunto de dois ponteiros. Na segunda expressão, o objeto ``a'' recebe ele mesmo, ou seja, a cosntrução que ele está referenciando, mais uma nova construção composta de dois objetos imutáveis.
Uma outra forma de definir objetos mutáveis e não mutáveis é definindo que nas operações feitas sobre os objetos mutáveis, estes objetos são passados por referência e nos não mutáveis são passados por valor.
def fatorial (n):
'retorna o fatorial de
n'
if n == 0:
return
1
return n*fat (n-1)
def pot (x, n=2)
'retorna a potencia com
base x e expoente n \
se n for ocultado eh assumido
n = 2'
return x**n
print fat (10)
print fat (5000L) #
inteiro longo
print pot (3,5)
print pot (8) #
equivale a 8**2
from Tkinter import *
class App:
def __init__ (self):
self.i = 0
self.root = Tk()
self.button = Button
(self.root, text = 'Hello', command = self.say_hi)
self.button.pack (side=LEFT)
self.root.mainloop()
def say_hi (self):
print 'Ola todos!'
self.i = self.i + 1
a = App()
O exemplo acima mostra a classe App. Esta classe cria uma janela com um botão com o texto 'Hello' que, quando pressionado, imprime a frase 'Ola todos!'. Esta classe é composta dos métodos __init__ e say_hi, e dos objetos root (a janela), button (o botão) e i (literal que conta o número de vezes que o botao foi pressionado). Os métodos definidos pelo usuário dentro do objeto são as implementações das operações válidas nos objetos desta classe. Estes objetos, por sua vez, representam o estado atual da classe.
Na última linha do observamos a atribuição de App à a. Neste ponto a tornou-se uma instância de App. Uma instância de uma Classe é obtida pela chamada desta classe como uma função. Quando isto ocorre, automaticamente é chamado o método __init__. Isto é um padrão da linguagem.
a.say_hi ()
print a.i #imprime o número de vezes que o botao foi pressionado
a.root.title ('Exemplo 1') # muda o título da janela
Isto não significa que os métodos de uma classe não sejam objetos executaveis, por exemplo, a expressão a.say_hi() é o mesmo do que App.say_hi(a).
O exemplo acima é representado pelo seguinte dicionário (os números são aleatórios e seria sibstituídos pelo endereço de memória dos objetos referidos pelos campos chave):
App = {'__init__':63233, 'say_hi':67542, 'root':63462, 'button':68382, 'i':68112}
class MyClass (OldClass):
def __init__ (self,
data1, data2):
self.data1 = data1
self.data2 = data2
OldClass.__init__ (self,
0, 0)
def Op1 (self):
pass
def Op2 (self):
pass
X = MyClass (x, y)
class arquivo:
def __init__ (self,
nomearq):
self.arq = open (nomearq,
'rw')
..........
def __del__ (self):
self.arq.close()
def riemann (expr, a, b):
x = a
somat = 0
norma = 0.0001
while x <= b:
somat = somat + eval
(expr)* norma
x = x + norma
return somat
É estritamente a mesma coisa do que:
class riemann:
def __call__ (self,
expr, a, b):
x = a
somat = 0
norma = 0.0001
while x <= b:
somat = somat + eval (expr)* norma
x = x + norma
return somat
x = 1
y = 2
nome = 'Mariazinha'
def troca (x, y):
'funcao que nao serve pra nada
aux = x
x = y
y = aux
# frame global
#{'x'=1,'y'=2, 'nome'='Mariazinha, 'troca'
= funcao}
# frame na funcao troca
#{'x'=??, 'y'=??, aux=??, 'nome'='Mariazinha'}
LyX é marca registrada de Matthias Ettrich, LaTeX é marca registrada de Leslie Lamport, Linux é marca registrada de Linus Torvalds e GhostView é marca registrada de Alladin Software. Todos estes programas são distribuídos livremente nos termos da GNU Public License.
A linguagem Python é marca registrada do Stichting Matematisch Centrum e também é distribuída livremente.
segue.......