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.

    <verm>def</verm> main () :
      i = 3; <cyan># declara variavel inteira 'i' (i sendo iniciada com valor 3)</cyan>
      x = 0.5; <cyan># declara variavel inteira 'x' (iniciada com 0.5)</cyan>
      y = i/2; <cyan># declara variavel inteiro 'y' (pois i e' inteiro => recebera' 3/2 = 1)</cyan>
      <cyan># %d e' formatador para imprimir inteiro, %f para flutuante - y=%f e' para comprovar que 3/2 = 1</cyan>
      <verd>print</verd>("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 = (<verm>float</verm>)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';
<verd>print</verd>("m=%d, f=%f, c=%c" % (m, f, c)); <cyan># imprime m, f e c`</cyan>
para imprimir inteiro, "float" e caractere (respectivamente).
Ainda pode-se usar um natural para indicar ajuste à direita e assim construir tabelas. Experimente: `<verd>print</verd>("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

    <cyan># Python 2 (Py2): funciona digitar 2 ou 2.4</cyan>
    <cyan># * O Py2 automaticamente transforma no tipo adequado</cyan>
    <cyan># * Mas o Python 3 (Py3) nao faz isso! Ele le^ tudo como</cyan>
    <cyan>#   texto, entao precisa converter explicitamente para</cyan>
    <cyan>#   para o que interssa, e.g. int(input())</cyan>
    <cyan>#   Se usar, 'leitura1_Py2()' com Py3, resultara' no erro:</cyan>
    <cyan>#     <verd>print</verd>("%d %s" % (n,n));</cyan>
    <cyan># TypeError: %d format: a number is required, not str</cyan>
    <verm>def</verm> leitura1_Py2 () :
      <verd>print</verd>("Digitar inteiro");
      <cyan># Suponha que digite 2</cyan>
      n = <verd>input</verd>(); <cyan># ATENCAO: aqui define o tipo como "int"</cyan>
      m = 3*n;     <cyan># como recebe inteiro => tambem sera' "int"</cyan>
      <cyan># Imprime 2 e 6: Py2 automaticamente interpreta como numero</cyan>
      <verd>print</verd>("n=%d 3*n=%d" % (n,m));
      n = 4.7; <cyan># Nova atribuicao => redeclara, agora float</cyan>
      m = 3*n; <cyan># idem, m passa a ser "float"</cyan>
      <cyan># Imprime 2 e 3*4: %f por agora ser "float"</cyan>
      <verd>print</verd>("n=%f 3*n=%f" % (n,m)); <cyan></cyan>
    leitura1_Py2()

    <cyan># Python 2 (Py2): funciona digitar 2 ou 2.4</cyan>
    <cyan># * O Py2 automaticamente transforma no tipo adequado</cyan>
    <cyan># * Mas o Python 3 (Py3) nao faz isso! Ele le^ tudo como</cyan>
    <cyan>#   texto, entao precisa converter explicitamente para</cyan>
    <cyan>#   para o que interssa, e.g. int(input())</cyan>
    <cyan>#   Se usar, 'leitura2_Py2()' com Py3, resultara' no erro:</cyan>
    <cyan>#     <verd>print</verd>("%d %s" % (n,n));</cyan>
    <cyan># TypeError: %d format: a number is required, not str</cyan>
    <verm>def</verm> leitura2_Py2 () :
      <verd>print</verd>("Digitar inteiro");
      <cyan># Suponha que digite 2</cyan>
      n = <verd>input</verd>(); <cyan># ATENCAO: declara "n" como "int"</cyan>
      m = 3*n;     <cyan># declara "m" como "int"</cyan>
      <cyan># Imprime 2 e 6</cyan>
      <verd>print</verd>(n,m);
      n = 4.7; <cyan># Nova atribuicao => redeclara, agora float</cyan>
      m = 3*n; <cyan># idem, m passa a ser "float"</cyan>
      <cyan># Imprime 2 e 3*4: %f por agora ser "float"</cyan>
      <verd>print</verd>(n,m); <cyan></cyan>
    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 Python dá prioridade à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 "<string>", 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, <verd>raw_input</verd>().split()); <cyan># raw_input pega a "string" digitada "2 4"</cyan>`
É uma sequência de passos:
1. `<verd>raw_input</verd>()` 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. `<verd>print</verd>("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, <verd>raw_input</verd>().split()); <cyan># raw_input pega a "string" digitada "2 4 3.1 6.1"</cyan>
       m, n = map(int, [m, n]); <cyan># gere uma lista [m,n] e a converta para inteiro</cyan>

É uma sequência de passos:
1. `<verd>raw_input</verd>()` 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. `<verd>print</verd>("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