# 7. Entrada e Saída

Existem várias maneiras de apresentar a saída de um programa; os dados podem ser exibidos ou impressos em forma legível para seres humanos, ou escritos em arquivos para uso posterior. Este capítulo apresentará algumas das possibilidades.

## 7.1. Refinando a formatação de saída

Até agora vimos duas maneiras de exibir valores: expressões e a função `print()`. (Uma outra maneira é utilizar o método `write()` de objetos arquivo; o arquivo saída padrão pode ser referenciada como `sys.stdout`. Veja a Referência da Biblioteca Python para mais informações sobre isto.)

Frequentemente é desejável mais controle sobre a formatação de saída do que simplesmente exibir valores separados por espaços. Existem duas formas de formatar a saída. A primeira é manipular strings através de fatiamento (slicing) e concatenação. Os tipos string têm métodos úteis para criar strings com tamanhos determinados, usando caracteres de preenchimento; eles serão apresentados a seguir. A segunda forma é usar o método `str.format()`.

O módulo `string` tem uma classe `string.Template` que oferece uma outra maneira de inserir valores em strings.

Permanece a questão: como converter valores para strings? Felizmente, Python possui duas maneiras de converter qualquer valor para uma string: as funções `repr()` e `str()`.

A função `str()` serve para retornar representações de valores que sejam legíveis para as pessoas, enquanto `repr()` é para gerar representações que o interpretador Python consegue ler (ou levantará uma exceção `SyntaxError`, se não houver sintaxe equivalente). Para objetos que não têm uma representação adequada para consumo humano, `str()` devolve o mesmo valor que `repr()`. Muitos valores, tal como números ou estruturas, como listas e dicionários, têm a mesma representação usando quaisquer das funções. Strings, em particular, têm duas representações distintas.

Alguns exemplos:

    >>> s = 'Hello, world.'
    >>> str(s)
    'Hello, world.'
    >>> repr(s)
    "'Hello, world.'"
    >>> str(1/7)
    '0.14285714285714285'
    >>> x = 10 * 3.25
    >>> y = 200 * 200
    >>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
    >>> print(s)
    The value of x is 32.5, and y is 40000...
    >>> # The repr() of a string adds string quotes and backslashes:
    ... hello = 'hello, world\n'
    >>> hellos = repr(hello)
    >>> print(hellos)
    'hello, world\n'
    >>> # The argument to repr() may be any Python object:
    ... repr((x, y, ('spam', 'eggs')))
    "(32.5, 40000, ('spam', 'eggs'))"

A seguir, duas maneiras de se escrever uma tabela de quadrados e cubos::

    >>> for x in range(1, 11):
    ...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
    ...     # Note use of 'end' on previous line
    ...     print(repr(x*x*x).rjust(4))
    ...
     1   1    1
     2   4    8
     3   9   27
     4  16   64
     5  25  125
     6  36  216
     7  49  343
     8  64  512
     9  81  729
    10 100 1000

    >>> for x in range(1, 11):
    ...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
    ...
     1   1    1
     2   4    8
     3   9   27
     4  16   64
     5  25  125
     6  36  216
     7  49  343
     8  64  512
     9  81  729
    10 100 1000

(Note that in the first example, one space between each column was added by the way `print()` works: by default it adds spaces between its arguments.)

Esse exemplo demonstra o método `str.rjust()` de objetos string, que alinha uma string à direita juntando espaços adicionais à esquerda. Existem métodos análogas `str.ljust()` e `str.center()`. Esses métodos não exibem nada na tela, apenas devolvem uma nova string formatada. Se a entrada extrapolar o comprimento especificado, a string original é devolvida sem modificação; isso pode estragar o alinhamento das colunas, mas é melhor do que a alternativa, que seria apresentar um valor mentiroso. (Se for realmente desejável truncar o valor, pode-se usar fatiamento, por exemplo: `x.ljust(n)[:n]`.)

Existe ainda o método `str.zfill()` que preenche uma string numérica com zeros à esquerda, e sabe lidar com sinais positivos e negativos:

    >>> '12'.zfill(5)
    '00012'
    >>> '-3.14'.zfill(7)
    '-003.14'
    >>> '3.14159265359'.zfill(5)
    '3.14159265359'

Um uso básico do método `str.format()` tem esta forma:

    >>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
    We are the knights who say "Ni!"

As chaves e seus conteúdos (chamados campos de formatação) são substituídos pelos objetos passados para o método `str.format()`. Um número nas chaves pode ser usado para referenciar a posição do objeto passado no método `str.format()`.

    >>> print('{0} and {1}'.format('spam', 'eggs'))
    spam and eggs
    >>> print('{1} and {0}'.format('spam', 'eggs'))
    eggs and spam

Se argumentos nomeados são passados para o método `str.format()`, seus valores serão referenciados usando o nome do argumento:

    >>> print('This {food} is {adjective}.'.format(
    ...       food='spam', adjective='absolutely horrible'))
    This spam is absolutely horrible.

Argumentos posicionais e nomeados podem ser combinados à vontade:

    >>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                           other='Georg'))
    The story of Bill, Manfred, and Georg.

`'!a'` (apply `ascii()`), `'!s'` (apply `str()`) and `'!r'` (apply `repr()`) can be used to convert the value before it is formatted:

    >>> contents = 'eels'
    >>> print('My hovercraft is full of {}.'.format(contents))
    My hovercraft is full of eels.
    >>> print('My hovercraft is full of {!r}.'.format(contents))
    My hovercraft is full of 'eels'.

Após o identificador do campo, uma especificação de formato opcional pode ser colocada depois de `:` (dois pontos). O exemplo abaixo arredonda Pi até a terceira casa após o ponto decimal.

    >>> import math
    >>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
    The value of PI is approximately 3.142.

Colocar um inteiro n logo após o `:` fará o campo ocupar uma largura mínima de n caracteres. Isto é útil para organizar tabelas.

    >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
    >>> for name, phone in table.items():
    ...     print('{0:10} ==> {1:10d}'.format(name, phone))
    ...
    Jack       ==>       4098
    Dcab       ==>       7678
    Sjoerd     ==>       4127

Se uma string de formatação é muito longa, e não se deseja quebrá-la, pode ser bom referir-se aos valores a serem formatados por nome, em vez de posição. Isto pode ser feito passando um dicionário usando colchetes `[]` para acessar as chaves:

    >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
    >>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
    ...       'Dcab: {0[Dcab]:d}'.format(table))
    Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Isto também pode ser feito passando o dicionário como argumento do método, usando a notação `**`:

    >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
    >>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
    Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Isto é particularmente útil em conjunto com a função embutida `vars()`, que devolve um dicionário contendo todas as variáveis locais.

Para uma visão completa da formatação de strings com `str.format()`, veja a seção Sintaxe das strings de formato.

### 7.1.1. Formatação de strings à moda antiga

O operador `%` também pode ser usado para formatação de strings. O operando da esquerda é interpretado de forma semelhante ao estilo de formatação da função `sprintf()` da linguagem C, aplicando a formatação ao operando da direita, e devolvendo a string resultante. Por exemplo:

    >>> import math
    >>> print('The value of PI is approximately %5.3f.' % math.pi)
    The value of PI is approximately 3.142.

Mais informação pode ser encontrada na seção Formatação de String no Formato printf-style.

## 7.2. Leitura e escrita de arquivos

A função `open()` devolve um file object, e é frequentemente usada com dois argumentos: `open(filename, mode)`.

    >>> f = open('workfile', 'w')

O primeiro argumento é uma string contendo o nome do arquivo. O segundo argumento é outra string, contendo alguns caracteres que descrevem o modo como o arquivo será usado. O parâmetro mode pode ser `'r'` quando o arquivo será apenas lido, `'w'` para escrever (se o arquivo já existir seu conteúdo prévio será apagado), e `'a'` para abrir o arquivo para adição; qualquer escrita será adicionada ao final do arquivo. A opção `'r+'` abre o arquivo tanto para leitura como para escrita. O parâmetro `mode` é opcional, em caso de omissão será assumido `'r'`.

Normalmente, os arquivos são abertos em modo texto, ou seja, você lê e grava strings de e para o arquivo, numa codificação específica. Se a codificação não for especificada, o padrão é dependente da plataforma (consulte `open()`). `'b'` anexado ao modo abre o arquivo em modo binário: agora os dados são lidos e escritos na forma de bytes. Este modo deve ser usado para todos os arquivos que não contenham texto.

Em modo texto, o padrão durante a leitura é converter terminadores de linha específicos da plataforma (`\n` no Unix, `\r\n` no Windows) para apenas `\n`. Ao escrever no modo de texto, o padrão é converter as ocorrências de `\n` de volta para os finais de linha específicos da plataforma. Essa modificação de bastidores nos dados do arquivo é adequada para arquivos de texto, mas corromperá dados binários, como arquivos `JPEG` ou `EXE`. Tenha muito cuidado para só usar o modo binário, ao ler e gravar esses arquivos.

It is good practice to use the `with` keyword when dealing with file objects. The advantage is that the file is properly closed after its suite finishes, even if an exception is raised at some point. Using `with` is also much shorter than writing equivalent `try`-`finally` blocks:

    >>> with open('workfile') as f:
    ...     read_data = f.read()
    >>> f.closed
    True

Se você não estiver usando a palavra-chave `with`, então você deve chamar `f.close()` para fechar o arquivo e liberar imediatamente quaisquer recursos do sistema usados por ele. Se você não fechar explicitamente um arquivo, o coletor de lixo do Python irá eventualmente destruir o objeto e fechar o arquivo aberto para você, mas o arquivo pode ficar aberto por um tempo. Outro risco é que diferentes implementações de Python farão essa limpeza em momentos diferentes.

Depois que um arquivo é fechado, seja por uma instrução `with` ou chamando `f.close()`, as tentativas de usar o arquivo falharão automaticamente.

    >>> f.close()
    >>> f.read()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: I/O operation on closed file.

### 7.2.1. Métodos de arquivos

Para simplificar, o resto dos exemplos nesta seção assumem que um objeto arquivo chamado `f` já foi criado.

Para ler o conteúdo de um arquivo, chame `f.read(size)`, que lê uma quantidade de dados e retorna-os como uma string (em modo texto) ou bytes (em modo binário). O argumento numérico size é opcional. Quando size é omitido ou negativo, todo o conteúdo do arquivo é lido e retornado; se o arquivo é duas vezes maior que a memória da máquina, o problema é seu. Caso contrário, no máximo size bytes serão lidos e retornados. Se o fim do arquivo for atingido, `f.read()` retornará uma string vazia (“”).

    >>> f.read()
    'This is the entire file.\n'
    >>> f.read()
    ''

O método `f.readline()` lê uma única linha do arquivo; o caractere de quebra de linha (`\n`) é mantido ao final da string, e só é omitido na última linha do arquivo, se o arquivo não termina com uma quebra de linha. Isso elimina a ambiguidade do valor retornado; se `f.readline()` devolver uma string vazia, o fim do arquivo foi atingido. Linhas em branco são representadas por um `'\n'` – uma string contendo apenas o terminador de linha.

    >>> f.readline()
    'This is the first line of the file.\n'
    >>> f.readline()
    'Second line of the file\n'
    >>> f.readline()
    ''

Uma maneira alternativa de ler linhas do arquivo é iterar diretamente pelo objeto arquivo. É eficiente, rápido e resulta em código mais simples:

    >>> for line in f:
    ...     print(line, end='')
    ...
    This is the first line of the file.
    Second line of the file

Se desejar ler todas as linhas de um arquivo em uma lista pode-se usar `list(f)` ou `f.readlines()`.

`f.write(string)` escreve o conteúdo de string para o arquivo, retornando o número de caracteres escritos.

    >>> f.write('This is a test\n')
    15

Outros tipos de objetos precisam ser convertidos – seja para uma string (em modo texto) ou para bytes (em modo binário) – antes de escrevê-los:

    >>> value = ('the answer', 42)
    >>> s = str(value)  # convert the tuple to string
    >>> f.write(s)
    18

`f.tell()` retorna um inteiro dando a posição atual do objeto de arquivo, no arquivo representado, como número de bytes desde o início do arquivo, no modo binário, e um número ininteligível, quando no modo de texto.

Para mudar a posição do objeto arquivo, use `f.seek(offset, from_what)`. A posição é calculada somando-se offset ao ponto de referência; o ponto de referência é selecionado a partir do argumento from_what. Um valor 0 para from_what indica o início do arquivo, 1 usa a posição atual no arquivo, e 2 usa o fim do arquivo como ponto de referência. from_what pode ser omitido e assumirá o valor 0, usando o início do arquivo como ponto de referência.

    >>> f = open('workfile', 'rb+')
    >>> f.write(b'0123456789abcdef')
    16
    >>> f.seek(5)      # Go to the 6th byte in the file
    5
    >>> f.read(1)
    b'5'
    >>> f.seek(-3, 2)  # Go to the 3rd byte before the end
    13
    >>> f.read(1)
    b'd'

Em arquivos texto (abertos sem um `b`, em modo string), somente seeks relativos ao início do arquivo serão permitidos (exceto se for indicado o final do arquivo, com `seek(0, 2)`) e o único valor válido para offset são aqueles retornados por chamada à `f.tell()`, ou zero. Qualquer outro valor para offset produz um comportamento indefinido.

Objetos arquivo tem alguns método adicionais, como `isatty()` e `truncate()` que não são usados com frequência; consulte a Biblioteca de Referência para um guia completo de objetos arquivo.

### 7.2.2. Gravando dados estruturados com `json`

Strings podem ser facilmente gravadas e lidas em um arquivo. Números dão um pouco mais de trabalho, já que o método `read()` só retorna strings, que terão que ser passadas para uma função como `int()`, que pega uma string como `'123'` e retorna seu valor numérico 123. Quando você deseja salvar tipos de dados mais complexos, como listas e dicionários aninhados, a análise e serialização manual tornam-se complicadas.

Ao invés de ter usuários constantemente escrevendo e depurando código para gravar tipos complicados de dados em arquivos, o Python permite que se use o popular formato de troca de dados chamado JSON (JavaScript Object Notation). O módulo padrão chamado `json` pode pegar hierarquias de dados em Python e convertê-las em representações de strings; esse processo é chamado serialização. Reconstruir os dados da representação string é chamado desserialização. Entre serializar e desserializar, a string que representa o objeto pode ser armazenada em um arquivo ou estrutura de dados, ou enviada por uma conexão de rede para alguma outra máquina.

Nota

O formato JSON é comumente usado por aplicativos modernos para permitir a troca de dados. Pessoas que programam já estão familiarizados com esse formato, o que o torna uma boa opção para interoperabilidade.

Um objeto `x`, pode ser visualizado na sua representação JSON com uma simples linha de código:

    >>> import json
    >>> json.dumps([1, 'simple', 'list'])
    '[1, "simple", "list"]'

Outra variação da função `dumps()`, chamada `dump()`, serializa o objeto para um arquivo texto. Se `f` é um arquivo texto aberto para escrita, podemos fazer isto:

    json.dump(x, f)

Para decodificar o objeto novamente, se `f` é um arquivo texto que foi aberto para leitura:

    x = json.load(f)

Essa técnica de serialização simples pode manipular listas e dicionários, mas a serialização de instâncias de classe arbitrárias no JSON requer um pouco mais de esforço. A referência para o módulo `json` contém uma explicação disso.

Ver também

O módulo `pickle`

Ao contrário do JSON, pickle é um protocolo que permite a serialização de objetos Python arbitrariamente complexos. Por isso, é específico do Python e não pode ser usado para se comunicar com aplicativos escritos em outros idiomas. Também é inseguro por padrão: desserializar dados de pickle, provenientes de uma fonte não confiável, pode executar código arbitrário, se os dados foram criados por um invasor habilidoso.