Uma Revisão dos Fundamentos de Módulos

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Neste laboratório, você aprenderá os fundamentos dos módulos Python. Módulos são arquivos Python com definições de funções, classes e variáveis que podem ser usados em outros programas Python. Eles ajudam a organizar o código em unidades lógicas e aprimoram a reutilização.

Ao final deste laboratório, você entenderá como criar seus próprios módulos, importá-los de várias maneiras e compreender os comportamentos importantes de carregamento de módulos que impactam seu código.

Criando um Módulo Simples

Vamos começar nossa jornada nos módulos Python criando um simples. Em Python, um módulo é essencialmente um arquivo com a extensão .py que contém código Python. Pense nele como um contêiner onde você pode agrupar funções, classes e variáveis relacionadas. Isso torna seu código mais organizado e fácil de gerenciar, especialmente à medida que seus projetos crescem em tamanho.

  1. Primeiro, abra o WebIDE. Depois de aberto, você precisará criar um novo arquivo. Para fazer isso, clique em "File" na barra de menu e selecione "New File". Nomeie este novo arquivo simplemod.py e salve-o no diretório /home/labex/project. Este diretório é onde manteremos todos os arquivos relacionados a este experimento.

  2. Agora, vamos adicionar algum código ao nosso arquivo simplemod.py recém-criado. O código abaixo define alguns elementos básicos que você normalmente encontrará em um módulo Python.

## simplemod.py

x = 42        ## Uma variável global

## Uma função simples
def foo():
    print('x is', x)

## Uma classe simples
class Spam:
    def yow(self):
        print('Yow!')

## Uma instrução de script
print('Loaded simplemod')

Neste código:

  • x = 42 cria uma variável global chamada x e atribui a ela o valor 42. Variáveis globais podem ser acessadas de qualquer lugar dentro do módulo.
  • A função foo() é definida para imprimir o valor da variável global x. Funções são blocos de código reutilizáveis que executam uma tarefa específica.
  • A classe Spam é um modelo para criar objetos. Ele tem um método chamado yow(), que simplesmente imprime a string 'Yow!'. Métodos são funções que pertencem a uma classe.
  • A instrução print('Loaded simplemod') é uma instrução de script. Ela será executada assim que o módulo for carregado, o que nos ajuda a confirmar que o módulo foi carregado com sucesso.
  1. Depois de adicionar o código, salve o arquivo. Você pode fazer isso pressionando Ctrl+S no seu teclado ou selecionando "File" > "Save" no menu. Salvar o arquivo garante que todas as alterações que você fez sejam preservadas.

Vamos dar uma olhada mais de perto no que este módulo contém:

  • Uma variável global x com o valor 42. Esta variável pode ser usada em todo o módulo e até mesmo acessada de outros módulos se importada corretamente.
  • Uma função foo() que imprime o valor de x. Funções são úteis para executar tarefas repetitivas sem ter que escrever o mesmo código várias vezes.
  • Uma classe Spam com um método yow(). Classes e métodos são conceitos fundamentais na programação orientada a objetos (object-oriented programming), que permite criar estruturas de dados e comportamentos complexos.
  • Uma instrução print que é executada quando o módulo é carregado. Esta instrução serve como um indicador visual de que o módulo foi carregado com sucesso no ambiente Python.

A instrução print na parte inferior nos ajudará a observar quando o módulo é carregado, o que é importante para depurar e entender como os módulos funcionam em Python.

Importando e Usando Módulos

Agora que criamos um módulo, é hora de entender como importá-lo e usar seus componentes. Em Python, um módulo é um arquivo que contém definições e instruções Python. Quando você importa um módulo, você ganha acesso a todas as funções, classes e variáveis definidas nele. Isso permite que você reutilize código e organize seus programas de forma mais eficaz.

  1. Primeiro, precisamos abrir um novo terminal no WebIDE. Este terminal servirá como nosso espaço de trabalho onde podemos executar comandos Python. Para abrir um novo terminal, clique em "Terminal" > "New Terminal".

  2. Depois que o terminal estiver aberto, precisamos iniciar o interpretador Python. O interpretador Python é um programa que lê e executa código Python. Para iniciá-lo, digite o seguinte comando no terminal e pressione Enter:

python3
  1. Agora que o interpretador Python está em execução, podemos importar nosso módulo. Em Python, usamos a instrução import para trazer um módulo para nosso programa atual. Digite o seguinte comando no interpretador Python:
>>> import simplemod
Loaded simplemod

Você notará que "Loaded simplemod" aparece na saída. Isso ocorre porque a instrução print em nosso módulo simplemod é executada quando o módulo é carregado. Quando o Python importa um módulo, ele executa todo o código de nível superior nesse módulo, incluindo quaisquer instruções print.

  1. Depois de importar o módulo, podemos acessar seus componentes usando a notação de ponto. A notação de ponto é uma maneira de acessar atributos (variáveis e funções) de um objeto em Python. Neste caso, o módulo é um objeto, e suas funções, variáveis e classes são seus atributos. Aqui estão alguns exemplos de como acessar diferentes componentes do módulo simplemod:
>>> simplemod.x
42
>>> simplemod.foo()
x is 42
>>> spam_instance = simplemod.Spam()
>>> spam_instance.yow()
Yow!

Na primeira linha, acessamos a variável x definida no módulo simplemod. Na segunda linha, chamamos a função foo do módulo simplemod. Nas terceira e quarta linhas, criamos uma instância da classe Spam definida no módulo simplemod e chamamos seu método yow.

  1. Às vezes, você pode encontrar um ImportError ao tentar importar um módulo. Este erro ocorre quando o Python não consegue encontrar o módulo que você está tentando importar. Para descobrir onde o Python está procurando módulos, você pode examinar a variável sys.path. A variável sys.path é uma lista de diretórios que o Python pesquisa ao procurar módulos. Digite os seguintes comandos no interpretador Python:
>>> import sys
>>> sys.path
['', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/usr/local/lib/python3.10/dist-packages', '/usr/lib/python3/dist-packages']

O primeiro elemento da lista (a string vazia) representa o diretório de trabalho atual. É aqui que o Python procura o arquivo simplemod.py. Se seu módulo não estiver em um dos diretórios listados em sys.path, o Python não conseguirá encontrá-lo e você receberá um ImportError. Certifique-se de que seu arquivo simplemod.py esteja no diretório de trabalho atual ou em um dos outros diretórios em sys.path.

Compreendendo o Comportamento de Carregamento de Módulos

Em Python, a maneira como os módulos são carregados tem algumas características interessantes. Nesta etapa, exploraremos esses comportamentos para entender como o Python gerencia o carregamento de módulos.

  1. Primeiro, vamos ver o que acontece quando tentamos importar um módulo novamente dentro da mesma sessão do interpretador Python. Quando você inicia um interpretador Python, é como abrir um espaço de trabalho onde você pode executar código Python. Depois de importar um módulo, importá-lo novamente pode parecer que recarregaria o módulo, mas esse não é o caso.
>>> import simplemod

Observe que desta vez você não vê a saída "Loaded simplemod". Isso ocorre porque o Python carrega um módulo apenas uma vez por sessão do interpretador. Instruções import subsequentes não recarregam o módulo. O Python lembra que já carregou o módulo, então não passa pelo processo de carregá-lo novamente.

  1. Depois de importar um módulo, você pode modificar as variáveis dentro dele. Um módulo em Python é como um contêiner que contém variáveis, funções e classes. Depois de importar um módulo, você pode acessar e alterar suas variáveis como faria com qualquer outro objeto Python.
>>> simplemod.x
42
>>> simplemod.x = 13
>>> simplemod.x
13
>>> simplemod.foo()
x is 13

Aqui, primeiro verificamos o valor da variável x no módulo simplemod, que é inicialmente 42. Em seguida, alteramos seu valor para 13 e verificamos se a alteração foi feita. Quando chamamos a função foo no módulo, ela reflete o novo valor de x.

  1. Importar o módulo novamente não redefine as alterações que fizemos em suas variáveis. Mesmo que tentemos importar o módulo mais uma vez, o Python não o recarrega, então as alterações que fizemos em suas variáveis permanecem.
>>> import simplemod
>>> simplemod.x
13
  1. Se você quiser recarregar um módulo à força, precisará usar a função importlib.reload(). Às vezes, você pode ter feito alterações no código do módulo e deseja ver essas alterações entrarem em vigor imediatamente. A função importlib.reload() permite que você faça exatamente isso.
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>
>>> simplemod.x
42
>>> simplemod.foo()
x is 42

O módulo foi recarregado e o valor de x foi redefinido para 42. Isso mostra que o módulo foi carregado novamente a partir de seu código-fonte e todas as variáveis foram inicializadas como eram originalmente.

  1. O Python acompanha todos os módulos carregados no dicionário sys.modules. Este dicionário atua como um registro onde o Python armazena informações sobre todos os módulos que foram carregados durante a sessão atual do interpretador.
>>> 'simplemod' in sys.modules
True
>>> sys.modules['simplemod']
<module 'simplemod' from 'simplemod.py'>

Verificando se o nome de um módulo está no dicionário sys.modules, você pode ver se o módulo foi carregado. E acessando o dicionário com o nome do módulo como chave, você pode obter informações sobre o módulo.

  1. Você pode remover um módulo deste dicionário para forçar o Python a recarregá-lo na próxima importação. Se você remover um módulo do dicionário sys.modules, o Python esquece que já carregou o módulo. Portanto, da próxima vez que você tentar importá-lo, o Python o carregará novamente a partir de seu código-fonte.
>>> del sys.modules['simplemod']
>>> import simplemod
Loaded simplemod
>>> simplemod.x
42

O módulo foi carregado novamente porque foi removido de sys.modules. Esta é outra maneira de garantir que você está trabalhando com a versão mais recente do código de um módulo.

Usando a Sintaxe from module import

Em Python, existem várias maneiras de importar componentes de módulos. Uma dessas maneiras é a sintaxe from module import, que exploraremos nesta seção.

Ao importar componentes de um módulo, geralmente é uma boa ideia começar com uma tela limpa. Isso garante que não haja variáveis ou configurações residuais de interações anteriores que possam interferir em nosso experimento atual.

  1. Reinicie o interpretador Python para obter um estado limpo:
>>> exit()

Este comando sai da sessão atual do interpretador Python. Depois de sair, iniciaremos uma nova sessão para garantir um ambiente limpo.

python3

Este comando bash inicia uma nova sessão do interpretador Python 3. Agora que temos um ambiente Python limpo, podemos começar a importar componentes de um módulo.

  1. Importe componentes específicos de um módulo usando a sintaxe from module import:
>>> from simplemod import foo
Loaded simplemod
>>> foo()
x is 42

Aqui, estamos usando a instrução from simplemod import foo para importar apenas a função foo do módulo simplemod. Observe que, embora tenhamos solicitado apenas a função foo, todo o módulo simplemod foi carregado. Isso é indicado pela saída "Loaded simplemod". A razão para isso é que o Python precisa carregar todo o módulo para acessar a função foo.

  1. Ao usar from module import, você não pode acessar o próprio módulo:
>>> simplemod.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'simplemod' is not defined

Quando usamos a sintaxe from module import, estamos apenas trazendo os componentes especificados diretamente para nosso namespace. O próprio nome do módulo não é importado. Portanto, quando tentamos acessar simplemod.foo(), o Python não reconhece simplemod porque ele não foi importado dessa maneira.

  1. Você pode importar vários componentes de uma vez:
>>> from simplemod import x, foo
>>> x
42
>>> foo()
x is 42

A sintaxe from module import nos permite importar vários componentes de um módulo em uma única instrução. Aqui, estamos importando a variável x e a função foo do módulo simplemod. Após a importação, podemos acessar diretamente esses componentes em nosso código.

  1. Ao importar uma variável de um módulo, você está criando uma nova referência ao objeto, não um link para a variável no módulo:
>>> x = 13  ## Change the local variable x
>>> x
13
>>> foo()
x is 42  ## The function still uses the module's x, not your local x

Quando importamos uma variável de um módulo, estamos essencialmente criando uma nova referência ao mesmo objeto em nosso namespace local. Portanto, quando alteramos a variável local x para 13, isso não afeta a variável x dentro do módulo simplemod. A função foo() ainda se refere à variável x do módulo, que é 42. Entender esse conceito é crucial para evitar confusão em seu código.

Explorando as Limitações do Recarregamento de Módulos

O recarregamento de módulos é um recurso útil em Python, mas ele vem com algumas limitações, especialmente ao lidar com classes. Nesta seção, exploraremos essas limitações passo a passo. Compreender essas limitações é crucial tanto para ambientes de desenvolvimento quanto para ambientes de produção.

  1. Reinicie o interpretador Python:
    Primeiro, precisamos reiniciar o interpretador Python. Esta etapa é importante porque garante que comecemos com uma tela limpa. Quando você reinicia o interpretador, todos os módulos e variáveis importados anteriormente são limpos. Para sair do interpretador Python atual, use o comando exit(). Em seguida, inicie uma nova sessão do interpretador Python usando o comando python3 no terminal.
>>> exit()
python3
  1. Importe o módulo e crie uma instância da classe Spam:
    Agora que temos uma nova sessão do interpretador Python, importaremos o módulo simplemod. Importar um módulo nos permite usar as classes, funções e variáveis definidas nesse módulo. Após importar o módulo, criaremos uma instância da classe Spam e chamaremos seu método yow(). Isso nos ajudará a ver o comportamento inicial da classe.
>>> import simplemod
Loaded simplemod
>>> s = simplemod.Spam()
>>> s.yow()
Yow!
  1. Agora vamos modificar a classe Spam em nosso módulo. Saia do interpretador Python:
    Em seguida, faremos alterações na classe Spam no módulo simplemod. Antes de fazermos isso, precisamos sair do interpretador Python. Isso ocorre porque queremos fazer alterações no código-fonte do módulo e, em seguida, ver como essas alterações afetam o comportamento da classe.
>>> exit()
  1. Abra o arquivo simplemod.py no WebIDE e modifique a classe Spam:
    Abra o arquivo simplemod.py no WebIDE. É aqui que o código-fonte do módulo simplemod está localizado. Modificaremos o método yow() da classe Spam para imprimir uma mensagem diferente. Essa alteração nos ajudará a observar como o comportamento da classe muda após o recarregamento do módulo.
## simplemod.py
## ... (leave the rest of the file unchanged)

class Spam:
    def yow(self):
        print('More Yow!')  ## Changed from 'Yow!'
  1. Salve o arquivo e retorne ao terminal. Inicie o interpretador Python e crie uma nova instância:
    Depois de fazer as alterações no arquivo simplemod.py, salve-o. Em seguida, retorne ao terminal e inicie uma nova sessão do interpretador Python. Importe o módulo simplemod novamente e crie uma nova instância da classe Spam. Chame o método yow() da nova instância para ver o comportamento atualizado.
python3
>>> import simplemod
Loaded simplemod
>>> t = simplemod.Spam()
>>> t.yow()
More Yow!
  1. Agora vamos demonstrar o que acontece com o recarregamento:
    Para ver como o recarregamento de módulos funciona, usaremos a função importlib.reload(). Essa função nos permite recarregar um módulo importado anteriormente. Após recarregar o módulo, veremos se as alterações que fizemos na classe Spam são refletidas.
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>
  1. Saia do Python, modifique o arquivo novamente e, em seguida, teste ambas as instâncias:
    Saia do interpretador Python mais uma vez. Em seguida, faça outra alteração na classe Spam no arquivo simplemod.py. Depois disso, testaremos as instâncias antigas e novas da classe Spam para ver como elas se comportam.
>>> exit()
  1. Atualize o arquivo simplemod.py:
    Abra o arquivo simplemod.py novamente e modifique o método yow() da classe Spam para imprimir uma mensagem diferente. Essa alteração nos ajudará a entender melhor as limitações do recarregamento de módulos.
## simplemod.py
## ... (leave the rest of the file unchanged)

class Spam:
    def yow(self):
        print('Even More Yow!')  ## Changed again
  1. Salve o arquivo e retorne ao terminal:
    Salve as alterações no arquivo simplemod.py e retorne ao terminal. Inicie uma nova sessão do interpretador Python, importe o módulo simplemod e crie uma nova instância da classe Spam. Chame o método yow() da nova instância para ver o comportamento atualizado.
python3
>>> import simplemod
Loaded simplemod
>>> s = simplemod.Spam()
>>> s.yow()
Even More Yow!

>>> ## Exit without closing Python, edit the file
  1. Sem fechar o Python, abra simplemod.py no WebIDE e altere-o:
    Sem fechar o interpretador Python, abra o arquivo simplemod.py no WebIDE e faça outra alteração no método yow() da classe Spam. Isso nos ajudará a ver como o comportamento das instâncias existentes e novas muda após o recarregamento do módulo.
## simplemod.py
## ... (leave the rest of the file unchanged)

class Spam:
    def yow(self):
        print('Super Yow!')  ## Changed one more time
  1. Salve o arquivo e volte para o interpretador Python:
    Salve as alterações no arquivo simplemod.py e volte para o interpretador Python. Recarregue o módulo simplemod usando a função importlib.reload(). Em seguida, teste as instâncias antigas e novas da classe Spam para ver como elas se comportam.
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>

>>> ## Try the old instance
>>> s.yow()
Even More Yow!  ## Still uses the old implementation

>>> ## Create a new instance
>>> t = simplemod.Spam()
>>> t.yow()
Super Yow!  ## Uses the new implementation

Observe que a instância antiga s ainda usa a implementação antiga, enquanto a nova instância t usa a nova implementação. Isso acontece porque o recarregamento de um módulo não atualiza as instâncias existentes de classes. Quando uma instância de classe é criada, ela armazena uma referência ao objeto da classe naquele momento. Recarregar o módulo cria um novo objeto de classe, mas as instâncias existentes ainda se referem ao objeto de classe antigo.

  1. Você também pode observar outros comportamentos incomuns:
    Podemos observar ainda mais as limitações do recarregamento de módulos usando a função isinstance(). Essa função verifica se um objeto é uma instância de uma classe específica. Após recarregar o módulo, veremos que a instância antiga s não é mais considerada uma instância da nova classe simplemod.Spam, enquanto a nova instância t é.
>>> isinstance(s, simplemod.Spam)
False
>>> isinstance(t, simplemod.Spam)
True

Isso indica que, após o recarregamento, simplemod.Spam se refere a um objeto de classe diferente daquele usado para criar s.

Essas limitações tornam o recarregamento de módulos útil principalmente para desenvolvimento e depuração, mas não recomendado para código de produção. Em um ambiente de produção, é importante garantir que todas as instâncias de uma classe usem a mesma implementação atualizada. O recarregamento de módulos pode levar a um comportamento inconsistente, o que pode ser difícil de depurar e manter.

Resumo

Neste laboratório, você aprendeu os fundamentos de como trabalhar com módulos em Python. Você aprendeu a criar um módulo Python como um arquivo .py com variáveis, funções e classes, e como importar módulos usando a instrução import. Você também entende que o Python carrega módulos apenas uma vez por sessão do interpretador e pode usar importlib.reload() para forçar o recarregamento.

Além disso, você explorou o dicionário sys.modules para rastrear módulos carregados, usou a sintaxe from module import para importar componentes específicos e compreendeu as limitações do recarregamento de módulos, especialmente com classes. Esses conceitos são a base para organizar o código Python em componentes reutilizáveis, que são essenciais para manter a estrutura do código e promover a reutilização em aplicações maiores.