5  Fundamentos de Python

Atenção!!!

A partir de agora, todo o código apresentado neste livro está na linguagem Python.

A fonte para a contrução deste material é McKinney (2022).

5.1 Instalação

Siga os passos abaixo para realizar a instalação do Anaconda e do JupyterLab:

  1. Baixe e instale o Anaconda a partir do site oficial. Siga as instruções de instalação para o seu sistema operacional específico.

  2. Após instalar o Anaconda, abra o Anaconda Navigator e crie um novo ambiente virtual. Navegue até a seção “Environments” e clique em “Create” para adicionar um novo ambiente. Dê um nome ao ambiente e escolha a versão do Python que deseja usar.

  3. Após criar o ambiente virtual, ative-o clicando no ambiente virtual recém-criado na lista de ambientes e selecionando “Open Terminal”. No terminal, digite o comando conda activate nome_do_seu_ambiente (substitua nome_do_seu_ambiente pelo nome do ambiente que você criou).

  4. Com o ambiente virtual ativado, instale o JupyterLab digitando conda install jupyterlab no terminal.

  5. Depois de instalar o JupyterLab, execute-o digitando jupyter lab no terminal ou através da interface do Anaconda. Isso abrirá o JupyterLab no seu navegador padrão.

  6. No JupyterLab, você pode criar um novo notebook Python clicando no ícone “+” na barra lateral esquerda e selecionando “Python 3” sob o cabeçalho “Notebook”.

5.2 Tipos de dados fundamentais

Em Python, os tipos de dados fundamentais incluem integer, float, string e boolean:

  • Integers são números inteiros, como 1, 2, -3, etc. - Floats são números decimais, como 3.14, -0.5, etc.
  • Strings são sequências de caracteres, como “hello”, “world”, “python”, etc.
  • Booleans são valores lógicos que representam verdadeiro (True) ou falso (False).

Esses tipos de dados são os blocos básicos para representar diferentes tipos de informações em Python, e são amplamente utilizados em programação para realizar operações e manipulações de dados.

5.2.1 O tipo de dado inteiro

Um tipo de dados inteiro (integer) em Python representa números inteiros, ou seja, números sem casas decimais. Por exemplo, 5, -10 e 0 são todos exemplos de números inteiros. No Python, os inteiros são representados pela classe int. Nos exemplos abaixo realizamos operações básicas com números inteiros.

2 + 2  
4

Na primeira linha, calculamos a soma de 2 com 2.

quantidade = 200
print(quantidade)
200
type(quantidade)
<class 'int'>

Acima, atribuímos o valor 200 à variável quantidade e a imprimimos usando print(quantidade). Por fim, verificamos o tipo de dado da variável quantidade com type(quantidade), que retorna <class 'int'>, indicando que é um número inteiro.

5.2.2 O tipo de dado ponto flutuante

Um tipo de dado ponto flutuante (float) em Python representa números decimais, ou seja, números que podem ter uma parte fracionária. Por exemplo, 3.14, -0.001, e 2.71828 são todos floats. Em Python, os floats são representados pela classe float.

1.75 + 2**3 
9.75
taxa_juros = 1.25

print(taxa_juros)
1.25
type(taxa_juros)
<class 'float'>

Na primeira linha do exemplo acima, calculamos a soma de 1.75 com 2 elevado à terceira potência. Em seguida, atribuímos o valor 1.25 à variável taxa_juros e a imprimimos usando print(taxa_juros). Por fim, verificamos o tipo de dado da variável taxa_juros com type(taxa_juros), que retorna <class 'float'>, indicando que é um número do tipo ponto flutuante.

5.2.3 O tipo de dado cadeia de caracteres

pais = "Brasil" 

print(pais)
Brasil
type(pais)
<class 'str'>

No código acima, criamos uma variável chamada pais e atribuímos a ela o valor “Brasil”, que é uma string. Em seguida, imprimimos o valor da variável pais usando print(pais), o que exibe “Brasil” na tela. Por fim, verificamos o tipo de dado da variável pais com type(pais), que retorna <class 'str'>, indicando que é uma string.

5.2.4 O tipo de dado lógico

O tipo de dados lógico, também conhecido como booleano (bool), é usado para representar valores de verdadeiro ou falso. No Python, os valores booleanos são True e False, que representam verdadeiro e falso, respectivamente.

1 == 2
False
5 % 2 == 0
False
taxa_juros_aumentando = True
print(taxa_juros_aumentando)
True
type(taxa_juros_aumentando)
<class 'bool'>

Na primeira linha do exemplo acima, há uma verificação de igualdade entre 1 e 2, que retorna False porque 1 não é igual a 2. Em seguida, temos 5 % 2 == 0, que também retorna False porque o resto da divisão de 5 por 2 não é igual a zero. Por fim, temos a variável taxa_juros_aumentando atribuída a True, indicando que a taxa de juros está aumentando. Ao imprimir e verificar o tipo dessa variável, obtemos True como resultado e o tipo bool, indicando que é um valor lógico.

5.2.5 Coerção de tipos

A coerção de dados em Python refere-se à conversão forçada de um tipo de dado para outro.

str_num = "1.41"
type(str_num)
<class 'str'>
float(str_num)
1.41

Veja que a variável str_num é uma string que representa o número 1.41. Inicialmente, seu tipo é verificado usando a função type, que retorna <class 'str'>, indicando que é uma string. Em seguida, usamos a função float() para converter explicitamente str_num em um float. Após a conversão, o valor de str_num é “1.41” e seu tipo é alterado para <class 'float'>.

A seguir, outros exemplos de cooerção.

Coerção para inteiro:

num_float = 3.14
num_int = int(num_float)
print(num_int)
3

Coerção para lógico:

valor_inteiro = 0
valor_logico = bool(valor_inteiro)
print(valor_logico)
False

Coerção para string (str):

num_float = 3.14
num_str = str(num_float)
print(num_str) 
3.14

No código acima, estamos convertendo um valor float em string.

5.3 Objetos básicos

Em Python, há três estruturas de dados básicas: listas, tuplas e dicionários:

  • As listas são coleções ordenadas e mutáveis de elementos, permitindo a inclusão de itens de diferentes tipos e a modificação dos valores contidos nelas.
  • As tuplas são semelhantes às listas, porém são imutáveis, ou seja, não podem ser alteradas após a sua criação.
  • Já os dicionários são coleções não ordenadas de pares chave-valor, onde cada valor é associado a uma chave única, proporcionando acesso eficiente aos dados por meio das chaves.

5.3.1 Listas

Em Python, uma lista é uma estrutura de dados que permite armazenar uma coleção ordenada de elementos. Para criar uma lista, utilizamos colchetes [], e os elementos são separados por vírgulas. Podemos instanciar uma lista vazia simplesmente utilizando [] ou a função list(). Por exemplo:

lista_vazia = [] # Lista vazia
lista_vazia = list() # alternativa

# lista com PIB de paises
pib_paises = [1800, 2500, 3200, 5600, 6700]

No exemplo acima, também temos a lista pib_paises que armazena o Produto Interno Bruto (PIB) de diferentes países. Para acessar elementos de uma lista em Python, podemos utilizar o índice do elemento desejado dentro de colchetes []. O índice começa do zero para o primeiro elemento, um para o segundo, e assim por diante. Por exemplo:

print(pib_paises[1])
2500

Também podemos acessar os elementos a partir do final da lista utilizando índices negativos, onde -1 representa o último elemento, -2 o penúltimo, e assim por diante:

# Acessando o último elemento
ultimo_elemento = pib_paises[-1]
print(ultimo_elemento)
6700
# Acessando o penúltimo elemento
penultimo_elemento = pib_paises[-2]
print(penultimo_elemento)
5600

Podemos usar o método append()se desejamos adicionar um elemento ao final da lista, ou o método insert() se queremos adicionar um elemento em uma posição específica. Veja os exemplos de como usar ambos os métodos:

# Adicionando elementos ao final da lista usando append()
pib_paises.append(2000)  # Adiciona o valor 2000 ao final da lista

# Adicionando um elemento em uma posição específica usando insert()
pib_paises.insert(1, 1500)  # Adiciona o valor 1500 na posição 1 da lista

Para verificar o tamanho de uma lista em Python, podemos usar a função len().

tamanho_lista = len(pib_paises)
print("Tamanho da lista:", tamanho_lista) 
Tamanho da lista: 7

Para ordenar uma lista, podemos usar o método sort() para ordenação in-place (ou seja, a lista é modificada) ou a função sorted() para retornar uma nova lista ordenada sem modificar a original:

# Usando a função sorted() para retornar uma nova lista ordenada
lista_ordenada = sorted(pib_paises)
print("Nova lista ordenada:", lista_ordenada)
Nova lista ordenada: [1500, 1800, 2000, 2500, 3200, 5600, 6700]
# Ordenando a lista usando o método sort()
pib_paises.sort()
print("Lista ordenada:", pib_paises)
Lista ordenada: [1500, 1800, 2000, 2500, 3200, 5600, 6700]

O método .pop() é usado para remover e retornar o último elemento de uma lista. Também podemos especificar um índice para remover e retornar um elemento em uma posição específica da lista. Aqui está como usar o método .pop():

# Removendo e retornando o último PIB da lista
ultimo_pib = pib_paises.pop()
print("Último PIB removido:", ultimo_pib) 
Último PIB removido: 6700
print("Lista atualizada:", pib_paises)
Lista atualizada: [1500, 1800, 2000, 2500, 3200, 5600]
# Removendo e retornando o PIB de um país específico da lista
pib_removido = pib_paises.pop(1) 
print("PIB removido:", pib_removido) 
PIB removido: 1800
print("Lista atualizada:", pib_paises)
Lista atualizada: [1500, 2000, 2500, 3200, 5600]

5.3.2 Tuplas

As tuplas são estruturas de dados semelhantes às listas, mas com uma diferença fundamental: elas são imutáveis, ou seja, uma vez criadas, não podem ser modificadas. Elas são representadas por parênteses () em vez de colchetes [].

x = (1, 2, 3) # tupla (lista imutável)
print(x)
(1, 2, 3)

# x[0] = 5 # gera erro!

Podemos usar tuplas para representar informações que não devem ser alteradas, como por exemplo, as taxas de câmbio entre moedas. Veja:

taxas_cambio = (("USD", "EUR", 0.82), ("USD", "JPY", 105.42), ("EUR", "JPY", 128.64))

Neste exemplo, temos uma tupla de tuplas que representam as taxas de câmbio entre o dólar (USD), o euro (EUR) e o iene japonês (JPY) para uma data fixa fictícia. Cada tupla interna contém três elementos: a moeda de origem, a moeda de destino e a taxa de câmbio. Como essas informações não devem ser alteradas, uma tupla é uma escolha apropriada.

Dica

Para acessar os elementos de uma tupla, você pode usar a mesma sintaxe que usa para acessar os elementos de uma lista, ou seja, usando colchetes [] e o índice do elemento desejado. Lembre-se de que os índices em Python começam em 0!

5.3.3 Dicionários

Dicionários em Python são estruturas de dados que permitem armazenar pares de chave-valor. Cada valor é associado a uma chave específica, permitindo o acesso rápido aos dados por meio das chaves, em vez de índices numéricos, como em listas e tuplas. Essa estrutura é útil quando você precisa associar informações de maneira semelhante a um banco de dados, onde você pode buscar informações com base em uma chave específica.

No exemplo abaixo, temos cotações de ações de algumas empresas brasileiras listadas na bolsa de valores.

cotacoes_acoes_brasileiras = {
    "PETR4": 36.75,
    "VALE3": 62.40,
    "ITUB4": 34.15,
    "BBDC4": 13.82
}

Cada chave é o código de negociação da ação na bolsa, e o valor associado é o preço da ação em uma data fixada. Por exemplo, cotacoes_acoes_brasileiras["PETR4"] retornaria o preço da ação da Petrobras.

Alternativamente, você pode criar um dicionário usando a função dict:

cotacoes_acoes_brasileiras = dict(PETR4=36.12, VALE3=62.40, ITUB4=34.15, BBDC4=13.82)

Você pode adicionar novos pares chave-valor a um dicionário ou atualizar os valores existentes. Por exemplo:

cotacoes_acoes_brasileiras["ABEV3"] = 12.80
cotacoes_acoes_brasileiras["PETR4"] = 36.75

Você pode remover pares chave-valor de um dicionário usando o comando método pop(). Por exemplo:

valor_removido = cotacoes_acoes_brasileiras.pop("BBDC4")

Outros métodos úteis para trabalhar com dicionários são keys(), values() e items() que retornam listas com as chaves, valores e itens do dicionário, respectivamente.

cotacoes_acoes_brasileiras.keys() # retorna uma lista contendo todas as chaves
dict_keys(['PETR4', 'VALE3', 'ITUB4', 'ABEV3'])
cotacoes_acoes_brasileiras.values() # retorna uma lista contendo todos os valores
dict_values([36.75, 62.4, 34.15, 12.8])
cotacoes_acoes_brasileiras.items() # retorna uma lista de tuplas
dict_items([('PETR4', 36.75), ('VALE3', 62.4), ('ITUB4', 34.15), ('ABEV3', 12.8)])

5.4 Fatias (slices)

O conceito de fatias, também conhecido como “slicing” em inglês, refere-se à técnica de extrair partes específicas de uma sequência, como uma lista, tupla ou string, usando índices. Ao utilizar fatias, você pode selecionar um intervalo de elementos dentro da sequência.

A sintaxe básica para fatias é sequencia[inicio:fim:passo], onde:

  • inicio: o índice inicial do intervalo a ser incluído na fatia (incluído).

  • fim: o índice final do intervalo a ser incluído na fatia (excluído).

  • passo: o tamanho do passo entre os elementos selecionados (opcional).

Considere a lista abaixo.

nomes_paises = ["Indonésia", "Índia", "Brasil", "África do Sul", "Alemanha"]

Para acessar os três primeiros países, podemos fazer:

nomes_paises[:3]
['Indonésia', 'Índia', 'Brasil']

Isso retorna os elementos da lista do índice 0 (inclusivo) ao índice 3 (exclusivo).

Se quisermos acessar os países do segundo ao terceiro:

nomes_paises[1:4]
['Índia', 'Brasil', 'África do Sul']

Podemos até mesmo fazer fatias reversas, onde o índice inicial é maior que o índice final, indicando que queremos percorrer a lista de trás para frente. Por exemplo, para acessar os últimos três países:

nomes_paises[-3:]
['Brasil', 'África do Sul', 'Alemanha']

Suponha que queremos acessar todos os países, mas pulando de dois em dois:

nomes_paises[::2]
['Indonésia', 'Brasil', 'Alemanha']

Neste exemplo, o ::2 indica que queremos começar do início da lista e ir até o final, pulando de dois em dois elementos.

5.5 Condicionais

O if e o else são estruturas de controle de fluxo em Python, usadas para tomar decisões com base em condições.

O bloco de código dentro do if é executado se a condição for avaliada como verdadeira (True). Por exemplo:

idade = 18
if idade >= 18:
    print("Você é maior de idade.")
Você é maior de idade.

O bloco de código dentro do else é executado se a condição do if for avaliada como falsa (False). Por exemplo:

idade = 16
if idade >= 18:
    print("Você é maior de idade.")
else:
    print("Você é menor de idade.")
Você é menor de idade.
Indentação

Em Python, a indentação é fundamental para definir blocos de código. No exemplo acima, observe que o código dentro do if e do else está indentado com quatro espaços. Isso indica que essas linhas pertencem ao bloco de código condicional. Se não houver indentação correta, o Python gerará um erro de sintaxe.

5.6 Estruturas repetitivas

As estruturas de repetição são utilizadas para executar um bloco de código repetidamente com base em uma condição específica. Existem duas principais estruturas de repetição em Python: for e while.

5.6.1 for

O loop for é utilizado para iterar sobre uma sequência (como uma lista, tupla, dicionário, etc.) e executar um bloco de código para cada item da sequência. Por exemplo:

for x in range(0, 20, 3): # lembre da notação dos slices
    print(x)
0
3
6
9
12
15
18
for pais in nomes_paises:
    print("País:", pais)
País: Indonésia
País: Índia
País: Brasil
País: África do Sul
País: Alemanha

No exemplo abaixo, temos uma lista de empresas e uma lista de lucros. Usando a função zip(), iteramos sobre essas duas listas em paralelo, imprimindo o nome da empresa e seu lucro correspondente. A função zip() combina elementos de duas ou mais sequências (como listas, tuplas, etc.) em pares ordenados.

empresas = ["Empresa A", "Empresa B", "Empresa C"]
lucros = [100000, 150000, 80000]

for empresa, lucro in zip(empresas, lucros):
    print("O lucro da empresa ", empresa, "foi R$", lucro)
O lucro da empresa  Empresa A foi R$ 100000
O lucro da empresa  Empresa B foi R$ 150000
O lucro da empresa  Empresa C foi R$ 80000

5.6.2 while

O while é uma estrutura de controle de fluxo que executa um bloco de código repetidamente enquanto uma condição especificada for verdadeira.

anos = 1
investimento = 1000
taxa_de_retorno = 0.05

while anos <= 10:
    investimento *= (1 + taxa_de_retorno)
    print("Após", anos, "anos, o investimento vale R$", round(investimento, 2))
    anos += 1
Após 1 anos, o investimento vale R$ 1050.0
Após 2 anos, o investimento vale R$ 1102.5
Após 3 anos, o investimento vale R$ 1157.62
Após 4 anos, o investimento vale R$ 1215.51
Após 5 anos, o investimento vale R$ 1276.28
Após 6 anos, o investimento vale R$ 1340.1
Após 7 anos, o investimento vale R$ 1407.1
Após 8 anos, o investimento vale R$ 1477.46
Após 9 anos, o investimento vale R$ 1551.33
Após 10 anos, o investimento vale R$ 1628.89

Neste exemplo, o loop calcula o valor do investimento ao longo de 10 anos, considerando um retorno anual de 5%. A cada iteração, o valor do investimento é atualizado multiplicando-se pelo fator de crescimento (1 + taxa_de_retorno).

5.7 Comprehensions

As comprehensions são uma maneira concisa e poderosa de criar coleções em Python, como listas, dicionários e conjuntos, a partir de iteráveis existentes, como listas, dicionários, conjuntos ou sequências. Elas permitem criar essas coleções de forma mais eficiente e legível em comparação com a abordagem tradicional de usar loops. As comprehensions podem incluir expressões condicionais para filtrar elementos ou expressões para transformar os elementos durante a criação da coleção.

Por exemplo, você pode criar uma lista de quadrados dos números de 1 a 10 usando uma compreensão de lista:

quadrados = [x ** 2 for x in range(1, 11)]
quadrados
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Isso é equivalente a:

quadrados = []
for x in range(1, 11):
    quadrados.append(x ** 2)

As comprehensions podem ser aplicadas a listas, dicionários e conjuntos, e você pode adicionar cláusulas condicionais para filtrar elementos com base em uma condição específica.

Abaixo, as variáveis linhas e colunas são definidas como intervalos de números de 1 a 3 e de 1 a 2, respectivamente. Em seguida, é utilizada uma compreensão de lista para gerar todos os pares possíveis, combinando cada valor de linha com cada valor de coluna. Por fim, um loop for é usado para iterar sobre a lista de pares e imprimir cada par na saída. O resultado será a impressão de todos os pares ordenados possíveis, combinando os valores de linha e coluna especificados.

linhas = range(1, 4)
colunas = range(1, 3)

pares = [(r, c) for r in linhas for c in colunas]

for x in pares:
    print(x)
(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)

Neste exemplo abaixo, a palavra “inconstitucionalissimamente” é analisada para contar quantas vezes cada letra aparece. Em seguida, é feito um loop sobre o dicionário resultante para imprimir a contagem de ocorrências de cada letra.

palavra = "inconstitucionalissimamente"

frequencia_letras = {letra: palavra.count(letra) for letra in palavra}

for letra, ocorrencias in frequencia_letras.items():
    print("A letra", letra, "ocorre", ocorrencias, "vezes" if ocorrencias > 1 else "vez")
A letra i ocorre 5 vezes
A letra n ocorre 4 vezes
A letra c ocorre 2 vezes
A letra o ocorre 2 vezes
A letra s ocorre 3 vezes
A letra t ocorre 3 vezes
A letra u ocorre 1 vez
A letra a ocorre 2 vezes
A letra l ocorre 1 vez
A letra m ocorre 2 vezes
A letra e ocorre 2 vezes

5.8 Funções

As funções são blocos de código reutilizáveis que realizam uma tarefa específica.
Elas aceitam entradas, chamadas de argumentos, e podem retornar resultados.

Em Python, a sintaxe básica de uma função é a seguinte:

def nome_da_funcao(argumento1, argumento2, ...):
    # Corpo da função
    # Faça alguma coisa com os argumentos
    resultado = argumento1 + argumento2
    return resultado

Por exemplo, vamos criar uma função em Python chamada calcular_juros que calcula o montante final de um investimento com base no valor inicial, na taxa de juros e no número de anos:

def calcular_juros(valor_inicial, taxa_juros, anos):
    montante_final = valor_inicial * (1 + taxa_juros) ** anos
    return montante_final

Agora, definimos valores e chamamos a função:

investimento_inicial = 1000  # Valor inicial do investimento
taxa_juros_anual = 0.05      # Taxa de juros anual (5%)
anos = 5                     # Número de anos
resultado = calcular_juros(investimento_inicial, taxa_juros_anual, anos)
print("O montante final após", anos, "anos será de: R$", round(resultado, 2))
O montante final após 5 anos será de: R$ 1276.28

5.8.1 Função lambda

Uma função lambda em Python é uma função anônima, o que significa que é uma função sem nome. Ela é definida usando a palavra-chave lambda e pode ter qualquer número de argumentos, mas apenas uma expressão. A sintaxe básica é a seguinte:

lambda argumento1, argumento2, ...: expressao

Veja um exemplo de uma função lambda que calcula o quadrado de um número:

quadrado = lambda x: x ** 2

Neste exemplo, lambda x: x ** 2 cria uma função que aceita um argumento x e retorna x ao quadrado. Você pode então usar essa função da mesma forma que qualquer outra função. Por exemplo:

resultado = quadrado(5)
print(resultado)
25

As funções lambda são frequentemente usadas em situações em que você precisa de uma função temporária e simples, como em operações de mapeamento, filtragem e ordenação de dados.

5.9 Classes e objetos

Uma classe é uma estrutura que define o comportamento e as propriedades de um tipo de objeto. Podemos pensar em uma classe como uma representação de um conceito abstrato, como uma transação financeira ou um tipo específico de investimento.

Por exemplo, podemos criar uma classe chamada Transacao para representar uma transação financeira, com propriedades como o valor da transação, a data e o tipo de transação.

Um objeto, por outro lado, é uma instância específica de uma classe. Ele representa uma entidade concreta com suas próprias características e comportamentos. Continuando com o exemplo da classe Transacao, podemos criar objetos individuais para representar transações específicas, como a compra de ações de uma empresa em uma determinada data.

class Transacao:
    def __init__(self, valor, data, tipo):
        self.valor = valor
        self.data = data
        self.tipo = tipo
    
    def print_info(self):
      print(f"Tipo da transação: {self.tipo}, Valor: R${self.valor}, Data:{self.data}")

Neste exemplo, a classe Transacao possui um método especial __init__ que é chamado quando um novo objeto é criado. Esse método inicializa as propriedades do objeto com os valores fornecidos como argumentos. Além disso, a classe possui um método chamado print_info, que imprime as informações da transação, incluindo o tipo, o valor e a data. Esse método também recebe self como parâmetro para acessar os atributos da instância atual da classe. Ao chamar print_info() em um objeto Transacao, ele exibirá as informações formatadas da transação.

A seguir, criamos dois objetos da classe Transacao, transacao1 e transacao2, e acessamos suas propriedades para obter informações sobre as transações.

# Criando objetos da classe Transacao
transacao1 = Transacao(valor=1000, data="2024-03-11", tipo="Compra de ações")
transacao2 = Transacao(valor=500, data="2024-03-12", tipo="Venda de ações")

# Acessando as propriedades dos objetos
print("Valor da transação 1:", transacao1.valor)
Valor da transação 1: 1000
print("Data da transação 2:", transacao2.data)
Data da transação 2: 2024-03-12
# Acessando métodos dos objetos
transacao1.print_info()
Tipo da transação: Compra de ações, Valor: R$1000, Data:2024-03-11
transacao2.print_info()
Tipo da transação: Venda de ações, Valor: R$500, Data:2024-03-12

5.10 Exercícios

1. Trabalhando com tipos de dados básicos

a) Crie variáveis para representar dados econômicos, como o PIB de pelo menos três países, taxas de inflação ou taxas de desemprego. Use valores recentes e históricos para criar um conjunto diversificado de dados econômicos que representem diferentes contextos econômicos ao redor do mundo.

b) Realize operações matemáticas básicas com esses dados, como calcular médias, taxas de crescimento ou proporções. Por exemplo, você pode calcular médias dos valores do PIB, taxas de crescimento do PIB ao longo do tempo, proporções entre diferentes indicadores econômicos (como o PIB per capita em relação ao PIB total), entre outras operações.

2. Durante a análise de dados, pode ser necessário converter entre diferentes tipos de dados. Utilize os tipos de dados fundamentais (integers, floats, strings) e aplique coerção de tipos conforme necessário. Considere, por exemplo que as variáveis representando o PIB foram dadas em formato string. Então, converta um tipo float para computar a média dos PIBs considerados. Depois disso, converta novamente os valores de PIB em uma string para formatação de saída ser no seguinte formato 1,111%.

3. Utilize o código abaixo para gerar um pandas dataframe que representa o preço de fechamento de uma ação

import pandas as pd

# Criando uma lista de datas
datas = pd.date_range(start='2023-01-01', end='2023-12-31', freq='B')  # Frequência 'B' para considerar apenas dias úteis

# Criando uma série de preços de fechamento simulados
import numpy as np
np.random.seed(0)  # Define a semente aleatória para reprodutibilidade
precos_fechamento = np.random.normal(loc=50, scale=5, size=len(datas))  # Simulando preços com distribuição normal

# Criando o DataFrame
df_precos_acoes = pd.DataFrame({'Data': datas, 'Preço de Fechamento': precos_fechamento})

# Exibindo as primeiras linhas do DataFrame
print(df_precos_acoes.head())
        Data  Preço de Fechamento
0 2023-01-02            58.820262
1 2023-01-03            52.000786
2 2023-01-04            54.893690
3 2023-01-05            61.204466
4 2023-01-06            59.337790

a) Obtenha os preços de fechamento da ação durante do mês de janeiro determinado.

b) Obtenha os preços de fechamento da ação entre 2023-06-01 e 2023-12-31.

c) Obtenha os preços de fechamento da ação às sextas-feiras ao longo de todo o período. Calcule o preço de fechamento médio às segundas-feiras e compare com o das sextas-feiras. Qual deles apresenta maior desvio padrão?

# Criando uma coluna para armazenar o dia da semana
df_precos_acoes['Dia da Semana'] = df_precos_acoes['Data'].dt.weekday

# Exibindo as primeiras linhas do DataFrame com a nova coluna
print(df_precos_acoes.head())
        Data  Preço de Fechamento  Dia da Semana
0 2023-01-02            58.820262              0
1 2023-01-03            52.000786              1
2 2023-01-04            54.893690              2
3 2023-01-05            61.204466              3
4 2023-01-06            59.337790              4

4. Considere a lista armazenada na variável pib_anos abaixo e utilize uma compreensão de lista para calcular o crescimento percentual do PIB em relação ao ano anterior para cada país.

# Lista de PIB de um pais nos últimos cinco anos
pib_anos = [1000, 1200, 800, 1500, 2000]  # Exemplo de valores fictícios para o PIB

5. Escreva uma função chamada calcular_ipc que receba três argumentos:

  • cesta_de_produtos: Um dicionário que mapeia cada produto a sua quantidade na cesta.
  • precos_atual: Um dicionário que mapeia cada produto ao seu preço atual.
  • precos_base: Um dicionário que mapeia cada produto ao seu preço base (preço de referência). O IPC é calculado utilizando a seguinte fórmula: \[IPC = \sum_i \frac{\text{preço atual do produto}_i}{\text{preço base do produto}_i}\times \text{quantidade do produto}_i.\] A função deve retornar o valor calculado do IPC. Use o código abaixo para testar sua função.
# Cesta de produtos com suas respectivas quantidades
cesta_de_produtos = {'arroz': 1, 'feijao': 2, 'carne': 3}  
# Preços atuais dos produtos
precos_atual = {'arroz': 5, 'feijao': 8, 'carne': 12}      
# Preços base dos produtos
precos_base = {'arroz': 4, 'feijao': 7, 'carne': 10}      

# Chamada da função para calcular o IPC
ipc = calcular_ipc(cesta_de_produtos, precos_atual, precos_base)
print("O Índice de Preços ao Consumidor (IPC) é:", ipc)

6. Você está encarregado de desenvolver um sistema para registrar e gerenciar transações de compra e venda de ações, além de calcular informações importantes sobre a carteira de investimentos. Para isso, você deve implementar duas classes em Python: Transacao e Carteira.

A classe Transacao representa uma única transação de compra ou venda de ações. Ela possui os seguintes atributos:

  • data: uma string representando a data da transação no formato ‘AAAA-MM-DD’. tipo: uma string indicando o tipo da transação, que pode ser ‘compra’ ou ‘venda’.
  • valor: um número inteiro representando a quantidade de ações transacionadas.

A classe Carteira representa a carteira de investimentos do usuário, que contém várias transações de ações. Ela possui os seguintes atributos: - transacoes: uma lista que armazena todas as transações de ações realizadas.

Além disso, a classe Carteira possui os seguintes métodos:

  • adicionar_transacao(transacao): adiciona uma nova transação à carteira.
  • calcular_posicao_atual(valor_atual_acao): calcula a posição atual da ação na carteira com base no valor atual da ação.
  • calcular_valor_presente(valor_atual_acao): calcula o valor presente da ação na carteira com base no valor atual da ação.

a) Implemente as classes Transacao e Carteira com os atributos e métodos descritos acima.

b) Crie três instâncias da classe Transacao para representar diferentes transações de compra e venda de ações.

c) Crie uma instância da classe Carteira e adicione as transações criadas à carteira.

d) Teste os métodos da classe Carteira, utilizando os exemplos fornecidos no código de teste abaixo.

# Criando algumas transações
transacao1 = Transacao('2024-03-18', 'compra', 10)  # Compra de 10 ações
transacao2 = Transacao('2024-03-19', 'compra', 5)   # Compra de mais 5 ações
transacao3 = Transacao('2024-03-20', 'venda', 8)    # Venda de 8 ações

# Criando uma carteira e adicionando as transações
carteira = Carteira()
carteira.adicionar_transacao(transacao1)
carteira.adicionar_transacao(transacao2)
carteira.adicionar_transacao(transacao3)

# Valor atual da ação (hipotético)
valor_atual_acao = 50

# Testando os métodos da classe Carteira
posicao_atual = carteira.calcular_posicao_atual(valor_atual_acao)
valor_presente = carteira.calcular_valor_presente(valor_atual_acao)

# Exibindo os resultados
print("Posição atual da ação na carteira:", posicao_atual)
print("Valor presente na carteira:", valor_presente)