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 em 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 inteiro '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.

Ainda usando como estrutura o código 1, outro exemplo de atribuição poderia ser i = n/2, que tem como lado direito a expressão n/2. Como no código 1 a variável n é do tipo inteiro, o mesmo para a constante 2 (se desejasse flutuante deveria usar 2.0), então seu resultado é o quociente da divisão inteira da divisão. Mas vale adiantar outra possibilidade de "forçar" o resultado a ser flutuante, usar o coversor de tipo: x = (float)n/2.

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).
Note que, 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.
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).

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 ilustar 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.

Vale observar que, usando uma linguagem como Python, não existe a necessidade de implementar algo tão básico (a divisão, pois isso é feito por um algoritmo implementado no processador do computador. Na verdade, desde a proposta inicial do matemática John von Neumann, existe uma unidade lógico/aritmética especialmente projetada para realizar as operações lógicas e aritméticas. Embora, o modelo inicialmente proposto por von Neumann preconizase o uso de ponto fixo, não o flutuante.
Entrada de dados simples: inteiro, real e texto em Python 2

Na versão 2 do Python a prioridade das entradas são os valores numéricos e a função para disparar o processo de "coleta" de dados é input(). Assim, usando o código da tabela 1, pode-se digitar um (único) valor inteiro e o programa imprime o valor e o dobro dele, em seguida o usuário deve digitar um (único) valor "real" e novamente é impresso o valor e seu dobro.

Em Python é possível fazer impressões mais sofisticadas utilizando um formatador (%) com o 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; f = 2.3; c = 'A';
    print("m=%d, f=%f, c=%c" % (m, f, c)); # imprime m, f e c

para imprimir inteiro, "float" e caractere (respectivamente).
Ainda pode-se usar um natural para indicar ajuste à direita e assim construir tabelas. Experimente: print("m=%3d, f=%8.3f, c=%2c" % (m, f, c));

Na tabela abaixo ilustra-se o uso da função/comando input() para entrada de dados no Python 2.

Tab. 1. Exemplo de códigos para entrada e saída de inteiros e "reais" para o Python 2
Python 2: impressão com formatador Python 2: com impressão simples
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
18
20
# Python 2 (Py2): funciona digitar 2 ou 2.4
# * O Py2 automaticamente transforma no tipo adequado
# * Mas o Python 3 (Py3) nao faz isso! Ele le^ tudo como
#   texto, entao precisa converter explicitamente para
#   para o que interssa, e.g. int(input())
#   Se usar, 'leitura1_Py2()' com Py3, resultara' no erro:
#     print("%d %s" % (n,n));
# TypeError: %d format: a number is required, not str
def leitura1_Py2 () :
  print("Digitar inteiro");
  # Suponha que digite 2
  n = input(); # ATENCAO: aqui define o tipo como "int"
  m = 3*n;     # como recebe inteiro => tambem sera' "int"
  # Imprime 2 e 6: Py2 automaticamente interpreta como numero
  print("n=%d 3*n=%d" % (n,m));
  n = 4.7; # Nova atribuicao => redeclara, agora float
  m = 3*n; # idem, m passa a ser "float"
  # Imprime 2 e 3*4: %f por agora ser "float"
  print("n=%f 3*n=%f" % (n,m)); 
leitura1_Py2()
# Python 2 (Py2): funciona digitar 2 ou 2.4
# * O Py2 automaticamente transforma no tipo adequado
# * Mas o Python 3 (Py3) nao faz isso! Ele le^ tudo como
#   texto, entao precisa converter explicitamente para
#   para o que interssa, e.g. int(input())
#   Se usar, 'leitura2_Py2()' com Py3, resultara' no erro:
#     print("%d %s" % (n,n));
# TypeError: %d format: a number is required, not str
def leitura2_Py2 () :
  print("Digitar inteiro");
  # Suponha que digite 2
  n = input(); # ATENCAO: declara "n" como "int"
  m = 3*n;     # declara "m" como "int"
  # Imprime 2 e 6
  print(n,m);
  n = 4.7; # Nova atribuicao => redeclara, agora float
  m = 3*n; # idem, m passa a ser "float"
  # Imprime 2 e 3*4: %f por agora ser "float"  
  print(n,m); 
leitura2_Py2()

Se o usuário desejar inserir outra coisa (em geral uma cadeia de caracteres - "string") deve-se usar uma função especial (vide raw_input a seguir).

Entrada de dados: vários valores em uma só linha no Python 2

Como citado acima, a versão 2 do Pythonprioridade às entradas serem valores numéricos, assim usando apenas input() automaticamente tenta-se interpretar o que foi digitado como número. Se forem digitados vários valores ou alguma palavra ocorre erro (File "", line 1).

Assim, se for necessário entrar vários valores de uma só vez deve-se usar um comando especial: raw_input() (que não mais existe no Python 3!). Entretanto, depois é preciso rodar um algoritmo para converter os dados, mas o Python já tem algumas funções/métodos pré-definidos para fazer isso como o split() que aplicado sobre uma "string" a quebra pegando cada um de seus elementos e a função map(tipo, lista) que pega uma lista de "strings" e gera uma lista de tipos.

Por exemplo, para digitar as dimensões de uma matriz e seu maior e menor valor em um único ENTER, pode-se usar o comando:
    m, n = map(int, raw_input().split()); # raw_input pega a "string" digitada "2 4"
É uma sequência de passos:
1. raw_input() pegar a "string" digitada (e.g. supor ter sido digitado 2 4 ENTER;
2. split() quebra a "string", gerando uma lista (e.g. ["2", "4"])
3. map com parâmetro int aplica um algoritmo de conversão em cada item tornando-os inteiro (e.g. [2, 4])
4. print("m=%d, n=%d" % (m, n, min, max));

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 ser digitado 2 inteiros seguindos de 2 "floats" (em um único ENTER), pode-se usar o conversor para o tipo de "maior tamanho" ("float" no caso) e depois fazer mais uma conversão:

   m, n, x, y = map(int, raw_input().split()); # raw_input pega a "string" digitada "2 4 3.1 6.1"
   m, n = map(int, [m, n]); # gere uma lista [m,n] e a converta para inteiro
É uma sequência de passos:
1. raw_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))
5. print("m=%d, n=%d, x=%f, y=%f" % (m, n, x, y));

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

Alterações:
2020/08/14: novo formato, pequenas revisões
2020/07/06: Segunda, 06 Julho 2020, 23:30