Tutorial de Python#
Este capítulo traz uma breve introdução ao Python. Nosso objetivo é apresentar conceitos básicos, visando um público que não possui familiaridade com linguagens de programação. Caso você já tenha familiaridade com alguma linguagem de programação e/ou queira aprofundar seu conhecimento em Python, recomendamos o tutorial oficial de Python e o Python Tutorial da W3Schools (em inglês).
Ambiente de Execução#
É possível executar e interagir com todo código Python neste site, basta ativar a opção Live Code. Essa é uma ótima maneira de testar seus conhecimentos. No entanto, o código executado não fica salvo, e a página volta ao seu estado inicial sempre que recarregada.
Todo o site é construído em Jupyter Notebook, assim, caso queira salvar suas alterações, é possível baixar o notebook da página (.ipynb
) e executá-lo localmente; ou carregar e executar o notebook no Binder/Colab e, em seguida, fazer o download do notebook com suas modificações.
Nota
Todo código executado com Live Code é processado pelo Binder.
Cuidado
O Binder possui limitações no uso de memória e CPU. Caso você exceda esse limite, será desconectado e poderá encontrar dificuldades para abrir uma nova sessão. Essa é uma restrição aplicada principalmente para impedir o uso da plataforma para minerar criptomoedas.
Os limites de uso de recursos do Binder não são bem estabelecidos; no entanto, todo código apresentado no site deve executar sem problemas. Mas fique atento em simulações quânticas, pois o uso de recursos computacionais cresce exponencialmente com o número de qubits e pode exceder rapidamente o limite.
Variáveis e Tipos de Dados#
As informações, como números e palavras, são armazenadas em variáveis. Cada variável possui um nome e um valor. Para criar ou atualizar o valor de uma variável, é usado o operador =
como no exemplo abaixo, onde é atribuído o valor 42 à variável answer
.
answer = 42
Você pode usar a função print
para mostrar na tela o valor de uma variável.
Dica
Caso você tenha ativado o Live Code, é necessário executar o código da célula anterior antes de executar o código abaixo. Caso contrário, a variável answer
não estará disponível. Todas as variáveis definidas em uma célula ficam disponíveis para as demais, no entanto, é necessário executar a célula para isso.
print("A resposta é", answer)
A resposta é 42
Além de números inteiros (int
), é possível atribuir números reais (float
), complexos (complex
), palavras (também chamado de string, str
) e outras estruturas de dados para variáveis.
# Isso é um comentário e não é executado
numero_inteiro = 10
numero_real = 10.5
numero_complexo = 2 + 4j # Representa o número 2 + 4i
texto = "Texto" # O valor do texto está sempre entre aspas
Toda variável tem um tipo que é dinamicamente definido no momento da atribuição. Conhecer o tipo da variável é importante quando for operar com ela. Por exemplo, é possível somar um número inteiro com um número real, mas não é possível somar um número inteiro com um texto.
print(numero_inteiro, "é do tipo", type(numero_inteiro))
print(numero_real, "é do tipo", type(numero_real))
print(numero_complexo, "é do tipo", type(numero_complexo))
print(texto, "é do tipo", type(texto)) # Tipo string
10 é do tipo <class 'int'>
10.5 é do tipo <class 'float'>
(2+4j) é do tipo <class 'complex'>
Texto é do tipo <class 'str'>
Operações Matemáticas Básicas#
Operações matemáticas básicas estão disponíveis nativamente no Python. É possível somar (+
), subtrair (-
), multiplicar (*
), dividir (/
) números e encontrar o resto da divisão inteira (%
) entre números. Além disso, também é possível realizar operações de potenciação (**
) e divisão inteira (//
). As operações seguem a precedência de operadores usual, e é possível usar parênteses para definir a ordem das operações.
Abaixo segue exemplos simples de como realizar operações matemáticas básicas em Python. Experimente modificar e executar este código em para ver os resultados das operações.
soma = 10 + 5
subtracao = 20 - 3
multiplicacao = 5 * 4
divisao = 15 / 3
resto_divisao = 17 % 4
potenciacao = 2**3
divisao_inteira = 17 // 4
print("Soma:", soma)
print("Subtração:", subtracao)
print("Multiplicação:", multiplicacao)
print("Divisão:", divisao)
print("Resto da Divisão:", resto_divisao)
print("Potenciação:", potenciacao)
print("Divisão Inteira:", divisao_inteira)
Soma: 15
Subtração: 17
Multiplicação: 20
Divisão: 5.0
Resto da Divisão: 1
Potenciação: 8
Divisão Inteira: 4
resultado1 = 10 + 5 * 2
resultado2 = (10 + 5) * 2
print("Resultado 1:", resultado1)
print("Resultado 2:", resultado2)
Resultado 1: 20
Resultado 2: 30
Estruturas de Controle#
Estruturas de controle permitem alterar o fluxo de execução de um código. Por padrão, o código é executado linha por linha, de cima para baixo. No entanto, é possível utilizar instruções para executar um trecho de código de maneira condicional, ou instruir para repetir uma execução dependendo de algum parâmetro.
Condicionais#
Uma das estruturas de controle mais usadas é o if-else
, onde um trecho de código é executado dependendo de alguma condição. Por exemplo, o código abaixo verifica se o número é par ou não.
numero = 24
if numero % 2 == 0:
print(numero, "é par")
else:
print(numero, "é impar")
24 é par
Note que no trecho de código numero % 2 == 0
, primeiro é calculado o resto da divisão por dois, e então é usado o operador ==
para verificar se o resultado é igual a 0. Assim, caso verdadeiro, é impresso na tela que o número é par, caso contrário, é impresso que o número é ímpar.
Outros operadores de comparação incluem >
, <
, >=
(maior ou igual), <=
(menor ou igual) e !=
(diferente).
Como teste para executar um trecho de código condicional, normalmente, é usado um valor booleano, que pode assumir True
(verdadeiro) ou False
(falso). Assim, considerando que numero
é par, numero % 2 == 0
resulta em True
.
É possível definir um trecho alternativo de execução caso uma condição não seja verdadeira. Nesse caso, é usado o else
. Note que o uso do else
é opcional e ele apenas executa se a condição falhar.
Outro aspecto importante do Python é a indentação. Um trecho de código é definido pela quantidade de espaço no início da linha. Usualmente, 4 espaços são usados para abrir um novo bloco de código. No exemplo anterior, a linha após o if
está indentada, indicando que a função print
faz parte do trecho de código controlado pelo if
. Da mesma forma, a linha após o else
está indentada para indicar que a linha faz parte do trecho de código do else
.
É possível aninhar operações condicionais, como no exemplo abaixo. Lembre-se sempre de identar corretamente seu código, caso contrário, o Python irá acusar um erro sintático, ou pior, o código pode retornar um valor errado.
x = 10
y = 5
z = 20
if x > y:
print("x é maior que y")
if x > z:
print("x é o maior de todos")
else:
print("x não é o maior, mas é maior que y")
else:
print("y é maior que x")
x é maior que y
x não é o maior, mas é maior que y
No exemplo acima, primeiro verificamos se x
é maior que y
. Se for verdadeiro, verificamos se x
também é maior que z
. Se isso for verdadeiro, imprimimos que x
é o maior de todos. Caso contrário, imprimimos que x
não é o maior, mas ainda é maior que y
. Se a primeira condição (x > y
) for falsa, então imprimimos que y
é maior que x
.
Laço de Repetição (Loop)#
Outra estrutura de controle muito usada é o laço de repetição for
, onde um bloco de código é executado repetidamente. Por exemplo, o código abaixo soma todos os números dos primeiros 1000 números:
acc = 0
# ↱ iterador
for i in range(1000):
# ↳ condição de parada
acc = acc + i
print(acc)
499500
A cada repetição do laço for
, o iterador assume um novo valor. Usando a função range
, é possível iterar por todos os números entre 0 e a condição de parada -1. É possível usar range(início, fim)
para iterar entre início e fim -1.
No exemplo a baixo, o laço for
itera sobre os números de 1 a 5, calcula o quadrado de cada número e adiciona à variável soma_quadrados
. O resultado final é a soma dos quadrados desses números.
soma_quadrados = 0
for num in range(1, 6): # de 1 a 5
quadrado = num**2
soma_quadrados += quadrado
print("A soma dos quadrados é:", soma_quadrados)
A soma dos quadrados é: 55
Além de usar o range
, é possível iterar sobre outras estruturas de dados. Por exemplo, é possível iterar sobre uma lista de strings (texto).
for animal in ["rato", "cutia", "lagarto"]:
print(animal, "tem", len(animal), "letras")
rato tem 4 letras
cutia tem 5 letras
lagarto tem 7 letras
Neste exemplo, a variável animal
assume cada valor da lista, e o bloco de código dentro do for
é executado para cada elemento da lista
Funções#
Funções são uma ótima maneira de abstrair o funcionamento do seu código e organizá-lo. Funções são blocos de código que com um comportamento específico e normalmente possuem parâmetros de entrada e retornam algum valor. Por exemplo, a função soma
definida abaixo retorna a soma dos argumentos de entrada.
def soma(valor_a, valor_b):
resultado = valor_a + valor_b
return resultado
O tipo dos parâmetros valor_a
e valor_b
é definido dinamicamente, e desde que os valores possam ser somados, essa função executará corretamente.
Uma vez tendo a função definida, podemos chamá-la usando a estrutura <nome da função>(parâmetros...)
.
Dica
Lembre-se de executar o código acima antes de executar o trecho de código abaixo, pois primeiro temos que definir a função para depois chamá-la.
a = 10
b = 33
print(soma(a, b))
43
A instrução return
é usada para indicar o valor que deve ser retornado da função. É possível que uma função retorne em mais de um lugar. Por exemplo, podemos colocar o return
dentro de um bloco condicional:
def maior_de_idade(name, idade):
if idade >= 18:
return f"{name} é maior de idade."
return f"{name} é menor de idade."
print(maior_de_idade("João", 20))
João é maior de idade.
O tipo de cada parâmetro de uma função, assim como o tipo do retorno, é definido dinamicamente quando a função é chamada. No entanto, normalmente, as funções são construídas para operar sobre um tipo de dado específico. Por exemplo, no parâmetro idade
da função maior_de_idade
, é esperado um número, e essa função retorna um erro se passarmos uma string, por exemplo.
Uma maneira de melhorar a clareza dos parâmetros da função é usar anotações de tipo. Essas anotações ajudam o programador a entender quais tipos de dados uma função recebe e que tipo de dado uma função retorna. No entanto, a anotação de tipo não é levada em consideração quando o código é executado. Abaixo segue a mesma função maior_de_idade
definida com anotação de tipo.
# tipo do parâmetro name ↴ ↱ tipo do parâmetro idade
def maior_de_idade(name: str, idade: int) -> str:
# ↳ tipo do retorno da função
if idade >= 18:
return f"{name} é maior de idade."
return f"{name} é menor de idade."
print(maior_de_idade("Maria", 12))
Maria é menor de idade.
Você também pode chamar funções já definidas. Por exemplo, print
é uma função já definida do Python. Além desta, existem diversas outras, como a função range
vista anteriormente.
Importando Módulos#
Além das funcionalidades básicas do Python, algumas já vistas neste tutorial, a linguagem traz uma vasta biblioteca com módulos específicos para criptografia, processamento de texto, gerenciamento de arquivos e muito mais. Recomendamos consultar a documentação do Python para ver quais bibliotecas o Python traz por padrão: Documentação Python. Para exemplificar o uso de módulos no Python, vamos importar a biblioteca math
.
Para importar uma biblioteca, é usada a instrução import
, como no exemplo abaixo:
import math
print("Valor de π =", math.pi)
print("Valor de e =", math.e)
print("Raiz quadrada de 2 =", math.sqrt(2))
Valor de π = 3.141592653589793
Valor de e = 2.718281828459045
Raiz quadrada de 2 = 1.4142135623730951
Uma vez que o módulo é importado, você terá acesso às funções e variáveis definidas nele. Além disso, é possível importar elementos específicos de um módulo, como no exemplo a seguir:
from math import cos, sin
print("Cosseno de π =", cos(math.pi))
print("Seno de π =", sin(math.pi))
Cosseno de π = -1.0
Seno de π = 1.2246467991473532e-16
Dica
Note que sin(math.pi)
não retorna zero, como esperado, mas sim um número muito pequeno. Isso acontece devido a erros de arredondamento em operações de ponto flutuante. Como números são armazenados em uma quantidade finita de memória, esses erros são inevitáveis. Muitas aplicações possuem métodos para tratar erros de ponto flutuante, mas não se preocupe muito com isso, na maioria dos casos esses erros são aceitáveis.
Estruturas de Dados#
Estruturar seus dados de maneira correta é essencial para conseguir resolver alguns problemas usando programação de maneira eficiente. Dentre as estruturas de dados que o Python implementa, duas são essenciais: listas e dicionários.
Listas#
Lista (list
) é uma estrutura de dados simples, onde cada elemento tem uma posição e é possível adicionar e remover elementos da lista, além de iterar sobre a mesma. Em Python, para criar uma lista, basta listar seus itens como no exemplo abaixo:
lista_de_pares = [2, 4, 6, 8, 10]
print(f"{lista_de_pares=}")
lista_de_pares=[2, 4, 6, 8, 10]
lista_de_animais = ["cachorro", "gato", "elefante"]
print(f"{lista_de_animais=}")
lista_de_animais=['cachorro', 'gato', 'elefante']
Além disso, existem outras formas de criar listas, como por exemplo, usando range
ou iterando sobre outra lista.
lista_de_pares = [2 * n for n in range(10)]
print(f"{lista_de_pares=}")
lista_de_pares=[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
tamanho_das_palavras = [len(n) for n in lista_de_animais]
print(f"{tamanho_das_palavras=}")
tamanho_das_palavras=[8, 4, 8]
As operações usuais de lista são:
Acessar elementos da lista pelo índice: Podemos acessar um elemento específico da lista indicando seu índice dentro de colchetes. Por exemplo,
lista_de_pares[0]
retorna o primeiro elemento da lista de pares.Adicionar elementos à lista: Podemos adicionar elementos à lista utilizando o método
append()
ouinsert()
.Remover elementos da lista: Podemos remover elementos da lista utilizando o método
remove()
,pop()
.Iterar sobre os elementos da lista: Podemos percorrer todos os elementos de uma lista utilizando um loop
for
.Verificar se um elemento está na lista: Podemos verificar se um determinado elemento está presente em uma lista utilizando o operador
in
.
Abaixo segue exemplos de como usar essas operações.
# Criando uma lista de números pares
lista_de_pares = [2, 4, 6, 8, 10]
# Acessando o terceiro elemento da lista
# A indexação começa em 0, então o terceiro elemento é o elemento na posição 2.
terceiro_elemento = lista_de_pares[2]
print("Terceiro elemento da lista de pares:", terceiro_elemento)
Terceiro elemento da lista de pares: 6
# Adicionando um novo número par à lista
lista_de_pares.append(12)
print("Lista de pares após adicionar o número 12:", lista_de_pares)
Lista de pares após adicionar o número 12: [2, 4, 6, 8, 10, 12]
# Removendo o segundo elemento da lista
elemento_removido = lista_de_pares.pop(1)
print("Elemento removido da lista de pares:", elemento_removido)
print("Lista de pares após remover o terceiro elemento:", lista_de_pares)
Elemento removido da lista de pares: 4
Lista de pares após remover o terceiro elemento: [2, 6, 8, 10, 12]
# Iterando sobre os elementos da lista
print("Iterando sobre os elementos da lista de pares:")
for numero in lista_de_pares:
print(numero)
Iterando sobre os elementos da lista de pares:
2
6
8
10
12
# Verificando se o número 6 está presente na lista
if 6 in lista_de_pares:
print("O número 6 está presente na lista de pares.")
else:
print("O número 6 não está presente na lista de pares.")
O número 6 está presente na lista de pares.
Dicionários#
Dicionário (dict
) é uma estrutura de dados que mapeia uma chave a um valor, análogo a um dicionário de português que mapeia uma palavra para o seu significado. É possível construir um dicionário diretamente, como no exemplo abaixo:
telefones = {
"Alice": "(23) 93901-1295",
"Bob": "(27) 97684-2155",
"Carlos": "(53) 93429-5110",
"Daniel": "(88) 93771-0112",
}
for nome in telefones:
print("Número de", nome, "é", telefones[nome])
Número de Alice é (23) 93901-1295
Número de Bob é (27) 97684-2155
Número de Carlos é (53) 93429-5110
Número de Daniel é (88) 93771-0112
As operações usuais em dicionários são:
Acessar elementos do dicionário pela chave: Podemos acessar o valor associado a uma chave específica utilizando a notação de colchetes, como
telefones["Alice"]
.Adicionar novos pares chave-valor ao dicionário: Podemos adicionar novos elementos ao dicionário utilizando a notação de colchetes e o operador de atribuição, como
telefones["Eva"] = "(99) 99999-9999"
.Remover elementos do dicionário: Podemos remover elementos do dicionário utilizando o comando
del
.Iterar sobre os elementos do dicionário: Podemos percorrer todas as chaves de um dicionário utilizando um loop
for
.Verificar se uma chave está presente no dicionário: Podemos verificar se uma determinada chave está presente no dicionário utilizando o operador
in
.
Abaixo seguem mais exemplos de como usar um dicionario.
# Criando um dicionário de notas dos alunos
notas_alunos = {
"Alice": 8.5,
"Bob": 7.2,
"Carlos": 9.0,
"Daniel": 6.8,
}
# Acessando a nota do aluno Carlos
nota_carlos = notas_alunos["Carlos"]
print("Nota do aluno Carlos:", nota_carlos)
Nota do aluno Carlos: 9.0
# Adicionando uma nova entrada ao dicionário
notas_alunos["Eva"] = 9.5
print("Dicionário de notas após adicionar a nota da aluna Eva:", notas_alunos)
Dicionário de notas após adicionar a nota da aluna Eva: {'Alice': 8.5, 'Bob': 7.2, 'Carlos': 9.0, 'Daniel': 6.8, 'Eva': 9.5}
# Removendo a entrada do aluno Bob do dicionário
del notas_alunos["Bob"]
print("Dicionário de notas após remover a nota do aluno Bob:", notas_alunos)
Dicionário de notas após remover a nota do aluno Bob: {'Alice': 8.5, 'Carlos': 9.0, 'Daniel': 6.8, 'Eva': 9.5}
# Iterando sobre os elementos do dicionário
print("Iterando sobre os elementos do dicionário de notas:")
for aluno, nota in notas_alunos.items():
print(f"Nota de {aluno}: {nota}")
Iterando sobre os elementos do dicionário de notas:
Nota de Alice: 8.5
Nota de Carlos: 9.0
Nota de Daniel: 6.8
Nota de Eva: 9.5
# Verificando se a nota do aluno Daniel está presente no dicionário
if "Daniel" in notas_alunos:
print("A nota do aluno Daniel está presente no dicionário de notas.")
else:
print("A nota do aluno Daniel não está presente no dicionário de notas.")
A nota do aluno Daniel está presente no dicionário de notas.
Operações com Matrizes#
Como a linguagem da computação quântica é álgebra linear, é interessante sabermos como operar com matrizes no Python. Para isso, é recomendado usar a biblioteca NumPy. Como essa biblioteca não faz parte do Python, é necessário instalá-la. Execute a próxima célula que irá instalar o NumPy e importá-lo.
Note que no importe nós renomeamos o módulo numpy
para np
no código.
!pip install -U pip -q
!pip install numpy -q
import numpy as np
Nota
Em outras páginas que usam o NumPy, ou outra biblioteca externa como Ket, as bibliotecas serão instaladas automaticamente ao iniciar o Live Code.
Para trabalhar com espaços vetoriais, precisamos de 3 elementos: escalares, vetores e matrizes.
Um escalar pode ser tanto um número inteiro (
int
), número real (float
), ou complexo (complex
).Para criar um vetor, é usada uma lista de escalares.
Para criar uma matriz, é usada uma lista de lista de escalares.
O exemplo abaixo ilustra como instanciar cada tipo de elemento.
escalar = 7.8
vetor = np.array([2, 8])
matriz = np.array([[4, 2], [5, 1]])
Todas as operações usuais estão presentes, como soma de vetores/matriz, multiplicação por escalar e multiplicação de matriz-matriz e matriz-vetor. Além disso, operações como soma e multiplicação elemento a elemento também estão definidas.
No exemplo abaixo, seguem exemplos de operações permitidas.
print("Multiplicação vetor-escalar")
print(vetor * escalar)
Multiplicação vetor-escalar
[15.6 62.4]
print("Divisão vetor-escalar")
print(vetor / escalar)
Divisão vetor-escalar
[0.25641026 1.02564103]
print("Multiplicação matrix-escalar")
print(matriz * escalar)
Multiplicação matrix-escalar
[[31.2 15.6]
[39. 7.8]]
print("Divisão matrix-escalar")
print(matriz / escalar)
Divisão matrix-escalar
[[0.51282051 0.25641026]
[0.64102564 0.12820513]]
print("Soma vetor-vetor")
print(vetor + vetor)
Soma vetor-vetor
[ 4 16]
Note que para a multiplicação matricial usual, é usado o operador @
, sendo o operador *
usado para multiplicação elemento a elemento.
print("Multiplicação matrix-vetor")
print(matriz @ vetor)
Multiplicação matrix-vetor
[24 18]
print("Multiplicação matrix-matrix")
print(matriz @ matriz)
Multiplicação matrix-matrix
[[26 10]
[25 11]]
Vetor Linha e Vetor Coluna#
Quando um vetor é definido como np.array([...])
, ele pode operar tanto como um vetor linha quanto como um vetor coluna. Esse é o comportamento esperado para um vetor de uma dimensão, no entanto, em alguns casos, como na computação quântica, diferenciar entre vetor linha e coluna é importante. Vetores linha e coluna possuem duas dimensões como matrizes e podem ser criados como no exemplo a seguir.
vetor_linha = np.array([[1, 2, 3, 4]])
print(vetor_linha)
[[1 2 3 4]]
vetor_coluna = np.array([[1], [2], [3], [4]])
print(vetor_coluna)
[[1]
[2]
[3]
[4]]
Outra maneira mais simples de criar um vetor coluna é instanciar um vetor linha e transpô-lo, como no exemplo abaixo.
vetor_coluna2 = np.array([[1, 2, 3, 4]]).T
print(vetor_coluna2)
[[1]
[2]
[3]
[4]]
Conclusão#
O objetivo deste tutorial é proporcionar uma breve introdução ao Python e permitir que alunos sem familiaridade com programação possam iniciar sua introdução ao tema.
Este material está longe de ser completo e não tem a intenção de ser. Recomendamos aos alunos que busquem materiais externos para complementar seus conhecimentos. Além disso, uma boa maneira de aprender é modificar e executar o código apresentado no site. Portanto, ative o Live Code e teste!