Vamos escrever os nossos programas na linguagem de programação Python, também conhecidos como scripts. Um programa em Python pode ser processado e executado por um interpretador de Python, interativamente ou não.
Em processamento interativo, o programador interage com o interpretador introduzindo comandos ou frases da linguagem através do teclado e visualizando o resultado de cada comando no ecrã. Cada comando indica ao interpretador de Python uma tarefa para executar. Depois de cada comando, o programador terá de aguardar pelo resultado do mesmo antes de introduzir o próximo comando. A este ciclo de ler um comando, avaliar um comando e escrever o resultado dá-se o nome de read-eval-print loop.
Quando iniciamos uma sessão interativa do interpretador de Python, o símbolo >>>
indica que podemos introduzir o próximo comando. Por exemplo,
Python 3.4.3 (default, Mar 16 2015, 10:22:24) [GCC 4.8.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 2+2 4 >>> print("Olá mundo") Olá mundo >>>
Cada comando pode ser uma expressão, uma instrução ou uma definição. Em notação BNF,
<comando> ::= <expressão> | <instrução> | <definição>
No que se segue veremos alguns elementos básicos da programação.
Expressões
Uma expressão tem um valor associado uma vez avaliada. Em Python podemos ter como expressões constantes, nomes, aplicações de funções, e composições de expressões. Em notação BNF,
<expressão> ::= <constante> | <nome> | <aplicação de função> | <expressão composta>
Em Python temos como constantes números inteiros e reais, valores lógicos e cadeias de caracteres (strings), entre outras entidades que veremos mais tarde. Sempre que avaliamos uma constante no interpretador de Python é retornada a própria constante. Nota-se ainda que a representação das constantes, assim como de outras entidades, apresentada pelo interpretador é apenas uma visualização das mesmas, designada representação externa. Esta visualização é em geral diferente da representação interna, que é em geral uma representação em código binário.
Alguns exemplos:
>>> 3 3 >>> -1 -1 >>> 67.9872871389 67.9872871389 >>> 5e10 50000000000.0 >>> 199219034787493827498734987239748.949823498782374897324 1.9921903478749383e+32 >>> True True >>> False False >>> 'Olá mundo' 'Olá mundo' >>> "Olá mundo" 'Olá mundo' >>>
Temos também expressões compostas que resultam da combinação de expressões através de operações pré-definidas (not
, -
, +
, *
, etc.). Um expressão composta resulta portanto da aplicação de uma operação ou operador a um conjunto de argumentos, sendo a sintaxe a seguinte,
<expressão composta> ::= <operador> <expressão> | <operador> (<expressão>) | <expressão> <operador> <expressão> | (<expressão> <operador> <expressão>)
Exemplos:
>>> 4+5 9 >>> not(True) False >>> -4+7 3 >>> 4*8+5 37 >>> 4*(8+5) 52 >>>
Notar a precedência dos operadores. Como vamos ver mais tarde, esta é uma descrição sucinta das expressões em Python.
Tipos de dados elementares
Cada expressão, ou em geral cada entidade em programação, tem um tipo associado, i.e., um tipo de dados. As entidades de um dado tipo de dados -- o domínio do tipo -- partilham um conjunto de características que definem esse tipo, como por exemplo as operações a que essas entidades podem ser sujeitas.
Os tipos de dados variam de linguagem para linguagem de programação e, de forma geral, dividem-se em tipos elementares e tipos estruturados. Em Python existe um conjunto de tipos elementares (mais detalhes na documentação de Python):
- tipo inteiro,
int
; - tipo real,
float
; - tipo lógico,
bool
.
>>> 3 3 >>> type(3) <class 'int'> >>> 7//2 3 >>> 7/2 3.5 >>> type(3.5) <class 'float'> >>> type(3.) <class 'float'> >>> type(.3) <class 'float'> >>> type(3) <class 'int'> >>> abs(-14) 14 >>> 7%2 1 >>> 2.1+.5 2.6 >>> 2.1/.5 4.2 >>> round(8.3) 8 >>> type(round(8.3)) <class 'int'> >>> int(3.9) 3 >>> float(3) 3.0 >>> 5e10 50000000000.0 >>> 199219034787493827498734987239748.949823498782374897324 1.9921903478749383e+32 >>> True and False False >>> not (True or False) False >>>
Notar que 1
e 1.0
não correspondem à mesma entidade, tendo diferentes representações (mesmo internas), no entanto os operadores sobre números sabem lidar com estas diferentes representações através de sobrecarga.
>>> 4+7.2 11.2 >>> type(4+7.2) <class 'float'> >>> 1/3 0.3333333333333333 >>> 1//3 0 >>>
Nomes
Em programação é importante designar entidades através do uso de nomes. Neste contexto podemos referirmos-nos às entidades através do seu nome. Como as entidades podem variar durante a execução do programa, os nomes são também conhecidos por variáveis. Os nomes em Python podem ser simples, indexados ou compostos,
<nome> ::= <nome simples> | <nome indexado> | <nome composto>
Para já vamos apenas preocupar-nos com nomes simples,
<nome simples> ::= <inicial> <subsequente>* <inicial> ::= _ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z <subsequente> ::= <inicial> | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
No Python 3 os nomes podem conter ainda outros caracteres (mas detalhes na documentação do Python), no entanto teremos em conta a definição acima no que se segue.
Alguns nomes estão reservados no Python e não podem ser associados a entidades. Nomes reservados:
False class finally is return None continue for lambda try True def from nonlocal while and del global not with as elif if or yield assert else import pass break except in raise
Atribuição
A associação de um nome a um entidade é conseguida através da instrução de atribuição em Python e recorre à operação pré-definida =
. Podemos ter atribuições simples ou múltiplas:
<instrução de atribuição> ::= <nome> = <expressão> | <nome> , <instrução de atribuição>, <expressão>
Após uma instrução de atribuição, se o nome não existir no ambiente, então a nova associação é incluída no ambiente, caso contrário a associação existente no ambiente é substituída pela nova associação. O ambiente consiste num mapa de associação entre nomes e entidades computacionais que é mantido em memória e onde são incluídas todas as associações que o interpretador de Python conhece num dado contexto.
Na execução de uma instrução de atribuição, primeiro é avaliada a expressão (do lado direito) e em segundo é feita uma associação entre o nome (do lado esquerdo) e o valor obtido na avaliação da expressão. No caso de uma atribuição múltipla todas as expressões são avaliadas primeiro (a ordem é irrelevante) e só depois são feitas as respectivas associações.
Exemplo:
>>> not = 9 File "<stdin>", line 1 not = 9 ^ SyntaxError: invalid syntax >>> x = 8 >>> y Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'y' is not defined >>> x 8 >>> y = x * 2 >>> y 16 >>> x = 7 >>> y 16 >>> x, z = 10, 3 >>> x+z 13 >>> x, z = z, x >>> x 3 >>> z 10 >>> z , a = a + 3, 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>>
Predicados e condições
Uma operação cuja avaliação resulta num valor do tipo lógico, i.e., bool
, designa-se por predicado. As expressões que tomam um valor lógico designam-se por condições. Nota-se no entanto que em Python qualquer expressão pode ser tomada por condição, caso em que se o valor for zero ou False
, a condição é considerada como falsa, e em caso contrário é considerada como verdadeira.
As condições podem ser combinadas através de operações lógicas (not
, and
, or
). Existem também operadores relacionais que nos permitem definir condições (==
, !=
, >
, <
, <=
).
Exemplos:
>>> x = 8 >>> x < 7 False >>> x < 7*3 True >>> x < 7*3 and x > 10 False >>> x < 7*3 < 25 True >>> x < 7*3 < 25 > 10 True >>> x < 7*3 < 25 > 100 False >>>
Este exemplos incluem também o uso de algum açúcar sintáctico.
Leitura e escrita
A comunicação com o exterior é um ingrediente indispensável em grande parte dos programas. Durante a execução de um programa pode ser necessário obter valores do exterior, fornecidos pelos utilizadores ou obtidos de outros programas ou ficheiros, e comunicar resultados ou enviar dados para outros programas. Nesta secção vamos começar por ver formas simples de ler dados, a função input
, e de escrever dados, função print
.
Leitura de dados, notação BNF:
<leitura de dados> ::= input() | input(<informação>) <informação> ::= <cadeia de caracteres>
A execução da instrução input
mostra no ecrã a informação, i.e., a cadeia de caracteres, após o que lê todos os símbolos introduzidos no teclado até que o utilizador carregue na tecla Enter
. O valor resultante da execução desta instrução é a cadeia de caracteres obtida da leitura.
A cadeia de caracteres passada como argumento da função input
pode conter caracteres de escape, e.g., \n
, \r
, \t
, \v
, etc.
Exemplo:
>>> input("Introduza uma expressão:\n\t") Introduza uma expressão: 201+1 '201+1' >>>
Uma vez que o valor obtido na execução da função input
é uma cadeia de caracteres, para ler inteiros ou reais vamos utilizar a função pré-definida eval
designada por função de avaliação, com a seguinte sintaxe:
<função de avaliação> ::= eval(<cadeia de caracteres>)
Esta função recebe uma cadeia de caracteres e devolve o resultado de avaliar a mesma como sendo uma expressão de Python.
Exemplo:
>>> eval('201+1') 202 >>> type(eval('201+1')) <class 'int'> >>>
Combinando ambas as funções:
>>> x = eval(input("Introduza uma expressão:\n\t")) Introduza uma expressão: 4+4.5/2 >>> x 6.25 >>> type(x) <class 'float'> >>>
Nota-se que o uso de eval
neste exemplo apresenta sérios problemas de segurança e que deve ser evitado em produção e/ou programas utilizados por terceiros. O problema reside no facto de não ser feita qualquer verificação da sequência de caracteres lida pela função input
antes de proceder à sua avaliação com a função eval
, podendo um utilizador malicioso explorar este facto para conseguir fazer uso indevido do software.
A função print
tem a seguinte sintaxe, em notação BNF:
<escrita de dados> ::= print() | print(<expressões>) <expressões> ::= <expressão> | <expressão>, <expressões>
A avaliação da instrução print
começa pela avaliação das expressões passadas como argumento da função print
após o que escreve a representação externa de cada um dos valores resultantes, por ordem, todos na mesma linha, separados por um espaço em branco, e terminando com uma linha em branco. Nota-se que no caso da instrução print()
a avaliação resulta apenas na escrita de uma linha em branco.
Exemplo:
>>> x = eval(input("Introduza uma expressão:\n\t")) Introduza uma expressão: 4 >>> y = input("Introduza uma string:\n\t") Introduza uma string: olá mundo >>> print(x, "e", y) 4 e olá mundo >>>
E qual é o valor resultante de avaliar a instrução print
?
>>> v = print(x, "e", y) 4 e olá mundo >>> print(v) None >>>
A avaliação da instrução print
não devolve nada. Este é o resultado de várias funções em Python cujo objectivo não é retornar um valor, mas sim ter um efeito.