Acesso a Atributos e Métodos Vinculados

Beginner

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

Introdução

Neste laboratório, você aprenderá sobre acesso a atributos em Python. Explorará como usar funções como getattr() e setattr() para manipular atributos de objetos de forma eficaz.

Adicionalmente, você experimentará com métodos vinculados (bound methods). O laboratório irá guiá-lo através desses conceitos, e você criará um arquivo chamado tableformat.py durante o processo.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível iniciante com uma taxa de conclusão de 100%. Recebeu uma taxa de avaliações positivas de 100% dos estudantes.

Compreendendo o Acesso a Atributos em Python

Em Python, objetos são um conceito fundamental. Eles podem armazenar dados em atributos, que são como contêineres nomeados para valores. Você pode pensar em atributos como variáveis que pertencem a um objeto. Existem várias maneiras de acessar esses atributos. O método mais direto e comumente usado é a notação de ponto (.). No entanto, Python também oferece funções específicas que lhe dão mais flexibilidade ao trabalhar com atributos.

A Notação de Ponto

Vamos começar criando um objeto Stock e ver como podemos manipular seus atributos usando a notação de ponto. A notação de ponto é uma maneira simples e intuitiva de acessar e modificar os atributos de um objeto.

Primeiro, abra um novo terminal e inicie o shell interativo do Python. É aqui que você pode escrever e executar código Python linha por linha.

## Abra um novo terminal e execute o shell interativo do Python
python3

## Importe a classe Stock do módulo stock
from stock import Stock

## Crie um objeto Stock
s = Stock('GOOG', 100, 490.1)

## Obtenha um atributo
print(s.name)    ## Output: 'GOOG'

## Defina um atributo
s.shares = 50
print(s.shares)  ## Output: 50

## Exclua um atributo
del s.shares
## Se tentarmos acessar s.shares agora, obteremos um AttributeError

No código acima, primeiro importamos a classe Stock do módulo stock. Em seguida, criamos uma instância da classe Stock chamada s. Para obter o valor do atributo name, usamos s.name. Para alterar o valor do atributo shares, simplesmente atribuímos um novo valor a s.shares. E se quisermos remover um atributo, usamos a palavra-chave del seguida pelo nome do atributo.

Funções de Acesso a Atributos

Python fornece quatro funções embutidas que são muito úteis para a manipulação de atributos. Essas funções dão a você mais controle ao trabalhar com atributos, especialmente quando você precisa manipulá-los dinamicamente.

  1. getattr() - Esta função é usada para obter o valor de um atributo.
  2. setattr() - Permite definir o valor de um atributo.
  3. delattr() - Você pode usar esta função para excluir um atributo.
  4. hasattr() - Esta função verifica se um atributo existe em um objeto.

Vamos ver como usar essas funções:

## Crie um novo objeto Stock
s = Stock('GOOG', 100, 490.1)

## Obtenha um atributo
print(getattr(s, 'name'))       ## Output: 'GOOG'

## Defina um atributo
setattr(s, 'shares', 50)
print(s.shares)                 ## Output: 50

## Verifique se um atributo existe
print(hasattr(s, 'name'))       ## Output: True
print(hasattr(s, 'symbol'))     ## Output: False

## Exclua um atributo
delattr(s, 'shares')
print(hasattr(s, 'shares'))     ## Output: False

Essas funções são particularmente úteis quando você precisa trabalhar com atributos dinamicamente. Em vez de usar nomes de atributos codificados (hard-coded), você pode usar nomes de variáveis. Por exemplo, se você tiver uma variável que armazena o nome de um atributo, poderá passar essa variável para essas funções para realizar operações no atributo correspondente. Isso lhe dá mais flexibilidade em seu código, especialmente ao lidar com diferentes objetos e atributos de uma forma mais dinâmica.

Usando getattr() para Processamento Genérico de Objetos

A função getattr() é uma ferramenta poderosa em Python que permite acessar atributos de um objeto de forma dinâmica. Isso é particularmente útil quando você deseja processar objetos de maneira genérica. Em vez de escrever código específico para um determinado tipo de objeto, você pode usar getattr() para trabalhar com qualquer objeto que tenha os atributos necessários. Essa flexibilidade torna seu código mais reutilizável e adaptável.

Processando Múltiplos Atributos

Vamos começar aprendendo como acessar múltiplos atributos de um objeto usando a função getattr(). Este é um cenário comum quando você precisa extrair informações específicas de um objeto.

Primeiro, abra um shell interativo do Python se você fechou o anterior. Você pode fazer isso executando o seguinte comando em seu terminal:

## Abra um shell interativo do Python se você fechou o anterior
python3

Em seguida, importaremos a classe Stock e criaremos um objeto Stock. A classe Stock representa uma ação com atributos como name, shares e price.

## Importe a classe Stock e crie um objeto stock
from stock import Stock
s = Stock('GOOG', 100, 490.1)

Agora, definiremos uma lista de nomes de atributos que queremos acessar. Essa lista nos ajudará a iterar sobre os atributos e imprimir seus valores.

## Defina uma lista de nomes de atributos
fields = ['name', 'shares', 'price']

Finalmente, usaremos um loop for para iterar sobre a lista de nomes de atributos e acessar cada atributo usando getattr(). Imprimiremos o nome do atributo e seu valor para cada iteração.

## Acesse cada atributo usando getattr()
for name in fields:
    print(f"{name}: {getattr(s, 'name')}" if name == 'name' else f"{name}: {getattr(s, name)}")

Quando você executar este código, verá a seguinte saída:

name: GOOG
shares: 100
price: 490.1

Essa saída mostra que fomos capazes de acessar e imprimir os valores de múltiplos atributos do objeto Stock usando a função getattr().

Valores Padrão com getattr()

A função getattr() também fornece um recurso útil: a capacidade de especificar um valor padrão se o atributo que você está tentando acessar não existir. Isso pode impedir que seu código levante um AttributeError e torná-lo mais robusto.

Vamos ver como isso funciona. Primeiro, tentaremos acessar um atributo que não existe no objeto Stock. Usaremos getattr() e forneceremos um valor padrão de 'N/A'.

## Tente acessar um atributo que não existe
print(getattr(s, 'symbol', 'N/A'))  ## Output: 'N/A'

Nesse caso, como o atributo symbol não existe no objeto Stock, getattr() retorna o valor padrão 'N/A'.

Agora, vamos comparar isso com o acesso a um atributo existente. Acessaremos o atributo name, que existe no objeto Stock.

## Compare com um atributo existente
print(getattr(s, 'name', 'N/A'))    ## Output: 'GOOG'

Aqui, getattr() retorna o valor real do atributo name, que é 'GOOG'.

Processando uma Coleção de Objetos

A função getattr() torna-se ainda mais poderosa quando você precisa processar uma coleção de objetos. Vamos ver como podemos usá-la para processar uma carteira de ações.

Primeiro, importaremos a função read_portfolio do módulo stock. Essa função lê uma carteira de ações de um arquivo CSV e retorna uma lista de objetos Stock.

## Importe a função de leitura da carteira
from stock import read_portfolio

Em seguida, usaremos a função read_portfolio para ler a carteira de um arquivo CSV chamado portfolio.csv.

## Leia a carteira do arquivo CSV
portfolio = read_portfolio('portfolio.csv')

Finalmente, usaremos um loop for para iterar sobre a lista de objetos Stock na carteira. Para cada ação, usaremos getattr() para acessar os atributos name e shares e imprimir seus valores.

## Imprima o nome e as ações de cada ação
for stock in portfolio:
    print(f"Stock: {getattr(stock, 'name')}, Shares: {getattr(stock, 'shares')}")

Essa abordagem torna seu código mais flexível porque você pode trabalhar com nomes de atributos como strings. Essas strings podem ser passadas como argumentos ou armazenadas em estruturas de dados, permitindo que você altere facilmente os atributos que deseja acessar sem modificar a lógica principal do seu código.

Criando um Formatador de Tabela Usando Acesso a Atributos

Em programação, o acesso a atributos é um conceito fundamental que nos permite interagir com as propriedades dos objetos. Agora, vamos colocar em prática o que aprendemos sobre acesso a atributos. Criaremos um utilitário útil: um formatador de tabela. Este formatador pegará uma coleção de objetos e os exibirá em um formato tabular, tornando os dados mais fáceis de ler e entender.

Criando o Módulo tableformat.py

Primeiro, precisamos criar um novo arquivo Python. Este arquivo conterá o código para o nosso formatador de tabela.

Para criar o arquivo, siga estas etapas:

  1. No WebIDE, clique no menu "File".
  2. No menu suspenso, selecione "New File".
  3. Salve o arquivo recém-criado como tableformat.py no diretório /home/labex/project/.

Agora que temos nosso arquivo, vamos escrever o código para a função print_table() dentro de tableformat.py. Esta função será responsável por formatar e imprimir nossos objetos em uma tabela.

def print_table(objects, fields):
    """
    Imprime uma coleção de objetos como uma tabela formatada.

    Args:
        objects: Uma sequência de objetos
        fields: Uma lista de nomes de atributos
    """
    ## Imprime o cabeçalho
    headers = fields
    for header in headers:
        print(f"{header:>10}", end=' ')
    print()

    ## Imprime a linha separadora
    for header in headers:
        print("-" * 10, end=' ')
    print()

    ## Imprime os dados
    for obj in objects:
        for field in fields:
            value = getattr(obj, field)
            print(f"{value:>10}", end=' ')
        print()

Vamos detalhar o que essa função faz:

  1. Ela recebe dois argumentos: uma sequência de objetos e uma lista de nomes de atributos. A sequência de objetos são os dados que queremos exibir, e a lista de nomes de atributos informa à função quais propriedades dos objetos mostrar.
  2. Ela imprime uma linha de cabeçalho. A linha de cabeçalho contém os nomes dos atributos nos quais estamos interessados.
  3. Ela imprime uma linha separadora. Essa linha ajuda a separar visualmente o cabeçalho dos dados.
  4. Para cada objeto na sequência, ela imprime o valor de cada atributo especificado. Ela usa a função getattr() para acessar o valor do atributo de cada objeto.

Agora, vamos testar nossa função print_table() para ver se ela funciona como esperado.

## Abra um shell interativo do Python
python3

## Importe nossos módulos
from stock import read_portfolio
import tableformat

## Leia os dados da carteira
portfolio = read_portfolio('portfolio.csv')

## Imprima a carteira como uma tabela com colunas de nome, ações e preço
tableformat.print_table(portfolio, ['name', 'shares', 'price'])

Quando você executar o código acima, deverá ver a seguinte saída:

      name     shares      price
---------- ---------- ----------
        AA        100       32.2
       IBM         50       91.1
       CAT        150      83.44
      MSFT        200      51.23
        GE         95      40.37
      MSFT         50       65.1
       IBM        100      70.44

Uma das grandes vantagens da nossa função print_table() é sua flexibilidade. Podemos alterar as colunas que são exibidas simplesmente alterando a lista fields.

## Mostre apenas ações e nome
tableformat.print_table(portfolio, ['shares', 'name'])

A execução deste código fornecerá a seguinte saída:

    shares       name
---------- ----------
       100         AA
        50        IBM
       150        CAT
       200       MSFT
        95         GE
        50       MSFT
       100        IBM

O poder dessa abordagem reside em sua generalidade. Podemos usar a mesma função print_table() para imprimir tabelas para qualquer tipo de objeto, desde que saibamos os nomes dos atributos que queremos exibir. Isso torna nosso formatador de tabela uma ferramenta muito útil em nosso kit de ferramentas de programação.

Compreendendo Métodos Vinculados em Python

Em Python, métodos são um tipo especial de atributos que você pode chamar. Quando você acessa um método através de um objeto, você está obtendo o que chamamos de "método vinculado" (bound method). Um método vinculado é essencialmente um método que está ligado a um objeto específico. Isso significa que ele tem acesso aos dados do objeto e pode operar sobre eles.

Acessando Métodos como Atributos

Vamos começar a explorar métodos vinculados usando nossa classe Stock. Primeiro, veremos como acessar um método como um atributo de um objeto.

## Abra um shell interativo do Python
python3

## Importe a classe Stock e crie um objeto stock
from stock import Stock
s = Stock('GOOG', 100, 490.10)

## Acesse o método cost sem chamá-lo
cost_method = s.cost
print(cost_method)  ## Output: <bound method Stock.cost of <stock.Stock object at 0x...>>

## Chame o método
result = cost_method()
print(result)  ## Output: 49010.0

## Você também pode fazer isso em uma etapa
print(s.cost())  ## Output: 49010.0

No código acima, primeiro importamos a classe Stock e criamos uma instância dela. Em seguida, acessamos o método cost do objeto s sem realmente chamá-lo. Isso nos dá um método vinculado. Quando chamamos este método vinculado, ele calcula o custo com base nos dados do objeto. Você também pode chamar diretamente o método no objeto em uma etapa.

Usando getattr() com Métodos

Outra maneira de acessar métodos é usando a função getattr(). Esta função permite que você obtenha um atributo de um objeto por seu nome.

## Obtenha o método cost usando getattr
cost_method = getattr(s, 'cost')
print(cost_method)  ## Output: <bound method Stock.cost of <stock.Stock object at 0x...>>

## Chame o método
result = cost_method()
print(result)  ## Output: 49010.0

## Obtenha e chame em uma etapa
result = getattr(s, 'cost')()
print(result)  ## Output: 49010.0

Aqui, usamos getattr() para obter o método cost do objeto s. Assim como antes, podemos chamar o método vinculado para obter o resultado. E você pode até obter e chamar o método em uma única linha.

O Método Vinculado e Seu Objeto

Um método vinculado sempre mantém uma referência ao objeto do qual foi acessado. Isso significa que, mesmo que você armazene o método em uma variável, ele ainda sabe a qual objeto pertence e pode acessar os dados do objeto.

## Armazene o método cost em uma variável
c = s.cost

## Chame o método
print(c())  ## Output: 49010.0

## Altere o estado do objeto
s.shares = 75

## Chame o método novamente - ele vê o estado atualizado
print(c())  ## Output: 36757.5

Neste exemplo, armazenamos o método cost em uma variável c. Quando chamamos c(), ele calcula o custo com base nos dados atuais do objeto. Em seguida, alteramos o atributo shares do objeto s. Quando chamamos c() novamente, ele usa os dados atualizados para calcular o novo custo.

Explorando os Interiores do Método Vinculado

Um método vinculado tem dois atributos importantes que nos dão mais informações sobre ele.

  • __self__: Este atributo se refere ao objeto ao qual o método está vinculado.
  • __func__: Este atributo é o objeto de função real que representa o método.
## Obtenha o método cost
c = s.cost

## Examine os atributos do método vinculado
print(c.__self__)  ## Output: <stock.Stock object at 0x...>
print(c.__func__)  ## Output: <function Stock.cost at 0x...>

## Você pode chamar manualmente a função com o objeto
print(c.__func__(c.__self__))  ## Output: 36757.5 (same as c())

Aqui, acessamos os atributos __self__ e __func__ do método vinculado c. Podemos ver que __self__ é o objeto s, e __func__ é a função cost. Podemos até mesmo chamar manualmente a função passando o objeto como um argumento, e isso nos dá o mesmo resultado que chamar o método vinculado diretamente.

Exemplo com um Método que Aceita Argumentos

Vamos ver como os métodos vinculados funcionam com um método que aceita argumentos, como o método sell().

## Obtenha o método sell
sell_method = s.sell

## Examine o método
print(sell_method)  ## Output: <bound method Stock.sell of <stock.Stock object at 0x...>>

## Chame o método com um argumento
sell_method(25)
print(s.shares)  ## Output: 50

## Chame o método manualmente usando __func__ e __self__
sell_method.__func__(sell_method.__self__, 10)
print(s.shares)  ## Output: 40

Neste exemplo, obtemos o método sell como um método vinculado. Quando o chamamos com um argumento, ele atualiza o atributo shares do objeto s. Também podemos chamar manualmente o método usando os atributos __func__ e __self__, passando o argumento também.

Compreender os métodos vinculados ajuda você a compreender como o sistema de objetos do Python funciona por dentro, o que pode ser útil para depuração, metaprogramação e criação de padrões de programação avançados.

Resumo

Neste laboratório, você aprendeu sobre o sistema de acesso a atributos do Python e seus mecanismos subjacentes. Agora você sabe como acessar atributos de objetos usando notação de ponto e funções como getattr(), setattr(), delattr() e hasattr(). Além disso, você entende como usar getattr() para processamento de objetos genérico e flexível e como criar um formatador de tabela para qualquer coleção de objetos.

Você também compreendeu o conceito de métodos vinculados e como eles mantêm uma conexão com seus objetos. Esses conceitos fundamentais são cruciais para técnicas avançadas de programação Python, como introspecção, reflexão e metaprogramação. Compreender o acesso a atributos permite que você escreva um código mais flexível e poderoso que pode lidar com vários tipos de objetos.