Python para Desenvolvedores

2ª edição, revisada e ampliada

Capítulo 11: Biblioteca padrão


É comum dizer que o Python vem com “baterias inclusas”, em referência a vasta biblioteca de módulos e pacotes que é distribuída com o interpretador.

Alguns módulos importantes da biblioteca padrão:

  • Matemática: math, cmath, decimal e random.
  • Sistema: os, glob, shutils e subprocess.
  • Threads: threading.
  • Persistência: pickle e cPickle.
  • XML: xml.dom, xml.sax e elementTree (a partir da versão 2.5).
  • Configuração: ConfigParser e optparse.
  • Tempo: time e datetime.
  • Outros: sys, logging, traceback, types e timeit.

Matemática

Além dos tipos numéricos builtins do interpretador, na biblioteca padrão do Python existem vários módulos dedicados a implementar outros tipos e operações matemáticas.

O módulo math define funções logarítmicas, de exponenciação, trigonométricas, hiperbólicas e conversões angulares, entre outras. Já o módulo cmath, implementa funções similares, porém feitas para processar números complexos.

Exemplo:

In [7]:
# Módulo para matemática
import math

# Módulo para matemática (de complexos)
import cmath

# Complexos
for cpx in [3j, 1.5 + 1j, -2 - 2j]:

    # Conversão para coordenadas polares
    plr = cmath.polar(cpx)
    print 'Complexo:', cpx
    print 'Forma polar:', plr, '(em radianos)'
    print 'Amplitude:', abs(cpx)
    print 'Ângulo:', math.degrees(plr[1]), '(graus)'
Complexo: 3j
Forma polar: (3.0, 1.5707963267948966) (em radianos)
Amplitude: 3.0
Ângulo: 90.0 (graus)
Complexo: (1.5+1j)
Forma polar: (1.8027756377319946, 0.5880026035475675) (em radianos)
Amplitude: 1.80277563773
Ângulo: 33.690067526 (graus)
Complexo: (-2-2j)
Forma polar: (2.8284271247461903, -2.356194490192345) (em radianos)
Amplitude: 2.82842712475
Ângulo: -135.0 (graus)

O módulo random traz funções para a geração de números aleatórios.

Exemplos:

In [8]:
import random
import string

# Escolha uma letra
print random.choice(string.ascii_uppercase)

# Escolha um número de 1 a 10
print random.randrange(1, 11)

# Escolha um float no intervalo de 0 a 1
print random.random()
B
2
0.117017323204

Na biblioteca padrão ainda existe o módulo decimal, que define operações com números reais com precisão fixa.

Exemplo:

In [9]:
from decimal import Decimal

t = 5.
for i in range(50):
    t = t - 0.1

print 'Float:', t

t = Decimal('5.')
for i in range(50):
    t = t - Decimal('0.1')

print 'Decimal:', t
Float: 1.02695629778e-15
Decimal: 0.0

Com este módulo, é possível reduzir a introdução de erros de arredondamento originados da aritmética de ponto flutuante.

Na versão 2.6, também está disponível o módulo fractions, que trata de números racionais.

Exemplo:

In [10]:
from fractions import Fraction

# Três frações
f1 = Fraction('-2/3')
f2 = Fraction(3, 4)
f3 = Fraction('.25')
print "Fraction('-2/3') =", f1
print "Fraction('3, 4') =", f2
print "Fraction('.25') =", f3

# Soma
print f1, '+', f2, '=', f1 + f2
print f2, '+', f3, '=', f2 + f3
Fraction('-2/3') = -2/3
Fraction('3, 4') = 3/4
Fraction('.25') = 1/4
-2/3 + 3/4 = 1/12
3/4 + 1/4 = 1

As frações podem ser inicializadas de várias formas: como string, como um par de inteiros ou como um número real. O módulo também possui uma função chamada gcd(), que calcula o maior divisor comum (MDC) entre dois inteiros.

Arquivos e I/O

Os arquivos no Python são representados por objetos do tipo *file*, que oferecem métodos para diversas operações de arquivos. Arquivos podem ser abertos para leitura ('r', que é o default), gravação ('w') ou adição ('a'), em modo texto ou binário('b').

Em Python:

  • sys.stdin representa a entrada padrão.
  • sys.stdout representa a saída padrão.
  • sys.stderr representa a saída de erro padrão.

A entrada, saída e erro padrões são tratados pelo Python como arquivos abertos. A entrada em modo de leitura e os outros em modo de gravação.

Exemplo de escrita:

In [3]:
import sys

# Criando um objeto do tipo file
temp = open('temp.txt', 'w')

# Escrevendo no arquivo
for i in range(20):
    temp.write('%03d\n' % i)

# Fechando
temp.close()

temp = open('temp.txt')

# Escrevendo no terminal
for x in temp:
    # Escrever em sys.stdout envia
    # o texto para a saída padrão
    sys.stdout.write(x)

temp.close()
000
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019

A cada iteração no segundo laço, o objeto retorna uma linha do arquivo de cada vez.

Exemplo de leitura:

In [12]:
import sys
import os.path

fn = 'teste.txt'

if not os.path.exists(fn):
    print 'Tente outra vez...'
    sys.exit()

# Numerando as linhas
for i, s in enumerate(open(fn)):
    print i + 1, s,
An exception has occurred, use %tb to see the full traceback.

SystemExit
Tente outra vez...
To exit: use 'exit', 'quit', or Ctrl-D.

É possível ler todas as linhas com o método readlines():

In [4]:
# Imprime uma lista contendo linhas do arquivo
print open('temp.txt').readlines()
['000\n', '001\n', '002\n', '003\n', '004\n', '005\n', '006\n', '007\n', '008\n', '009\n', '010\n', '011\n', '012\n', '013\n', '014\n', '015\n', '016\n', '017\n', '018\n', '019\n']

Os objetos do tipo arquivo também possuem um método seek(), que permite ir para qualquer posição no arquivo.

Na versão 2.6, está disponível o módulo io, que implementa de forma separada as operações de arquivo e as rotinas de manipulação de texto.

Sistemas de arquivo

Os sistemas operacionais modernos armazenam os arquivos em estruturas hierárquicas chamadas sistemas de arquivo (file systems).

Várias funcionalidades relacionadas a sistemas de arquivo estão implementadas no módulo os.path, tais como:

  • os.path.basename(): retorna o componente final de um caminho.
  • os.path.dirname(): retorna um caminho sem o componente final.
  • os.path.exists(): retorna True se o caminho existe ou False em caso contrário.
  • os.path.getsize(): retorna o tamanho do arquivo em bytes.

O glob é outro módulo relacionado ao sistema de arquivo:

In [2]:
import os.path
import glob

# Mostra uma lista de nomes de arquivos
# e seus respectivos tamanhos
for arq in sorted(glob.glob('*.py')):
    print arq, os.path.getsize(arq)

A função glob.glob() retorna uma lista com os nomes de arquivo que atendem ao critério passado como parâmetro, de forma semelhante ao comando ls disponível nos sistemas UNIX.

Arquivos temporários

O módulo os implementa algumas funções para facilitar a criação de arquivos temporários, liberando o desenvolvedor de algumas preocupações, tais como:

  • Evitar colisões com nomes de arquivos que estão em uso.
  • Identificar a área apropriada do sistema de arquivos para temporários (que varia conforme o sistema operacional).
  • Expor a aplicação a riscos (a área de temporários é utilizada por outros processos).

Exemplo:

In [3]:
import os

texto = 'Teste'
# cria um arquivo temporário
temp = os.tmpfile()

# Escreve no arquivo temporário
temp.write('Teste')

# Volta para o inicio do arquivo
temp.seek(0)

# Mostra o conteúdo do arquivo
print temp.read()

# Fecha o arquivo
temp.close()
Teste

Existe também a função tempnam(), que retorna um nome válido para arquivo temporário, incluindo um caminho que respeite as convenções do sistema operacional. Porém, fica por conta do desenvolvedor garantir que a rotina seja usada de forma a não comprometer a segurança da aplicação.

Arquivos compactados

O Python possui módulos para trabalhar com vários formatos de arquivos compactados.

Exemplo de gravação de um arquivo “.zip”:

In [ ]:
"""
Gravando texto em um arquivo compactado
"""

import zipfile

texto = """
***************************************
Esse é o texto que será compactado e...
... guardado dentro de um arquivo zip.
***************************************
"""

# Cria um zip novo
zip = zipfile.ZipFile('arq.zip', 'w',
    zipfile.ZIP_DEFLATED)

# Escreve uma string no zip como se fosse um arquivo
zip.writestr('texto.txt', texto)

# Fecha o zip
zip.close()

Exemplo de leitura:

In [4]:
"""
Lendo um arquivo compactado
"""

import zipfile

# Abre o arquivo zip para leitura
zip = zipfile.ZipFile('arq.zip')

# Pega a lista dos arquivos compactados
arqs = zip.namelist()

for arq in arqs:
    # Mostra o nome do arquivo
    print 'Arquivo:', arq
    # Pegando as informações do arquivo
    zipinfo = zip.getinfo(arq)
    print 'Tamanho original:', zipinfo.file_size
    print 'Tamanho comprimido:', zipinfo.compress_size

    # Mostra o conteúdo do arquivo
    print zip.read(arq)
Arquivo: texto.txt
Tamanho original: 162
Tamanho comprimido: 85

***************************************
Esse é o texto que será compactado e...
... guardado dentro de um arquivo zip.
***************************************

O Python também provê módulos para os formatos gzip, bzip2 e tar, que são bastante utilizados em ambientes UNIX.

Arquivo de dados

Na biblioteca padrão, o Python também fornece um módulo para simplificar o processamento de arquivos no formato CSV (Comma Separated Values).

No formato CSV, os dados são armazenados em forma de texto, separados por vírgula, um registro por linha.

Exemplo de escrita:

In [ ]:
import csv

# Dados
dt = (('temperatura', 15.0, 'C', '10:40', '2006-12-31'),
    ('peso', 42.5, 'kg', '10:45', '2006-12-31'))

# A rotina de escrita recebe um objeto do tipo file
out = csv.writer(file('dt.csv', 'w'))

# Escrevendo as tuplas no arquivo
out.writerows(dt)

Exemplo de leitura:

In [13]:
import csv

# A rotina de leitura recebe um objeto arquivo
dt = csv.reader(file('dt.csv'))

# Para cada registro do arquivo, imprima
for reg in dt:
    print reg
['temperatura', '15.0', 'C', '10:40', '2006-12-31']
['peso', '42.5', 'kg', '10:45', '2006-12-31']

O formato CSV é aceito pela maioria das planilhas e sistemas de banco de dados para importação e exportação de informações.

Sistema operacional

Além do sistema de arquivos, os módulos da biblioteca padrão também fornecem acesso a outros serviços providos pelo sistema operacional.

Exemplo:

In [5]:
import os
import sys
import platform

def uid():
    """
    uid() -> retorna a identificação do usuário
    corrente ou None se não for possível identificar
    """

    # Variáveis de ambiente para cada
    # sistema operacional
    us = {'Windows': 'USERNAME',
        'Linux': 'USER'}

    u = us.get(platform.system())
    return os.environ.get(u)

print 'Usuário:', uid()
print 'plataforma:', platform.platform()
print 'Diretório corrente:', os.path.abspath(os.curdir)
exep, exef = os.path.split(sys.executable)
print 'Executável:', exef
print 'Diretório do executável:', exep
Usuário: lslf
plataforma: Linux-3.8.0-26-generic-x86_64-with-Ubuntu-13.04-raring
Diretório corrente: /home/lslf/projetos/github/python-para-desenvolvedores/Capitulo11
Executável: python
Diretório do executável: /usr/bin

Exemplo de execução de processo:

In [ ]:
import sys
from subprocess import Popen, PIPE

# ping
cmd = 'ping -c 1 '
# No Windows
if sys.platform == 'win32':
    cmd = 'ping -n 1 '

# Local só para testar
host = '127.0.0.1'

# Comunicação com outro processo,
# um pipe com o stdout do comando
py = Popen(cmd + host, stdout=PIPE)

# Mostra a saída do comando
print py.stdout.read()

O módulo subprocess provê uma forma genérica de execução de processos, na função Popen(), que permite a comunicação com o processo através pipes do sistema operacional.

Tempo

O Python possui dois módulos para lidar com tempo:

  • time: implementa funções que permitem utilizar o tempo gerado pelo sistema.
  • datetime: implementa tipos de alto nível para realizar operações de data e hora.

Exemplo com time:

In [5]:
import time

# localtime() Retorna a data e hora local no formato
# de uma estrutura chamada struct_time, que é uma
# coleção com os itens: ano, mês, dia, hora, minuto,
# segundo, dia da semana, dia do ano e horário de verão
print time.localtime()

# asctime() retorna a data e hora como string, conforme
# a configuração do sistema operacional
print time.asctime()

# time() retorna o tempo do sistema em segundos
ts1 = time.time()

# gmtime() converte segundos para struct_time
tt1 = time.gmtime(ts1)
print ts1, '->', tt1

# Somando uma hora
tt2 = time.gmtime(ts1 + 3600.)

# mktime() converte struct_time para segundos
ts2 = time.mktime(tt2)
print ts2, '->', tt2

# clock() retorma o tempo desde quando o programa
# iniciou, em segundos
print 'O programa levou', time.clock(), \
    'segundos até agora...'

# Contando os segundos...
for i in xrange(5):

    # sleep() espera durante o número de segundos
    # especificados como parâmetro
    time.sleep(1)
    print i + 1, 'segundo(s)'
time.struct_time(tm_year=2013, tm_mon=7, tm_mday=19, tm_hour=14, tm_min=36, tm_sec=13, tm_wday=4, tm_yday=200, tm_isdst=0)
Fri Jul 19 14:36:13 2013
1374255373.26 -> time.struct_time(tm_year=2013, tm_mon=7, tm_mday=19, tm_hour=17, tm_min=36, tm_sec=13, tm_wday=4, tm_yday=200, tm_isdst=0)
1374269773.0 -> time.struct_time(tm_year=2013, tm_mon=7, tm_mday=19, tm_hour=18, tm_min=36, tm_sec=13, tm_wday=4, tm_yday=200, tm_isdst=0)
O programa levou 0.48 segundos até agora...
1 segundo(s)
2 segundo(s)
3 segundo(s)
4 segundo(s)
5 segundo(s)

Em datetime, estão definidos quatro tipos para representar o tempo:

  • datetime: data e hora.
  • date: apenas data.
  • time: apenas hora.
  • timedelta: diferença entre tempos.

Exemplo:

In [6]:
import datetime

# datetime() recebe como parâmetros:
# ano, mês, dia, hora, minuto, segundo
# e retorna um objeto do tipo datetime
dt = datetime.datetime(2020, 12, 31, 23, 59, 59)

# Objetos date e time podem ser criados
# a partir de um objeto datetime
data = dt.date()
hora = dt.time()

# Quanto tempo falta para 31/12/2020
dd = dt - dt.today()

print 'Data:', data
print 'Hora:', hora
print 'Quanto tempo falta para 31/12/2020:', \
    str(dd).replace('days', 'dias')
Data: 2020-12-31
Hora: 23:59:59
Quanto tempo falta para 31/12/2020: 2722 dias, 9:23:31.736243

Os objetos dos tipos date e datetime retornam datas em formato ISO.

Expressões regulares

Expressão regular é uma maneira de identificar padrões em sequências de caracteres. No Python, o módulo re provê um analisador sintático que permite o uso de tais expressões. Os padrões definidos através de caracteres que tem significado especial para o analisador.

Principais caracteres:

  • Ponto (.): Em modo padrão, significa qualquer caractere, menos o de nova linha.
  • Circunflexo (^): Em modo padrão, significa inicio da string.
  • Cifrão ($): Em modo padrão, significa fim da string.
  • Contra-barra (\): Caractere de escape, permite usar caracteres especiais como se fossem comuns.
  • Colchetes ([]): Qualquer caractere dos listados entre os colchetes.
  • Asterisco (*): Zero ou mais ocorrências da expressão anterior.
  • Mais (+): Uma ou mais ocorrências da expressão anterior.
  • Interrogação (?): Zero ou uma ocorrência da expressão anterior.
  • Chaves ({n}): n ocorrências da expressão anterior.
  • Barra vertical (|): “ou” lógico.
  • Parenteses (()): Delimitam um grupo de expressões.
  • \d: Dígito. Equivale a [0-9].
  • \D: Não dígito. Equivale a [^0-9].
  • \s: Qualquer caractere de espaçamento ([ \t\n\r\f\v]).
  • \S: Qualquer caractere que não seja de espaçamento.([^ \t\n\r\f\v]).
  • \w: Caractere alfanumérico ou sublinhado ([a-zA-Z0-9_]).
  • \W: Caractere que não seja alfanumérico ou sublinhado ([^a-zA-Z0-9_]).

Exemplos:

In [7]:
import re

# Compilando a expressão regular
# Usando compile() a expressão regular fica compilada
# e pode ser usada mais de uma vez
rex = re.compile('\w+')

# Encontra todas as ocorrências que atendam a expressão
bandas = 'Yes, Genesis & Camel'
print bandas, '->', rex.findall(bandas)

# Identifica as ocorrências de Björk (e suas variações)
bjork = re.compile('[Bb]j[öo]rk')
for m in ('Björk', 'björk', 'Biork', 'Bjork', 'bjork'):

    # match() localiza ocorrências no inicio da string
    # para localizar em qualquer parte da string, use search()
    print m, '->', bool(bjork.match(m))

# Substituindo texto
texto = 'A próxima faixa é Stairway to Heaven'
print texto, '->', re. sub('[Ss]tairway [Tt]o [Hh]eaven',
    'The Rover', texto)

# Dividindo texto
bandas = 'Tool, Porcupine Tree e NIN'
print bandas, '->', re.split(',?\s+e?\s+', bandas)
Yes, Genesis & Camel -> ['Yes', 'Genesis', 'Camel']
Björk -> False
björk -> False
Biork -> False
Bjork -> True
bjork -> True
A próxima faixa é Stairway to Heaven -> A próxima faixa é The Rover
Tool, Porcupine Tree e NIN -> ['Tool, Porcupine Tree', 'NIN']

O comportamento das funções desse módulo pode ser alterado por opções, para tratar as strings como unicode, por exemplo.

In [1]:
 
Out[1]: