10. Um breve passeio pela biblioteca padrão

10.1. Interface com o sistema operacional

O módulo os fornece dúzias de funções para interagir com o sistema operacional:

>>> import os
>>> os.getcwd()      # Return the current working directory
'C:\\Python39'
>>> os.chdir('/server/accesslogs')   # Change current working directory
>>> os.system('mkdir today')   # Run the command mkdir in the system shell
0

Certifique-se de usar a forma import os ao invés de from os import *. Isso evitará que os.open() oculte a função open() que opera de forma muito diferente.

As funções embutidas dir() e help() são úteis como um sistema de ajuda interativa para lidar com módulos grandes como os:

>>> import os
>>> dir(os)
<returns a list of all module functions>
>>> help(os)
<returns an extensive manual page created from the module's docstrings>

Para tarefas de gerenciamento cotidiano de arquivos e diretórios, o módulo shutil fornece uma interface de alto nível que é mais simples de usar:

>>> import shutil
>>> shutil.copyfile('data.db', 'archive.db')
'archive.db'
>>> shutil.move('/build/executables', 'installdir')
'installdir'

10.2. Caracteres curinga

O módulo glob fornece uma função para criar listas de arquivos a partir de buscas em diretórios usando caracteres curinga:

>>> import glob
>>> glob.glob('*.py')
['primes.py', 'random.py', 'quote.py']

10.3. Argumentos de linha de comando

Scripts geralmente precisam processar argumentos passados na linha de comando. Esses argumentos são armazenados como uma lista no atributo argv do módulo sys. Por exemplo, teríamos a seguinte saída executando python demo.py one two three na linha de comando:

>>> import sys
>>> print(sys.argv)
['demo.py', 'one', 'two', 'three']

O módulo argparse fornece um mecanismo mais sofisticado para processar argumentos de linha de comando. O script seguinte extrai e exibe um ou mais nomes de arquivos e um número de linhas opcional:

import argparse

parser = argparse.ArgumentParser(
    prog='top',
    description='Show top lines from each file')
parser.add_argument('filenames', nargs='+')
parser.add_argument('-l', '--lines', type=int, default=10)
args = parser.parse_args()
print(args)

Quando executada a linha de comando python top.py --lines=5 alpha.txt beta.txt, o script define args.lines para 5 e args.filenames para ['alpha.txt', 'beta.txt'].

10.4. Redirecionamento de erros e encerramento do programa

O módulo sys também possui atributos para stdin, stdout e stderr. O último é usado para emitir avisos e mensagens de erros visíveis mesmo quando stdout foi redirecionado:

>>> sys.stderr.write('Warning, log file not found starting a new one\n')
Warning, log file not found starting a new one

A forma mais direta de encerrar um script é usando sys.exit().

10.5. Reconhecimento de padrões em strings

O módulo re fornece ferramentas para lidar com processamento de strings através de expressões regulares. Para reconhecimento de padrões complexos, expressões regulares oferecem uma solução sucinta e eficiente:

>>> import re
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'

Quando as exigências são simples, métodos de strings são preferíveis por serem mais fáceis de ler e depurar:

>>> 'tea for too'.replace('too', 'two')
'tea for two'

10.6. Matemática

O módulo math oferece acesso às funções da biblioteca C para matemática de ponto flutuante:

>>> import math
>>> math.cos(math.pi / 4)
0.70710678118654757
>>> math.log(1024, 2)
10.0

O módulo random fornece ferramentas para gerar seleções aleatórias:

>>> import random
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.sample(range(100), 10)   # sampling without replacement
[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
>>> random.random()    # random float
0.17970987693706186
>>> random.randrange(6)    # random integer chosen from range(6)
4

O módulo statistics calcula as propriedades estatísticas básicas (a média, a mediana, a variação, etc.) de dados numéricos:

>>> import statistics
>>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
>>> statistics.mean(data)
1.6071428571428572
>>> statistics.median(data)
1.25
>>> statistics.variance(data)
1.3720238095238095

O projeto SciPy <https://scipy.org> tem muitos outros módulos para cálculos numéricos.

10.7. Acesso à internet

Há diversos módulos para acesso e processamento de protocolos da internet. Dois dos mais simples são urllib.request para efetuar download de dados a partir de URLs e smtplib para enviar mensagens de correio eletrônico:

>>> from urllib.request import urlopen
>>> with urlopen('http://worldtimeapi.org/api/timezone/etc/UTC.txt') as response:
...     for line in response:
...         line = line.decode()             # Convert bytes to a str
...         if line.startswith('datetime'):
...             print(line.rstrip())         # Remove trailing newline
...
datetime: 2022-01-01T01:36:47.689215+00:00

>>> import smtplib
>>> server = smtplib.SMTP('localhost')
>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
... """To: jcaesar@example.org
... From: soothsayer@example.org
...
... Beware the Ides of March.
... """)
>>> server.quit()

(Note que o segundo exemplo precisa de um servidor de email rodando em localhost.)

10.8. Data e hora

O módulo datetime fornece classes para manipulação de datas e horas nas mais variadas formas. Apesar da disponibilidade de aritmética com data e hora, o foco da implementação é na extração eficiente dos membros para formatação e manipulação. O módulo também oferece objetos que levam os fusos horários em consideração.

>>> # dates are easily constructed and formatted
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2003, 12, 2)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

>>> # dates support calendar arithmetic
>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
14368

10.9. Compressão de dados

Formatos comuns de arquivamento e compressão de dados estão disponíveis diretamente através de alguns módulos, entre eles: zlib, gzip, bz2, lzma, zipfile and tarfile.

>>> import zlib
>>> s = b'witch which has which witches wrist watch'
>>> len(s)
41
>>> t = zlib.compress(s)
>>> len(t)
37
>>> zlib.decompress(t)
b'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979

10.10. Medição de desempenho

Alguns usuários de Python desenvolvem um interesse profundo pelo desempenho relativo de diferentes abordagens para o mesmo problema. Python oferece uma ferramenta de medição que esclarece essas dúvidas rapidamente.

Por exemplo, pode ser tentador usar o empacotamento e desempacotamento de tuplas ao invés da abordagem tradicional de permutar os argumentos. O módulo timeit rapidamente mostra uma modesta vantagem de desempenho:

>>> from timeit import Timer
>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.57535828626024577
>>> Timer('a,b = b,a', 'a=1; b=2').timeit()
0.54962537085770791

Em contraste com a granularidade fina do módulo timeit, os módulos profile e pstats oferecem ferramentas para identificar os trechos mais críticos em grandes blocos de código.

10.11. Controle de qualidade

Uma das abordagens usadas no desenvolvimento de software de alta qualidade é escrever testes para cada função à medida que é desenvolvida e executar esses testes frequentemente durante o processo de desenvolvimento.

O módulo doctest oferece uma ferramenta para realizar um trabalho de varredura e validação de testes escritos nas strings de documentação (docstrings) de um programa. A construção dos testes é tão simples quanto copiar uma chamada típica juntamente com seus resultados e colá-los na docstring. Isto aprimora a documentação, fornecendo ao usuário um exemplo real, e permite que o módulo doctest verifique se o código continua fiel à documentação:

def average(values):
    """Computes the arithmetic mean of a list of numbers.

    >>> print(average([20, 30, 70]))
    40.0
    """
    return sum(values) / len(values)

import doctest
doctest.testmod()   # automatically validate the embedded tests

O módulo unittest não é tão simples de usar quanto o módulo doctest, mas permite que um conjunto muito maior de testes seja mantido em um arquivo separado:

import unittest

class TestStatisticalFunctions(unittest.TestCase):

    def test_average(self):
        self.assertEqual(average([20, 30, 70]), 40.0)
        self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
        with self.assertRaises(ZeroDivisionError):
            average([])
        with self.assertRaises(TypeError):
            average(20, 30, 70)

unittest.main()  # Calling from the command line invokes all tests

10.12. Baterias incluídas

Python tem uma filosofia de “baterias incluídas”. Isso fica mais evidente através da sofisticação e robustez dos seus maiores pacotes. Por exemplo:

  • The xmlrpc.client and xmlrpc.server modules make implementing remote procedure calls into an almost trivial task. Despite the modules’ names, no direct knowledge or handling of XML is needed.

  • O pacote email é uma biblioteca para gerenciamento de mensagens de correio eletrônico, incluindo MIME e outros baseados no RFC 2822. Diferente dos módulos smtplib e poplib que apenas enviam e recebem mensagens, o pacote de email tem um conjunto completo de ferramentas para construir ou decodificar a estrutura de mensagens complexas (incluindo anexos) e para implementação de protocolos de codificação e cabeçalhos.

  • O pacote json oferece um suporte robusto para analisar este popular formato para troca de dados. O módulo csv oferece suporte para leitura e escrita direta em arquivos no formato Comma-Separated Value, comumente suportado por bancos de dados e planilhas. O processamento XML é fornecido pelos pacotes xml.etree.ElementTree, xml.dom e xml.sax. Juntos, esses módulos e pacotes simplificam muito a troca de informações entre aplicativos Python e outras ferramentas.

  • O módulo sqlite3 é um wrapper para a biblioteca de banco de dados SQLite, fornecendo um banco de dados persistente que pode ser atualizado e acessado usando sintaxe SQL ligeiramente fora do padrão.

  • Internacionalização está disponível através de diversos módulos, como gettext, locale, e o pacote codecs.