Mais sobre entradas e saídas de dados

1. Qual a diferença entre declarar e usar uma variável?

Uma variável nada mais é que um nome associado à uma posição de memória do computador: a posição de seu bit inicial e o número de bits usados para representar aquele tipo de variável. Como a linguagem Python é interpretada, pode-se em qualquer parte declarar uma variável e depois pode-se usá-la, recebendo valores ou expressões.

def main () :
  i = 3; # declara variavel inteira 'i' (i sendo iniciada com valor 3)
  x = 0.5; # declara variavel inteira 'x' (iniciada com 0.5)
  y = i/2; # declara variavel inteira 'y' (pois i e' inteiro => recebera' 3/2 = 1)
  # %d e' formatador para imprimir inteiro, %f para flutuante - y=%f e' para comprovar que 3/2 = 1  
  print("i=%d, x=%f, y=%f" % (i, x, y));
  ...
main();
Cód. 1. Código ilustrando a declaração de variáveis inteiras e flutuantes.

Outro conceito essencial às variáveis é o de atribuição de valor. Sua sintaxe em Python, e em muitas outras linuguagens, é usar do lado esquerdo da atribuição um nome de variável e do lado direito da atribuição uma expressão aritméitca válida. No código 1, i=0 e x=0.5 são atribuições, então funciona no Python como declaração de variável, desse modo i será variável inteira e x flutuante. tendo como lado esquerdo as variáveis i e x e como lado direito as expressões constantes 0 e 0.5.

Vamos ilustrar expressões com um operador especial do Python 3, o quociente da divisão inteira que é obtido com o operador binário // (de modo complementar, o resto da divisão inteira é obtido com o operador binário %). Assim, 5//2 resulta no valor 2 (e 5%2 resulta no valor 1, pois 2*2 + 1 = 5).

Desse modo, se um trecho de código tem uma variável n inteira (e.g. n = 5), como a constante 2 também é inteira, então a atribuição i = n//2, tem como lado direito a expressão n//2 que é um valor inteiro (e.g., se n=5, então 5//2 resulta no valor 2), portanto a variável i é declarada como inteira.

Por outro lado, o código x = 2*float(n) resulta na declaração da variável x como flututante, da mesma forma que y = n/2 resulta em declarar y como flututante.
Entretando, o conversor float é errelevante na expressão float(n/2), pois (no Python 3) n/2 já resulta flutuante.

Para saber mais "clique" na seta A figura 1 ilustra a associação de espaço em memória (RAM) para duas variáveis, são associados 16 bits à variável de nome n, para guardar valores inteiros, seguido da associação de 32 bits para a variável de nome x, que deve guardar valores "reais". Nota-se que a variável "real" tem um esquema mais "complicado", ela implementa o conceito de ponto flutuante, usando o padrão IEEE 754 (o primeiro bit é o sinal s; os 8 bits seguintes correspondente ao expoente e e os últimos 23 à mantissa m - valor de x é s x m x 10e, sendo m entre 0 e 1).

Fig. 1. Representação da memória com agrupamentos em bytes (8 bits).

Procure lembrar-se: em Python, sempre que existe uma atribuição, a variável que aparece do lado esquerdo da atribuição está sendo (re)definida! Isso corresponde à sua declaração!
Isso implica que, na declaração é reservado um espaço de tamanho fixo na memória do computador, o "tamanho" desse espaço depende do tipo da variável.

2. O que são "entradas de dados" e "saídas de dados"?

Um algoritmo é uma sequência finita de passos, que ao ser aplicado à um conjunto de dados (entradas) deve produzir sempre as mesmas saídas. Por exemplo, o algoritmo da divisão ao ser aplicado sobre valores fixados a e b, deve produzir sempre o mesmo valor q (de tal forma que q * b = a, ou seja, o quociente q vezes o denominador b recupera o valor do numerador a).

Por outro lado, um programa, em Python ou em qualquer outra linguagem, nada mais é que a implementação de um algoritmo na referida linguagem. Desse modo, para este programa ser usado, o usuário (aquele que está executando) deve fornecer um conjunto de dados de entrada, na ordem adequada (pois a/b geralmente não é o mesmo que b/a), para que o programa possa ser executado e produzir as saídas desejadas.


Fig. 2. Ilustração da existência de um algoritmo que aplicado sobre as entradas produz as respectivas saídas.

Podemos usar o mesmo exemplo da divisão para ilustrar a necessidade dos dados de entrada adequados. Para que um algoritmo para a divisão de dois números reais seja adequadamente executado, devem ser fornecidos os dois valores reais, o primeiro será o numerador e o segundo será o denominador. Assim, se o usuário digitar apenas um valor, o programa ficará parado até que ele digite o segundo valor.

Saber mais Vale observar que, em uma linguagem de programação, não existe a necessidade de implementar algo tão básico quanto à divisão de dois números, pois isso é feito por um algoritmo implementado diretamente no processador do computador. Desde a proposta do computador EDVAC, apresentada em documento de 1945 pelo matemático John von Neumann, existe uma unidade lógico/aritmética especialmente projetada para realizar as operações lógicas e aritméticas. Entretanto, nesse modelo o tratamento para "números reais" era feito com ponto fixo, enquanto hoje utilizamos ponto flutuante por permitir um maior escopo de valores.

3. Entrada e saída de dados simples: inteiro e "real" em Python 3

Na versão 3 do Python a função input() passou a devolver sempre cadeia de caracteres (que é usualmente tratada pelo correspondente em Inglês "strings").
Desse modo, se o usuário deseja trabalhar com um valor inteiro, deve convertê-lo para inteiro logo após a leitura usando a função int(.), por exemplo: n = int(input())
O análogo deve ser feito para "reais", flutuantes, usando-se float(.): x = float(input())

O código 2 mostra a entrada de um valor inteiro (um Enter), seguido pela entrada de um valor "real" (outro Enter).

def leia1 () :
  a = int(input()); b = float(input()); # o primeiro ';' e' obrigatorio para poder usar 2 atribuicoes em uma unica linha
  print(a,b); # o finalizador ';' e' opcional

leia1(); # chama a funcao para leitura
Cód. 2. Código ilustrando a entrada para valor inteiro e para "flutuante".

Vale notar que, para o código 2, se o usuário digitar um "real" como primeira entrada, ele receberá uma mensagem de erro. Abaixo a mensagem de erro após digitar o número 5.16:
  File "codigos/introducao_leituras_python_3.py", line 2, in leia1
    a = int(input()); b = float(input());
ValueError: invalid literal for int() with base 10: '5.16'

4. Saída de dados formatada: inteiro, "real" e caractere em Python 3

Em Python é possível fazer impressões mais sofisticadas utilizando um formatador (%) seguido de um caractere indicando o tipo da variável ser impressa: d ⇒ "inteiro"; f ⇒ "float"; c ⇒ "caractere"; s ⇒ "string". Por exemplo, pode-se usar os comandos
    m = 2; x = 2.3; t = 'A';
    print("m=%d, x=%f, t=%c" % (m, x, t)); # imprime m, x e t


que ao ser interpretado pelo Python resulta na impressão
    m=2, x=2.300000, t=A

Devemos destacar que o quarto caractere percentagem (%), imediatamente antes de (m, x, t), é para separar o texto a ser impresso dos valores a serem usados nos formatadores. Os valores estão na lista de valores (m, x, t) (que poderia usar alguma expressão em qualquer deles) a ser impressa, sendo a ordem importante. No exemplo, o primeiro formatador %d será usado para imprimir a primeira variável m (inteira), o segundo %f é associado à segunda variável t (que é "flutuante") e o terceiro %c é para t (caractere).

Os formatadores podem facilitar a impressão de tabelas, utilizando valores entre o símbolo de porcentagem e o tipo de variável a ser impressa, por exemplo: %3d usa 3 espaços, ajutando à direita o último, %8.3f usa 8 espaços, ajutando à direita o último e colocando o ponto decimal na terceira posição (da direita para esquerda). Experimente criar um arquivo cod_formatadores_1.py com as linhas abaixo:
    m = 2; x = 2.3; t = 'A';
    print("m=%3d, x=%8.3f, t=%2c" % (m, x, t));
Ela deverá produzir a seguinte saída:
    m= 2, x= 2.300, t= A


 $ python cod_formatadores_1.py
 m=  2, x=   2.300, t= A
Cód. 3. Usando código com formatadores.

Na tabela 1, apresentamos códigos ilustrativos para entrada e saída de valores inteiros e flutuantes. Outro aspecto importante que é ilustrado é o tratamento de divisão no Python 3, que precisa diferenciar a divisão inteira (e.g. a // b) da divisão flutuante (e.g. a / b).

Tab. 1. Exemplo de códigos para entrada e saída de inteiros e "reais" para o Python 3
Python 3: código com formatador Exemplo para entradas e respectivas saídas
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
18
20
21
22
23
24
25
26
# No Python 3 "input()" pega um linha inteira como caracteres
# Se for necessario usar valores numericos, precisa converter um a um

def leia_imprima () :
  # Ilustrando a entrada de um texto:
  texto = input();
  print("Foi digitado: %s" % texto); # formatador %s e' para "string"

  # Ilustrando entrada de inteiro e divisao inteira/"real"
  n = int(input()); # "int(.)" tenta converter para inteiro
  m1 = n//2;     # divisao inteira => m1 sera' "int"
  m2 = n/2;      # divisao "real"  => m2 sera' "float"
  print("n=%d=%f, m1=%f=%d, m2=%f!=%d" % (n,n,m1,m1,m2,m2));

  # Ilustrando que nova atribuicao => nova definicao
  n = 4.7; # Nova atribuicao => redeclara, agora float
  m1 = 3*n; # idem, m1 passa a ser "float"
  print("n=%f, m1=%f != %d" % (n,m1,m1)); 

  # Ilustrando entrada de flutuante e divisao "real"
  n = float(input()); # "float(.)" tenta converter para flutuante
  m1 = n//2;     # divisao inteira => m1 sera' "int"
  m2 = n/2;      # divisao "real"  => m2 sera' "float"
  print("n=%d=%f, m1=%f=%d, m2=%f!=%d" % (n,n,m1,m1,m2,m2));

leia_imprima()





Entrada: este e' um teste
Saída:   Foi digitado: este e' um teste


Entrada: 3
Explicação: 3//2 é quociente da divisão inteira, logo m1 receberá o valor 1
Explicação: 3/2 é quociente da divisão "real", logo m2 receberá o valor 1.5
Saída:   n=3=3.000000, m1=1.000000=1, m2=1.500000!=1


Explicação: nova definição para variável n que passou a ser do tipo flutuante com valor 4.7
Explicação: nova definição para variável m1 que passou a ser do tipo flutuante com valor 14.1
Saída:   n=4.700000, m1=14.100000 != 14


Entrada: 3.2
Explicação: m1 recebe quociente da divisão inteira por 2, logo m1 receberá o valor 1
Explicação: m2 recebe divisão "real", logo m2 receberá o valor 1.6
Saída:   n=3=3.200000, m1=1.000000=1, m2=1.600000!=1


Se o programador desejar inserir várias entradas com uma única linha deve-se, após o comando input(.), utilizar algumas funções especiais, como discutido na seção seguinte.

5. Entrada de dados: vários valores em uma só linha no Python 3

Como citado acima, a versão 3 do Python passou a fazer a leitura dos dados como uma sequência de caracteres ("string"). Assim, se for necessário tratar alguma entrada como valor numérico, o resultado devolvido pelo input() deverá necessáriamente passar por alguma conversão.

Assim, se for necessário entrar vários valores de uma só vez deve-se usar uma sequência de comandos:

  1. input(): para forçar que a leitura seja feita pegando uma sequência de caracteres (cadeia de caracteres ou "string") - a partir do Python 3 o comando input() passar a fazer isso;
  2. string.split(): é uma função especial para string que, quebra cada item considerando espaços em branco;
  3. map(tipo, iterador): para aplicar uma função (no caso, o conversor de tipo) sobre cada um dos elementos de uma estrutura que permite iteração (como mapa);
  4. list(iterador): devolve uma lista com todos de uma estrutura que permite iteração (como mapa).

Por exemplo, para digitar as dimensões de uma matriz (número de linhas e de colunas) em uma única linha (como 3 2 ENTER), pode-se usar a seguinte sequência de comandos:

m, n = map(int, input().split()); # input pega a "string" digitada "2 4"
print("m=%d, n=%d" % (m, n));
Cód. 4. Código para digitar 2 inteiros em uma única linha (único ENTER).
As funções especiais usadas no código 1 estão explicadas a seguir:
  1. input() pegar a "string" digitada (e.g. supor ter sido digitado 2 4 3.1 6.1 ENTER;
  2. split() quebra a "string", gerando uma lista (e.g. ("2", "4", "3.1", "6.1"))
  3. map com parâmetro float aplica um algoritmo de conversão em cada item tornando-os "float" (e.g. (2.0, 4.0, 3.1, 6.1))
  4. map com parâmetro int aplica um algoritmo de conversão em cada item tornando-os "int" (e.g. (2, 4))

Mas com a conversão é uniforme na função map, se tiver misturas de valores seria necessário algum "truque". Por exemplo, suponha que precise digitar 2 inteiros seguindos por 2 "flutuantes" (com um único ENTER). Nesse caso pode-se converter todos para "flutuante" (pois o contrário poderia implicar em perder os decimais) e depois conveter o que interssa para inteiro:

m, n, x, y = map(float, input().split()); # pega-se 4 valores (e.g. "2 4 3.1 6.1") como "float"
m, n = map(int, [m, n]); # gere uma lista [m,n] e a converta para inteiro
print("m=%d, n=%d" % (m, n));
print("m=%d, n=%d, x=%f, y=%f" % (m, n, x, y));
Cód. 5. Código para digitar 2 inteiros e 2 "flutuantes" em uma única linha (único ENTER), arquivo cod_formatadores_2.py.
Essa linha corresponde a uma sequência de passos:
  1. input() pegar a "string" digitada (e.g. supor ter sido digitado 2 4 3.1 6.1 ENTER);
  2. split() quebra a "string", gerando uma lista (e.g. ("2", "4", "3.1", "6.1"))
  3. map com parâmetro float aplica um algoritmo de conversão em cada item tornando-os "float" (e.g. (2.0, 4.0, 3.1, 6.1))
  4. map com parâmetro int aplica um algoritmo de conversão em cada item tornando-os "int" (e.g. (2, 4))

Para o código anterior, se rodá-lo com o Python 3, supondo que seja digitado 2 4 3.1 6.1 (com um único ENTER), produzirá o seguinte resultado:


$ python cod_formatadores_2.py  
2 4 3.1 6.1
m=2, n=4
m=2, n=4, x=3.100000, y=6.100000
Fig. 3. Ilustração do erro ao supor que existe comentários aninhados em Python.

Para um exemplo mais sofisticado, podemos elaborar um código para digitar as dimensões de uma matriz (número de linhas e de colunas) e todos seus elementos em uma única linha, como 3 2 0 1 2 3 4 5 ENTER. Para isso podemos usar a seguinte sequência de comandos:

lista = list(map(float, input().split())); # converter a "string" digitada "3 2 1.0 1.1 1.2 1.3 1.4 1.5" em flutuantes
m = int(lista[0]); n = int(lista[1]);      # converte 2 primeiros para inteiro
print("m=%d, n=%d" % (m, n));              # imprimir m e n
# passear pela lista para gerar linhas e colunas da matriz
conta = 2; # tem que "pular" os 2 primeiros
mat = []; # inicia nova lista que sera matriz
for i in range(m) :
  linha = []; # inicia nova linha da matriz
  for j in range(n) :
    linha.append(lista[conta]);
    conta += 1; # avancar para proximo elemento
    # finalizada a linha
  mat.append(linha); # nova linha da matriz - mat[conta]

# Conferindo a matriz
for i in range(m) :
  for j in range(n) :
    print("%4.1f " % mat[i][j], end=""); # 'end=""' => NAO quebrar linha
  print(); # quebra linha
Cód. 6. Código para digitar em uma única linha todos os dados de uma matriz, iniciando por número de linhas e colunas.

Note que no código 2 foi necessário um "truque" adicional para quebrar os elementos da lista em linhas para compor uma matriz. Desse modo foi necessário construir linhas (via append(.)) e a cada linha deve-se anexá-la à matriz (via mat.append(.)).

Leônidas de Oliveira Brandão
http://line.ime.usp.br

Alterações :
2022/11/07: acerto no cod. 3 "formatores" para "formatadores"
2021/07/14: várias quenas correções
2021/06/25: revisão completa da seção 5
2021/04/22: pequenos acertos, alterações visibilidade desse rodapé
2021/04/20: pequenas correções
2020/08/14: novo formato, pequenas revisões
2020/07/06: Segunda, 06 Julho 2020, 23:30