Artigo original: Python Code Example Handbook – Sample Script Coding Tutorial for Beginners

Olá! Boas-vindas. Se você está aprendendo Python, este artigo é para você. Você encontrará uma descrição detalhada da sintaxe do Python e diversos exemplos de código para guiar você durante sua jornada de programação.

Sobre o que trataremos:

Estão prontos? Vamos começar! 🔅

💡 Dica: no decorrer deste artigo, usarei <> para indicar que essa parte da sintaxe será substituída pelo elemento descrito no texto. Por exemplo, <var> significa que isso será substituído por uma variável quando escrevemos o código.

🔹 Definições de variáveis em Python

A base de qualquer linguagem de programação é o conceito de variável, um nome ou lugar na memória que reservamos para que receba um valor.

Em Python, usamos esta sintaxe para criar uma variável e atribuir a ela um valor:

<nome_da_variavel> = <valor>

Por exemplo:

idade = 56
nome = "Nora"
cor = "Azul"
notas = [67, 100, 87, 56]

Se o nome de uma variável tiver mais de uma palavra, o Guia de estilo para o código em Python (em inglês, mas também pode ser encontrado em português aqui) recomenda separar as palavras com uma sublinha "conforme necessário para melhorar a legibilidade."

Por exemplo:

minha_lista = [1, 2, 3, 4, 5]

💡 Dica: o Guia de estilo para o código em Python (PEP 8) tem ótimas sugestões as quais você deve seguir se quiser escrever código limpo em Python.

🔸 Programa Hello World! em Python

Antes de nos aprofundarmos nos tipos e nas estruturas de dados que podem ser usados em Python, vejamos como podemos escrever nosso primeiro programa em Python.

Você precisa apenas chamar a função print() e escrever "Hello World!" entre parênteses:

print("Hello World!")

Você verá a mensagem abaixo após executar o programa:

"Hello World!"

💡 Dica: escrever um programa "Hello World!" é uma tradição na comunidade de desenvolvedores. A maioria dos desenvolvedores começa a aprender a programar escrevendo esse programa.

Ótimo. Você acaba de escrever seu primeiro programa em Python. Agora, vamos começar a aprender sobre tipos de dados e estruturas de dados integradas que você pode utilizar em Python.

🔹 Tipos de dados e estruturas de dados integradas em Python

Temos vários tipos básicos de dados e estruturas de dados integradas com as quais podemos trabalhar em nossos programas. Cada uma tem suas aplicações específicas. Vamos vê-las em detalhes.

Tipos de dados numéricos em Python: Integers, Floats e Complex

Esses são os tipos numéricos com os quais você pode trabalhar em Python:

Integers

Os integers, ou números inteiros, são aqueles números que não têm casas decimais. Você pode verificar se um número é um inteiro com a função type(). Se o resultado for <class 'int'>, o número é inteiro.

Por exemplo:

>>> type(1)
<class 'int'>

>>> type(15)
<class 'int'>

>>> type(0)
<class 'int'>

>>> type(-46)
<class 'int'>

Floats

Floats são números de ponto flutuante ou números com casas decimais. Você pode detectar isso visualmente ao ver onde está o ponto decimal. Se chamarmos type() para verificar o tipo de dados desses valores, teremos o seguinte como resultado:

<class 'float'>

Aqui temos alguns exemplos:

>>> type(4.5)
<class 'float'>

>>> type(5.8)
<class 'float'>

>>> type(2342423424.3)
<class 'float'>

>>> type(4.0)
<class 'float'>

>>> type(0.0)
<class 'float'>

>>> type(-23.5)
<class 'float'>

Complex

Complex, ou números complexos, têm uma parte real e outra imaginária, denotada com um j. Você pode criar números complexos em Python com complex(). O primeiro argumento será a parte real e o segundo será a parte imaginária.

Aqui temos alguns exemplos:

>>> complex(4, 5)
(4+5j)

>>> complex(6, 8)
(6+8j)

>>> complex(3.4, 3.4)
(3.4+3.4j)

>>> complex(0, 0)
0j

>>> complex(5)
(5+0j)

>>> complex(0, 4)
4j

Strings em Python

Strings são incrivelmente úteis em Python. Elas contêm uma sequência de caracteres e são usadas, em geral, para representar texto no código.

Por exemplo:

"Hello World!"
'Hello World!'

Podemos usar aspas simples '' ou aspas duplas "" para definir uma string. As duas formas de aspas são válidas e equivalentes, mas você deve escolher uma delas e usá-la consistentemente em seu programa.

💡 Dica: sim! Você usou uma string quando escreveu o programa "Hello World!". Sempre que você enxergar um valor cercado por aspas simples ou duplas em Python, estamos falando de uma string.

Strings podem conter qualquer caractere que possamos digitar em nosso teclado, incluindo números, símbolos e outros caracteres especiais.

Por exemplo:

"45678"
"meu_email@email.com"
"#EuAmoPython"

💡 Dica: espaços também são contados como caracteres em uma string.

Citações dentro de strings

Se definirmos uma string com aspas duplas "", podemos usar aspas simples dentro da string. Por exemplo:

"Ele falou que o show foi 'incrível'." 

Se definirmos uma string com aspas simples '', podemos usar as aspas duplas dentro da string. Por exemplo:

'Meu livro favorito se chama "Razão e Sensibilidade"'

Indexação de strings

Podemos usar os índices para acessar os caracteres de uma string em nosso programa em Python. Um índice é um número inteiro que representa uma posição  específica na string. O índice está associado ao caractere daquela posição.

Este é um diagrama da string "Hello":

String:  H e l l o
Índice:  0 1 2 3 4

💡 Dica: os índices iniciem em 0 e aumentam 1 número a cada caractere à sua direita.

Por exemplo:

>>> minha_string = "Hello"

>>> minha_string[0]
'H'

>>> minha_string[1]
'e'

>>> minha_string[2]
'l'

>>> minha_string[3]
'l'

>>> minha_string[4]
'o'

Também podemos usar índices negativos para acessar esses caracteres:

>>> minha_string = "Hello"

>>> minha_string[-1]
'o'

>>> minha_string[-2]
'l'

>>> minha_string[-3]
'l'

>>> minha_string[-4]
'e'

>>> minha_string[-5]
'H'

💡 Dica: normalmente, usamos -1 para acessar o último caractere de uma string.

Divisão (slicing) de strings

É possível, também, que precisemos de uma parte de uma string ou de um subconjunto de seus caracteres. Podemos fazer isso por meio de um processo chamado de string slicing, ou divisão/fatiamento de strings.

Esta é a sintaxe geral:

<variável_string>[início:parada:passo]

início é o índice do primeiro caractere que será incluído na "fatia". Por padrão, esse índice é o 0.

  • parada é o índice do último caractere da fatia (este caractere não será incluído). Por padrão, ele é o último caractere da string (se omitirmos esse valor, o último caractere também será incluído na fatia).
  • passo é o número que adicionaremos ao índice atual para buscar o próximo índice a ser incluído na fatia.

Podemos especificar dois parâmetros para usar o valor padrão de passo, que é 1. Isso incluirá todos os caracteres entre início e parada (sem contar o que está nesse último índice):

<variável_string>[início:parada]

Por exemplo:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp[2:8]
'eeCode'

>>> freecodecamp[0:3]
'fre'

>>> freecodecamp[0:4]
'free'

>>> freecodecamp[4:7]
'Cod'

>>> freecodecamp[4:8]
'Code'

>>> freecodecamp[8:11]
'Cam'

>>> freecodecamp[8:12]
'Camp'

>>> freecodecamp[8:13]
'Camp'

💡 Dica: observe que, se o valor de um parâmetro vai além do intervalo válido de índices, a fatia ainda será apresentada. É assim que os criadores do Python implementaram esse recurso de divisão de strings.

Se personalizarmos o passo, "saltaremos" de um índice para o próximo, de acordo com esse valor.

Por exemplo:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp[0:9:2]
'feCdC'

>>> freecodecamp[2:10:3]
'eoC'

>>> freecodecamp[1:12:4]
'roa'

>>> freecodecamp[4:8:2]
'Cd'

>>> freecodecamp[3:9:2]
'eoe'

>>> freecodecamp[1:10:5]
'rd'

Também podemos usar um passo negativo para ir da direita para a esquerda:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp[10:2:-1]
'maCedoCe'

>>> freecodecamp[11:4:-2]
'paeo'

>>> freecodecamp[5:2:-4]
'o'

Além disso, podemos omitir um parâmetro para usar seu valor padrão. Somente precisamos incluir os dois pontos (:)  correspondentes se omitirmos início, parada ou os dois:

>>> freecodecamp = "freeCodeCamp"

# Início e passo padrões
>>> freecodecamp[:8]
'freeCode'

# Parada e passo padrões
>>> freecodecamp[4:]
'CodeCamp'

# Início padrão
>>> freecodecamp[:8:2]
'feCd'

# Parada padrão
>>> freecodecamp[4::3]
'Cem'

# Início e parada padrões
>>> freecodecamp[::-2]
'paeoer'

# Início e parada padrões
>>> freecodecamp[::-1]
'pmaCedoCeerf'

💡 Dica: o último exemplo é uma das maneiras mais comuns de inverter uma string.

f-strings

No Python 3.6 e em versões mais recentes, podemos usar um tipo de string chamada de f-string, que nos ajuda a formatar nossas strings de modo muito mais fácil.

Para definir uma f-string, simplesmente adicionamos f antes das aspas simples ou duplas. Então, dentro da string, cercamos as variáveis ou as expressões com chaves {}. Isso substituirá seu valor na string quando executarmos o programa.

Por exemplo:

nome = "Nora"
linguagem_favorita = "Python"

print(f"Olá, eu sou {nome}. Estou aprendendo {linguagem_favorita}.")

O resultado é:

Olá, eu sou Nora. Estou aprendendo Python.

Aqui temos um exemplo onde calculamos o valor de uma expressão e substituímos o resultado na string:

valor = 5

print(f"{valor} multiplicado por 2 é: {valor * 2}")

As expressões entre chaves são substituídas no resultado:

5 multiplicado por 2 é: 10

Também podemos chamar métodos dentro das chaves. O valor retornado será substituído na string quando executarmos o programa:

freecodecamp = "FREECODECAMP"

print(f"{freecodecamp.lower()}")

O resultado é:

freecodecamp

Métodos de strings

Strings têm métodos, que representam funcionalidades comuns que foram implementadas pelos desenvolvedores do Python, para que possamos usá-las em nossos programas diretamente. Eles são muito úteis para realizarmos operações comuns.

Esta é a sintaxe geral de como chamar um método de string:

<variável_string>.<nome_do_método>(<argumentos>)

Por exemplo:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp.capitalize()
'Freecodecamp'

>>> freecodecamp.count("C")
2

>>> freecodecamp.find("e")
2

>>> freecodecamp.index("p")
11

>>> freecodecamp.isalnum()
True

>>> freecodecamp.isalpha()
True

>>> freecodecamp.isdecimal()
False

>>> freecodecamp.isdigit()
False

>>> freecodecamp.isidentifier()
True

>>> freecodecamp.islower()
False

>>> freecodecamp.isnumeric()
False

>>> freecodecamp.isprintable()
True

>>> freecodecamp.isspace()
False

>>> freecodecamp.istitle()
False

>>> freecodecamp.isupper()
False

>>> freecodecamp.lower()
'freecodecamp'

>>> freecodecamp.lstrip("f")
'reeCodeCamp'

>>> freecodecamp.rstrip("p")
'freeCodeCam'

>>> freecodecamp.replace("e", "a")
'fraaCodaCamp'

>>> freecodecamp.split("C")
['free', 'ode', 'amp']

>>> freecodecamp.swapcase()
'FREEcODEcAMP'

>>> freecodecamp.title()
'Freecodecamp'

>>> freecodecamp.upper()
'FREECODECAMP'

Para aprender mais sobre métodos em Python, recomendo ler este artigo da documentação do Python (em inglês).

💡 Dica: todos os métodos de strings retornam cópias das strings. Eles não modificam a string, pois strings são imutáveis em Python.

Booleanos em Python

Os valores booleanos são True e False em Python. Eles devem começar com uma letra maiúscula para serem reconhecidos como valores booleanos.

Por exemplo:

>>> type(True)
<class 'bool'>

>>> type(False)
<class 'bool'>

Se os escrevermos inteiramente em letras minúsculas, receberemos uma mensagem de erro:

>>> type(true)
Traceback (most recent call last):
  File "<pyshell#92>", line 1, in <module>
    type(true)
NameError: name 'true' is not defined

>>> type(false)
Traceback (most recent call last):
  File "<pyshell#93>", line 1, in <module>
    type(false)
NameError: name 'false' is not defined

Listas em Python

Agora que tratamos dos tipos de dados básicos em Python, começaremos a tratar das estruturas de dados integradas. A primeira delas é a lista.

Para definir uma lista, usamos colchetes [], com os elementos separados por uma vírgula.

💡 Dica: é recomendado adicionar um espaço após cada vírgula para tornar o código mais legível.

Por exemplo, aqui temos alguns exemplos de listas:

[1, 2, 3, 4, 5]
["a", "b", "c", "d"]
[3.4, 2.4, 2.6, 3.5]

As listas podem conter valores de tipos de dados diferentes. Por isso, a lista abaixo seria válida em Python:

[1, "Emily", 3.4]

Também podemos atribuir uma lista a uma variável:

minha_lista = [1, 2, 3, 4, 5]
letras = ["a", "b", "c", "d"]

Listas aninhadas

Listas podem conter valores de qualquer tipo de dados, incluindo outras listas. Essas "listas internas" são chamadas de listas aninhadas.

[[1, 2, 3], [4, 5, 6]]

Neste exemplo, [1, 2, 3] e [4, 5, 6] são listas aninhadas.

Aqui temos outros exemplos válidos:

[["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
[1, [2, 3, 4], [5, 6, 7], 3.4]

Podemos acessar as listas aninhadas usando seu índice correspondente:

>>> minha_lista = [[1, 2, 3], [4, 5, 6]]

>>> minha_lista[0]
[1, 2, 3]

>>> minha_lista[1]
[4, 5, 6]

Listas aninhadas podem ser usadas para representar, por exemplo, a estrutura de um tabuleiro de um jogo bidimensional, onde cada número pode representar um elemento diferente ou um bloco:

# Tabuleiro simples, onde: 
# 0 = Bloco vazio
# 1 = Moeda
# 2 = Inimigo
# 3 = Objetivo
tabuleiro = [[0, 0, 1],
             [0, 2, 0],
             [1, 0, 3]]

Tamanho da lista

Podemos usar a função len() para saber o tamanho (length, em inglês) de uma lista (o número de elementos que ela contém).

Por exemplo:

>>> minha_lista = [1, 2, 3, 4]

>>> len(minha_lista)
4

Atualizar um valor em uma lista

Podemos atualizar um valor em um índice específico com a sintaxe abaixo:

<variável_lista>[<índice>] = <valor>

Por exemplo:

>>> letras = ["a", "b", "c", "d"]

>>> letras[0] = "z"

>>> letras
['z', 'b', 'c', 'd']

Adicionar um valor a uma lista

Podemos adicionar um valor ao final de uma lista com o método .append().

Por exemplo:

>>> minha_lista = [1, 2, 3, 4]

>>> minha_lista.append(5)

>>> minha_lista
[1, 2, 3, 4, 5]

Remover um valor de uma lista

Podemos remover um valor de uma lista com o método .remove().

Por exemplo:

>>> minha_lista = [1, 2, 3, 4]

>>> minha_lista.remove(3)

>>> minha_lista
[1, 2, 4]

💡 Dica: isso removerá somente a primeira ocorrência do elemento. Se tentarmos, por exemplo, remover o número 3 de uma lista que tem dois números 3, o segundo número não será removido:

>>> minha_lista = [1, 2, 3, 3, 4]

>>> minha_lista.remove(3)

>>> minha_lista
[1, 2, 3, 4]

Indexação de listas

Podemos indexar uma lista do mesmo modo que indexamos strings, com índices que começam em 0:

>>> letras = ["a", "b", "c", "d"]

>>> letras[0]
'a'

>>> letras[1]
'b'

>>> letras[2]
'c'

>>> letras[3]
'd'

Divisão de listas

Também podemos obter uma parte/"fatia" de uma lista usando a mesma sintaxe que utilizamos com as strings e podemos omitir os parâmetros para usar seus valores padrão. Agora, em vez de adicionar caracteres à fatia, adicionaremos os elementos da lista.

<variável_lista>[início:parada:passo]

Por exemplo:

>>> minha_lista = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]

>>> minha_lista[2:6:2]
['c', 'e']

>>> minha_lista[2:8]
['c', 'd', 'e', 'f', 'g', 'h']

>>> minha_lista[1:10]
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

>>> minha_lista[4:8:2]
['e', 'g']

>>> minha_lista[::-1]
['i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

>>> minha_lista[::-2]
['i', 'g', 'e', 'c', 'a']

>>> minha_lista[8:1:-1]
['i', 'h', 'g', 'f', 'e', 'd', 'c']

Métodos de listas

O Python também tem métodos de listas já implementados para nos ajudar a realizar operações comuns com listas. Aqui estão alguns exemplos dos métodos de listas mais comumente usados:

>>> minha_lista = [1, 2, 3, 3, 4]

>>> minha_lista.append(5)
>>> minha_lista
[1, 2, 3, 3, 4, 5]

>>> minha_lista.extend([6, 7, 8])
>>> minha_lista
[1, 2, 3, 3, 4, 5, 6, 7, 8]

>>> minha_lista.insert(2, 15)
>>> minha_lista
[1, 2, 15, 3, 3, 4, 5, 6, 7, 8, 2, 2]

>>> minha_lista.remove(2)
>>> minha_lista
[1, 15, 3, 3, 4, 5, 6, 7, 8, 2, 2]

>>> minha_lista.pop()
2

>>> minha_lista.index(6)
6

>>> minha_lista.count(2)
1

>>> minha_lista.sort()
>>> minha_lista
[1, 2, 3, 3, 4, 5, 6, 7, 8, 15]

>>> minha_lista.reverse()
>>> minha_lista
[15, 8, 7, 6, 5, 4, 3, 3, 2, 1]

>>> minha_lista.clear()
>>> minha_lista
[]

Para saber mais sobre métodos de listas, recomendo ler este artigo da documentação do Python (em inglês).

Tuplas em Python

Para definir uma tupla em Python, usamos os parênteses () e separamos os elementos com vírgulas. É recomendado adicionar um espaço após cada vírgula para tornar o código mais legível.

(1, 2, 3, 4, 5)
("a", "b", "c", "d")
(3.4, 2.4, 2.6, 3.5)

Podemos atribuir tuplas a variáveis:

minha_tupla = (1, 2, 3, 4, 5)

Indexação de tuplas

Podemos acessar cada elemento de uma tupla com seu índice correspondente:

>>> minha_tupla = (1, 2, 3, 4)

>>> minha_tupla[0]
1

>>> minha_tupla[1]
2

>>> minha_tupla[2]
3

>>> minha_tupla[3]
4

Também podemos usar índices negativos:

>>> minha_tupla = (1, 2, 3, 4)

>>> minha_tupla[-1]
4

>>> minha_tupla[-2]
3

>>> minha_tupla[-3]
2

>>> minha_tupla[-4]
1

Tamanho das tuplas

Para descobrir o tamanho de uma tupla, usamos a função len(), passando a tupla como argumento:

>>> minha_tupla = (1, 2, 3, 4)

>>> len(minha_tupla)
4

Tuplas aninhadas

As tuplas podem conter valores de qualquer tipo de dados, até mesmo listas e outras tuplas. Essas tuplas internas são chamadas de tuplas aninhadas.

([1, 2, 3], (4, 5, 6))

Nesse exemplo, temos uma tupla aninhada (4, 5, 6) e uma lista. Você pode acessar essas estruturas de dados aninhadas com seu índice correspondente.

Por exemplo:

>>> minha_tupla = ([1, 2, 3], (4, 5, 6))

>>> minha_tupla[0]
[1, 2, 3]

>>> minha_tupla[1]
(4, 5, 6)

Divisão de tuplas

Podemos dividir/"fatiar" uma tupla do mesmo modo que fizemos com listas e strings. O mesmo princípio e as mesmas regras são aplicáveis.

Essa é a sintaxe geral:

<variável_tupla>[início:parada:passo]

Por exemplo:

>>> minha_tupla = (4, 5, 6, 7, 8, 9, 10)

>>> minha_tupla[3:8]
(7, 8, 9, 10)

>>> minha_tupla[2:9:2]
(6, 8, 10)

>>> minha_tupla[:8]
(4, 5, 6, 7, 8, 9, 10)

>>> minha_tupla[:6]
(4, 5, 6, 7, 8, 9)

>>> minha_tupla[:4]
(4, 5, 6, 7)

>>> minha_tupla[3:]
(7, 8, 9, 10)

>>> minha_tupla[2:5:2]
(6, 8)

>>> minha_tupla[::2]
(4, 6, 8, 10)

>>> minha_tupla[::-1]
(10, 9, 8, 7, 6, 5, 4)

>>> minha_tupla[4:1:-1]
(8, 7, 6)

Métodos das tuplas

Existem dois métodos integrados das tuplas em Python:

>>> minha_tupla = (4, 4, 5, 6, 6, 7, 8, 9, 10)

>>> minha_tupla.count(6)
2

>>> minha_tupla.index(7)
5

💡 Dica: tuplas são imutáveis. Elas não podem ser modificadas. Não é possível, adicionar, atualizar ou remover elementos de uma tupla. Se precisarmos fazer isso, precisamos criar uma nova cópia da tupla.

Atribuição de tuplas

Em Python, temos um recurso muito interessante, chamado de atribuição de tuplas. Com esse tipo de atribuição, podemos atribuir valores a diversas variáveis em uma única linha.

Os valores são atribuídos às suas variáveis correspondentes na ordem em que elas aparecem. Em a, b = 1, 2, para fins de exemplo, o valor 1 é atribuído à variável a e o valor 2 é atribuído à variável b.

Por exemplo:

# Atribuição de tuplas
>>> a, b = 1, 2

>>> a
1

>>> b
2

💡 Dica: a atribuição de tuplas normalmente é usada para trocar os valores de duas variáveis:

>>> a = 1

>>> b = 2

# Troca dos valores
>>> a, b = b, a

>>> a
2

>>> b
1

Dicionários em Python

Agora, entraremos no tópico dos dicionários. Esta estrutura de dados integrada nos permite criar pares de valores, onde um valor está associado ao outro.

Para definir um dicionário em Python, usamos chaves {} com pares de chave-valor separados por vírgulas.

A chave é separada do valor por dois pontos :, assim:

{"a": 1, "b": 2, "c"; 3}

Você pode atribuir o dicionário a uma variável:

my_dict = {"a": 1, "b": 2, "c"; 3}

As chaves de um dicionário devem ser de um tipo de dados imutável. Por exemplo, elas podem ser strings, números ou tuplas, mas não listas, já que listas são mutáveis.

  • Strings: {"Cidade 1": 456, "Cidade 2": 577, "Cidade 3": 678}
  • Números: {1: "Mover para a esquerda", 2: "Mover para a direita", 3: "Mover para cima", 4: "Mover para baixo"}
  • Tuplas: {(0, 0): "Início", (2, 4): "Objetivo"}

Os valores de um dicionário, por outro lado, podem ser de qualquer tipo de dados. Assim, podemos atribuir strings, números, listas, tuplas, sets e até mesmo outros dicionários aos valores. Aqui temos alguns exemplos:

{"id_do_produto": 4556, "ingredientes": ["tomate", "queijo", "cogumelos"], "preço": 10.67}
{"id_do_produto": 4556, "ingredientes": ("tomate", "queijo", "cogumelos"), "preco": 10.67}
{"id": 567, "nome": "Emily", "notas": {"Matemática": 80, "Biologia": 74, "Português": 97}}

Tamanho do dicionário

Para obter o número de pares chave-valor, usamos a função len():

>>> meu_dicionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> len(meu_dicionario)
4

Obter um valor em um dicionário

Para obter o valor em um dicionário, usamos sua chave, com essa sintaxe:

<variável_com_dicionário>[<chave>]

Essa expressão será substituída pelo valor que corresponde à chave.

Por exemplo:

meu_dicionario = {"a": 1, "b": 2, "c": 3, "d": 4}

print(meu_dicionario["a"])

O resultado é o valor associado a "a":

1

Atualizar um valor em um dicionário

Para atualizar um valor associado a uma chave existente, usamos a mesma sintaxe, mas agora adicionamos um operador de atribuição e o valor:

<variável_com_dicionário>[<chave>] = <valor>

Por exemplo:

>>> meu_dicionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> meu_dicionario["b"] = 6

Agora temos o seguinte dicionário:

{'a': 1, 'b': 6, 'c': 3, 'd': 4}

Adicionar um par chave-valor a um dicionário

As chaves de um dicionário precisam ser únicas. Para adicionar um novo par chave-valor, usamos a mesma sintaxe que usamos para atualizar um valor, mas agora as chaves precisam ser novas.

<variável_com_dicionário>[<nova_chave>] = <valor>

Por exemplo:

>>> meu_dicionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> meu_dicionario["e"] = 5

Agora, o dicionário tem o novo par chave-valor:

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Excluir um par chave-valor de um dicionário

Para excluir um par chave-valor, usamos a instrução del:

del <variável_com_dicionário>[<chave>]

For example:

>>> meu_dicionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> del meu_dicionario["c"]

Agora, o dicionário será assim:

{'a': 1, 'b': 2, 'd': 4}

Métodos de dicionário

Estes são alguns exemplos dos métodos de dicionários mais comumente usados:

>>> meu_dicionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> meu_dicionario.get("c")
3

>>> meu_dicionario.items()
dict_items([('a', 1), ('b', 2), ('c', 3), ('d', 4)])

>>> meu_dicionario.keys()
dict_keys(['a', 'b', 'c', 'd'])

>>> meu_dicionario.pop("d")
4

>>> meu_dicionario.popitem()
('c', 3)

>>> meu_dicionario.setdefault("a", 15)
1

>>> meu_dicionario
{'a': 1, 'b': 2}

>>> meu_dicionario.setdefault("f", 25)
25

>>> meu_dicionario
{'a': 1, 'b': 2, 'f': 25}

>>> meu_dicionario.update({"c": 3, "d": 4, "e": 5})

>>> meu_dicionario.values()
dict_values([1, 2, 25, 3, 4, 5])

>>> meu_dicionario.clear()

>>> meu_dicionario
{}

Para ler mais sobre métodos de dicionários, recomendo ler este artigo da documentação (em inglês).

🔸 Operadores em Python

Ótimo. Agora que você conhece a sintaxe dos tipos de dados básicos e das estruturas de dados integradas do Python, começaremos a ver os operadores em Python. Eles são essenciais para realizar operações e formar expressões.

Operadores aritméticos em Python

Esses operadores são:

Adição: +

>>> 5 + 6
11

>>> 0 + 6
6

>>> 3.4 + 5.7
9.1

>>> "Hello" + ", " + "World"
'Hello, World'

>>> True + False
1

💡 Dica: os últimos dois exemplos são interessantes, não? Esse operador se comporta de modos diferentes com base no tipo de dados dos operandos.

Quando eles são strings, esse operador concatena as strings. Quando são valores booleanos, ele realiza uma operação específica.

Em Python, True é equivalente a 1 e False é equivalente a 0. É por isso que o resultado é 1 + 0 = 1

Subtração: -

>>> 5 - 6
-1

>>> 10 - 3
7

>>> 5 - 6
-1

>>> 4.5 - 5.6 - 2.3
-3.3999999999999995

>>> 4.5 - 7
-2.5

>>> - 7.8 - 6.2
-14.0

Multiplicação: *

>>> 5 * 6
30

>>> 6 * 7
42

>>> 10 * 100
1000

>>> 4 * 0
0

>>> 3.4 *6.8
23.119999999999997

>>> 4 * (-6)
-24

>>> (-6) * (-8)
48

>>> "Hello" * 4
'HelloHelloHelloHello'

>>> "Hello" * 0
''

>>> "Hello" * -1
''

💡 Dica: você pode "multiplicar" uma string por um número inteiro para repetir a string um número determinado de vezes.

Potenciação: **

>>> 6 ** 8
1679616

>>> 5 ** 2
25

>>> 4 ** 0
1

>>> 16 ** (1/2)
4.0

>>> 16 ** (0.5)
4.0

>>> 125 ** (1/3)
4.999999999999999

>>> 4.5 ** 2.3
31.7971929089206

>>> 3 ** (-1)
0.3333333333333333

Divisão: /

>>> 25 / 5
5.0

>>> 3 / 6
0.5

>>> 0 / 5
0.0

>>> 2467 / 4673
0.5279263856195163

>>> 1 / 2
0.5

>>> 4.5 / 3.5
1.2857142857142858

>>> 6 / 7
0.8571428571428571

>>> -3 / -4
0.75

>>> 3 / -4
-0.75

>>> -3 / 4
-0.75

💡 Dica: esse operador retorna um float como resultado, mesmo que a parte decimal seja .0

Se tentar dividir por 0, você receberá uma mensagem ZeroDivisionError:

>>> 5 / 0
Traceback (most recent call last):
  File "<pyshell#109>", line 1, in <module>
    5 / 0
ZeroDivisionError: division by zero

Divisão de inteiros: //

Esse operador retorna um inteiro se os operandos forem. Se forem floats, o resultado será um float com .0 como a parte decimal, pois ele trunca a parte decimal.

>>> 5 // 6
0

>>> 8 // 2
4

>>> -4 // -5
0

>>> -5 // 8
-1

>>> 0 // 5
0

>>> 156773 // 356
440

Módulo: %

>>> 1 % 5
1

>>> 2 % 5
2

>>> 3 % 5
3

>>> 4 % 5
4

>>> 5 % 5
0

>>> 5 % 8
5

>>> 3 % 1
0

>>> 15 % 3
0

>>> 17 % 8
1

>>> 2568 % 4
0

>>> 245 % 15
5

>>> 0 % 6
0

>>> 3.5 % 2.4
1.1

>>> 6.7 % -7.8
-1.0999999999999996

>>> 2.3 % 7.5
2.3

Operadores de comparação

Esses operadores são:

  • Maior que: >
  • Maior que ou igual a: >=
  • Menor que: <
  • Menor que ou igual a: <=
  • Igual a: ==
  • Não igual a: !=

Esses operadores de comparação criam expressões que resultam em True ou False. Aqui, temos alguns exemplos:

>>> 5 > 6
False

>>> 10 > 8
True

>>> 8 > 8
False

>>> 8 >= 5
True

>>> 8 >= 8
True

>>> 5 < 6
True

>>> 10 < 8
False

>>> 8 < 8
False

>>> 8 <= 5
False

>>> 8 <= 8
True

>>> 8 <= 10
True

>>> 56 == 56
True

>>> 56 == 78
False

>>> 34 != 59
True

>>> 67 != 67
False

Também podemos usá-los para comparar strings com base na ordem alfabética:

>>> "Hello" > "World"
False
>>> "Hello" >= "World"
False
>>> "Hello" < "World"
True
>>> "Hello" <= "World"
True
>>> "Hello" == "World"
False
>>> "Hello" != "World"
True

Tipicamente os usamos para comparar os valores de duas ou mais variáveis:

>>> a = 1
>>> b = 2

>>> a < b
True

>>> a <= b
True

>>> a > b
False

>>> a >= b
False

>>> a == b
False

>>> a != b
True

💡 Dica: observe que o operador de comparação é ==, enquanto o operador de atribuição é =. Seus efeitos são diferente. == retorna True ou False, enquanto = atribui um valor a uma variável.

Encadeamento de operadores de comparação

Em Python, podemos usar algo chamado de "encadeamento de operadores de comparação", para encadearmos os operadores de comparação e tornarmos o processo de fazer mais de uma comparação mais conciso.

Por exemplo, isso verifica se a é menor que b e se b é menor que c:

a < b < c

Aqui temos alguns exemplos:

>>> a = 1
>>> b = 2
>>> c = 3

>>> a < b < c
True

>>> a > b > c
False

>>> a <= b <= c
True

>>> a >= b >= c
False

>>> a >= b > c
False

>>> a <= b < c
True

Operadores lógicos

Existem três operadores lógicos em Python: and, or e not ("e", "ou" e "não", respectivamente). Cada um desses operadores tem sua própria tabela verdade e elas são essenciais para se trabalhar com condicionais.

O operador and:

>>> True and True
True

>>> True and False
False

>>> False and True
False

>>> False and False
False

O operador or:

>>> True or True
True

>>> True or False
True

>>> False or True
True

>>> False or False
False

O operador not:

>>> not True
False

>>> not False
True

Esses operadores são usados para formar expressões mais complexas que combinam operadores e variáveis diferentes.

Por exemplo:

>>> a = 6
>>> b = 3

>>> a < 6 or b > 2
True

>>> a >= 3 and b >= 1
True

>>> (a + b) == 9 and b > 1
True

>>> ((a % 3) < 2) and ((a + b) == 3)
False

Operadores de atribuição

Operadores de atribuição são usados para atribuir um valor a uma variável.

Eles são: =, +=, -=, *=, %=, /=, //=, **=

  • O operador = atribui o valor à variável.
  • Os outros operadores realizam uma operação com o valor atual da variável e o novo valor e atribuem o resultado à mesma variável.

Por exemplo:

>>> x = 3
>>> x
3

>>> x += 15
>>> x
18

>>> x -= 2
>>> x
16

>>> x *= 2
>>> x
32

>>> x %= 5
>>> x
2

>>> x /= 1
>>> x
2.0

>>> x //= 2
>>> x
1.0

>>> x **= 5
>>> x
1.0

💡 Dicas: esses operadores realizam operações bitwise antes de atribuir o resultado à variável: &=, |=, ^=, >>=, <<=.

Operadores de associação

Você pode verificar se um elemento está ou não em uma sequência com os operadores in e not in. O resultado será True ou False.

Por exemplo:

>>> 5 in [1, 2, 3, 4, 5]
True

>>> 8 in [1, 2, 3, 4, 5]
False

>>> 5 in (1, 2, 3, 4, 5)
True

>>> 8 in (1, 2, 3, 4, 5)
False

>>> "a" in {"a": 1, "b": 2}
True

>>> "c" in {"a": 1, "b": 2}
False

>>> "h" in "Hello"
False

>>> "H" in "Hello"
True

>>> 5 not in [1, 2, 3, 4, 5]
False

>>> 8 not in (1, 2, 3, 4, 5)
True

>>> "a" not in {"a": 1, "b": 2}
False

>>> "c" not in {"a": 1, "b": 2}
True

>>> "h" not in "Hello"
True

>>> "H" not in "Hello"
False

Tipicamente, usamos esses operadores com variáveis que armazenam sequências, como neste exemplo:

>>> mensagem = "Hello, World!"

>>> "e" in mensagem
True

🔹 Condicionais em Python

Vejamos agora como podemos escrever condicionais para fazer com que partes do nosso código sejam executadas (ou não) com base em uma condição ser True ou False.

Instruções if em Python

Esta é a sintaxe de uma instrução if básica:

if <condição>:
    <código>

Se a condição for True (verdadeira), o código será executado. Do contrário, se ela for False (falsa), o código não será executado.

💡 Dica: temos dois pontos (:) ao final da primeira linha e o código é indentado (vem depois de alguns espaços ou tabulação). Isso é essencial em Python para fazer com que o código pertença ao condicional.

Aqui temos alguns exemplos:

Condição falsa

x = 5

if x > 9:
    print("Hello, World!")

A condição é x > 9 e o código é print("Hello, World!").

Neste caso, a condição é False, não havendo resultado.

Condição verdadeira

Aqui temos outro exemplo. Agora, a condição é True:

cor = "Azul"

if cor == "Azul":
    print("Essa é a minha cor favorita")

O resultado será:

"Essa é a minha cor favorita"

Código após o condicional

Aqui temos um exemplo com código que será executado após o condicional ter sido concluído. Observe que a última linha não está indentada, ou seja, não pertence ao condicional.

x = 5

if x > 9:
    print("Olá!")

print("Fim")

Neste exemplo, a condição x > 9 é False, então a primeira instrução print não será executada. A segunda instrução print, no entanto, será executada por não ser parte do condicional. O resultado, portanto, é:

Fim

Porém, se o condicional for True, como neste exemplo:

x = 15

if x > 9:
    print("Olá!")

print("Fim")

O resultado será:

Olá!
Fim

Exemplos de condicionais

Este é um outro exemplo de condicional:

estacao_favorita = "Verão"

if estacao_favorita == "Verão":
    print("Essa é a minha estação do ano favorita também!")

Neste caso, o resultado será:

Essa é a minha estação do ano favorita também!

Mas se mudarmos o valor de estacao_favorita:

estacao_favorita = "Inverno"

if estacao_favorita == "Verão":
    print("Essa é a minha estação do ano favorita também!")

Não haverá resultado, pois a condição será False.

Instruções if/else em Python

Podemos adicionar uma instrução else ao condicional se quisermos especificar o que deve acontecer quando a condição é False.

Esta é a sintaxe geral:

if <condição>:
    <código>
else:
    <código>

💡 Dica: observe que os dois blocos de código são indentados (if e else). Isso é essencial para que o Python consiga diferenciar entre o código que pertence ao programa principal e o código que pertence ao condicional.

Vejamos um exemplo com a instrução else:

Condição verdadeira

x = 15

if x > 9:
    print("Olá!")
else:
    print("Tchau!")

print("Fim")

O resultado é:

Olá!
Fim

Quando a condição da instrução if é True, essa instrução é executada. A instrução else não é.

Condição falsa

Por outro lado, a instrução else é executada quando a condição é False.

x = 5

if x > 9:
    print("Olá!")
else:
    print("Tchau!")

print("Fim")

Now the output is:

Tchau!
Fim

Instruções if/elif/else em Python

Para personalizar nossos condicionais ainda mais, podemos adicionar uma ou mais instruções elif para verificar e lidar com diversas condições. Somente o código da primeira condição que é avaliada como True será executada.

💡 Dica: elif precisa ser escrito após o if e antes do else.

Primeira condição verdadeira

x = 5

if x < 9:
    print("Olá!")
elif x < 15:
    print("Que bom ver você!")
else:
    print("Tchau!")

print("Fim")

Temos duas condições, x < 9 e x < 15. Apenas o bloco de código da primeira condição que é True de cima para baixo será executada.

Neste caso, o resultado é:

Olá!
Fim

Isso ocorre pois a primeira condição é True: x < 9.

Segunda condição verdadeira

Se a primeira condição for False, a segunda condição será verificada.

Neste exemplo, a primeira condição x < 9 é False, mas a segunda condição, x < 15, é True. Por isso, o código que pertence a essa instrução será executado.

x = 13

if x < 9:
    print("Olá!")
elif x < 15:
    print("Que bom ver você!")
else:
    print("Tchau!")

print("Fim")

O resultado é:

Que bom ver você!
Fim

Todas as condições são falsas

Se todas as condições forem False, a instrução else será executada:

x = 25

if x < 9:
    print("Olá!")
elif x < 15:
    print("Que bom ver você")
else:
    print("Tchau!")

print("Fim")

O resultado será:

Tchau!
Fim

Várias instruções elif

Podemos adicionar quantas instruções elif quisermos. Este é um exemplo de um condicional com duas instruções elif:

if estacao_favorita == "Inverno":
    print("Essa também é a minha estação favorita")
elif estacao_favorita == "Verão":
    print("O verão é ótimo")
elif estacao_favorita == "Primavera":
    print("Eu adoro a primavera")
else:
    print("O outono é a estação favorita da minha mãe")

Todas as condições serão verificadas e somente o bloco de código da primeira condição avaliada como True será executado. Se nenhuma delas for True, a instrução else será executada.

🔸 Laços for em Python

Agora que você já sabe como escrever condicionais em Python, vamos ver os laços. Os laços for são estruturas de programação incríveis que você pode usar para repetir um bloco de código um número específico de vezes.

Esta é a sintaxe básica de um laço for em Python:

for <variável_de_laço> in <iterável>:
    <código>

O iterável pode ser uma lista, uma tupla, um dicionário, uma string, a sequência retornada por um range (intervalo), um arquivo ou qualquer outro tipo de iterável em Python. Comecemos com o range().

A função range() em Python

Essa função retorna uma sequência de números inteiros que podemos usar para determinar quantas iterações (repetições) do laço serão concluídas. O laço completará uma iteração para cada número inteiro.

💡 Dica: cada número inteiro é atribuído à variável de laço uma vez por iteração.

Esta é a sintaxe geral de um laço for com range():

for <variável_de_laço> in range(<início>, <parada>, <passo>):
    <código>

Como você pode ver, a função range tem três parâmetros:

  • início: onde a sequência de inteiros inicia. Por padrão, o valor é 0.
  • parada: onde a sequência de inteiros é interrompida (sem inclui o último valor).
  • passo: o valor que será adicionado a cada elemento para obter o próximo elemento da sequência. Por padrão, o valor é 1.

Você pode passar 1, 2 ou 3 argumentos para range():

  • Com 1 argumento, o valor é atribuído ao parâmetro parada e os valores padrão para os outros dois parâmetros são usados.
  • Com 2 argumentos, os valores são atribuídos para os parâmetros início e parada e o valor padrão para passo é usado.
  • Com 3 argumentos, os valores são atribuídos para os parâmetros início, parada e passo (em ordem).

Aqui temos uns exemplos com um parâmetro:

for i in range(5):
    print(i)

Resultado:

0
1
2
3
4

💡 Dica: a variável de laço é atualizada automaticamente.

>>> for j in range(15):
    print(j * 2)

Resultado:

0
2
4
6
8
10
12
14
16
18
20
22
24
26
28

No exemplo abaixo, repetimos uma string tantas vezes quantas for indicadopelo valor da variável de laço:

>>> for num in range(8):
	print("Olá" * num)

Resultado:

Olá
OláOlá
OláOláOlá
OláOláOláOlá
OláOláOláOláOlá
OláOláOláOláOláOlá
OláOláOláOláOláOláOlá

Também podemos usar os laços for com estruturas de dados integradas, como listas:

>>> minha_lista = ["a", "b", "c", "d"]

>>> for i in range(len(minha_lista)):
	print(minha_lista[i])

Resultado:

a
b
c
d

💡 Dica: quando você usa range(len(<seq>)), você obtém uma sequência de números que vai de 0 até len(<seq>)-1. Isso representa a sequência de índices válidos.

Aqui estão alguns exemplos com dois parâmetros:

>>> for i in range(2, 10):
	print(i)

Resultado:

2
3
4
5
6
7
8
9

Código:

>>> for j in range(2, 5):
	print("Python" * j)

Resultado:

PythonPython
PythonPythonPython
PythonPythonPythonPython

Código:

>>> minha_lista = ["a", "b", "c", "d"]

>>> for i in range(2, len(minha_lista)):
	print(minha_lista[i])

Resultado:

c
d

Código:

>>> minha_lista = ["a", "b", "c", "d"]

>>> for i in range(2, len(minha_lista)-1):
	minha_lista[i] *= i

Agora, a lista é: ['a', 'b', 'cc', 'd']

Esses são alguns exemplos com três parâmetros:

>>> for i in range(3, 16, 2):
	print(i)

Resultado:

3
5
7
9
11
13
15

Código:

>>> for j in range(10, 5, -1):
	print(j)

Resultado:

10
9
8
7
6

Código:

>>> minha_lista = ["a", "b", "c", "d", "e", "f", "g"]

>>> for i in range(len(minha_lista)-1, 2, -1):
	print(minha_lista[i])

Resultado:

g
f
e
d

Como iterar sobre iteráveis em Python

Podemos iterar (realizar uma sequência de passos) diretamente sobre iteráveis como listas, tuplas, dicionários, strings e arquivos usando laços for. Pegaremos cada um dos elementos, um por vez e por iteração. Isso é bastante útil para trabalhar com cada um dos elementos diretamente.

Vejamos alguns exemplos:

Iterar por uma string

Para iterar por uma string, seus caracteres serão atribuídos à variável de laço, um por vez (incluindo espaços e símbolos).

>>> mensagem = "Olá, mundo!"

>>> for char in mensagem:
	print(char)

	
O
l
á
,
 
m
u
n
d
o
!

Podemos também iterar sobre cópias modificadas da string chamando o método de string onde especificamos o iterável no laço for. Isso atribuirá uma cópia da string como iterável que será usada para as iterações, desse modo:

>>> word = "Hello"

>>> for char in word.lower(): # calling the string method
	print(char)

	
h
e
l
l
o
>>> palavra = "Olá"

>>> for char in palavra.upper(): # chamando o método de string
	print(char)

	
O
L
Á

Iterar sobre listas e tuplas

>>> minha_lista = [2, 3, 4, 5]

>>> for num in minha_lista:
	print(num)

O resultado é:

2
3
4
5

Código:

>>> minha_lista = (2, 3, 4, 5)

>>> for num in minha_lista:
	if num % 2 == 0:
		print("Par")
	else:
		print("Ímpar")

Resultado:

Par
Ímpar
Par
Ímpar

Iterar sobre as chaves, valores e pares chave-valor de dicionários

Podemos iterar sobre as chaves, valores e pares chave-valor de um dicionário chamando métodos de dicionário específicos. Vejamos como fazer isso.

Para iterar sobre as chaves, escrevemos:

for <var> in <variável_de_dicionário>:
    <código>

Simplesmente escrevemos o nome da variável que armazena o dicionário como o iterável.

💡 Dica: você também pode escrever <variável_de_dicionário>.keys(). Porém, escrever o nome da variável diretamente é mais conciso e funciona da mesma maneira.

Por exemplo:

>>> meu_dicionário = {"a": 1, "b": 2, "c": 3}

>>> for chave in meu_dicionário:
	print(chave)

	
a
b
c

💡 Dica: você pode atribuir qualquer nome válido à variável de laço.

Para iterar sobre os valores, usamos:

for <var> in <variável_de_dicionário>.values():
    <código>

For example:

>>> meu_dicionário = {"a": 1, "b": 2, "c": 3}

>>> for valor in meu_dicionário.values():
	print(valor)

	
1
2
3

Para iterar sobre os pares chave-valor, usamos:

for <chave>, <valor> in <variável_de_dicionário>.items():
    <código>

💡 Dica: estamos definindo duas variáveis de laço, pois queremos atribuir a chave e o valor às variáveis que podemos usar no laço.

>>> meu_dicionário = {"a": 1, "b": 2, "c": 3}

>>> for chave, valor in meu_dicionário.items():
	print(chave, valor)

	
a 1
b 2
c 3

Se definirmos somente uma variável do laço, essa variável terá uma tupla com o par chave-valor:

>>> meu_dicionário = {"a": 1, "b": 2, "c": 3}
>>> for par in meu_dicionário.items():
	print(par)

	
('a', 1)
('b', 2)
('c', 3)

Break e continue em Python

Agora você sabe como iterar sobre sequências em Python. Também temos instruções de controle de laços para personalizar o que acontece quando o laço é executado: break e continue.

A instrução break

A instrução break é usada para interromper o laço imediatamente.

Quando uma instrução break é encontrada, o laço para e o programa volta à sua execução normal após o laço.

No exemplo abaixo, paramos o laço quando um elemento par é encontrado.

>>> minha_lista = [1, 2, 3, 4, 5]

>>> for elemento in minha_lista:
	if elemento % 2 == 0:
		print("Par:", elemento)
		print("break")
		break
	else:
		print("Ímpar:", elemento)

		
Ímpar: 1
Par: 2
break

A instrução continue

A instrução continue é usada para ignorar o resto da iteração atual.

Quando encontrada durante a execução do laço, a iteração atual para e uma nova começa com o valor atualizado da variável de laço.

No exemplo abaixo, paramos a iteração atual do elemento se o elemento for par, imprimindo o valor apenas se o elemento for ímpar:

>>> minha_lista = [1, 2, 3, 4, 5]

>>> for elemento in minha_lista:
	if elemento % 2 == 0:
		print("continue")
		continue
	print("Ímpar:", elemento)

	
Ímpar: 1
continue
Ímpar: 3
continue
Ímpar: 5

A função zip() em Python

zip() é uma função integrada incrível que podemos usar em Python para iterar sobre varias sequências ao mesmo tempo, obtendo seus elementos correspondentes em cada iteração.

Precisamos apenas passar as sequências como argumentos para a função zip() e usar esse resultado no laço.

Por exemplo:

>>> minha_lista1 = [1, 2, 3, 4]
>>> minha_lista2 = [5, 6, 7, 8]

>>> for elem1, elem2 in zip(minha_lista1, minha_lista2):
	print(elem1, elem2)

	
1 5
2 6
3 7
4 8

A função enumerate() em Python

Você também pode acompanhar um contador enquanto o laço é executado com a função enum(). Ela é comumente usada para iterar sobre uma sequência e obter o índice correspondente.

💡 Dica: por padrão, o contador começa em 0.

Por exemplo:

>>> minha_lista = [5, 6, 7, 8]

>>> for i, elem in enumerate(minha_lista):
	print(i, elem)

	
0 5
1 6
2 7
3 8
>>> palavra = "Olá"

>>> for i, char in enumerate(palavra):
	print(i, char)

	
0 O
1 l
2 á

Se você começa o contador do 0, pode usar o índice e o valor atual na mesma iteração para modificar a sequência:

>>> minha_lista = [5, 6, 7, 8]

>>> for índice, num in enumerate(minha_lista):
	minha_lista[índice] = num * 3

>>> minha_lista
[15, 18, 21, 24]

Você pode começar o contador de um número diferente passando um segundo argumento para enumerate():

>>> palavra = "Olá"

>>> for i, char in enumerate(palavra, 2):
	print(i, char)

	
2 O
3 l
4 á

A instrução else

Os laços for também têm uma instrução else. Você pode adicionar essa instrução ao laço se quiser executar um bloco de código específico quando o laço completa todas as suas iterações sem encontrar a instrução break.

💡 Dica: se break for encontrado, a instrução else não é executada. Se break não for encontrado, else é executado.

No exemplo abaixo, tentamos encontrar um elemento maior que 6 na lista. O elemento não é encontrado, break não é executado e a instrução else é executada em seu lugar.

minha_lista = [1, 2, 3, 4, 5]

for elem in minha_lista:
    if elem > 6:
        print("Encontrado")
        break
else:
    print("Não encontrado")

O resultado é:

Não encontrado

Porém, se a instrução break for executada, a instrução else não será. Podemos ver isso no exemplo abaixo:

minha_lista = [1, 2, 3, 4, 5, 8] # Agora a lista tem o valor 8

for elem in minha_lista:
    if elem > 6:
        print("Encontrado")
        break
else:
    print("Não encontrado")

O resultado é:

Encontrado

🔹 Laços while em Python

Os laços while são semelhantes aos laços for, pois nos deixam repetir um bloco de código. A diferença está no fato de que o laço while é executado enquanto uma condição for True.

Em um laço while, definimos a condição, não o número de iterações. O laço para quando a condição for False.

Essa é a sintaxe geral de um laço while:

while <condição>:
    <código>

💡 Dica: nos laços while, você precisa atualizar as variáveis que são parte da condição para garantir que a condição, em algum momento, se torne False.

Por exemplo:

>>> x = 6

>>> while x < 15:
	print(x)
	x += 1

	
6
7
8
9
10
11
12
13
14
>>> x = 4

>>> while x >= 0:
	print("Olá" * x)
	x -= 1

	
OláOláOláOlá
OláOláOlá
OláOlá
Olá
>>> num = 5

>>> while num >= 1:
	print("*" * num)
	num -= 2

	
*****
***
*

Break e continue

Também podemos usar break e continue com os laços while e eles funcionam da mesma maneira:

  • break para o laço while imediatamente.
  • continue para a iteração atual e começa uma nova.

Por exemplo:

>>> x = 5

>>> while x < 15:
	if x % 2 == 0:
		print("Par:", x)
		break
	print(x)
	x += 1
    

5
Par: 6
>>> x = 5

>>> while x < 15:
	if x % 2 == 0:
		x += 1
		continue
	print("Ímpar:", x)
	x += 1

	
Ímpar: 5
Ímpar: 7
Ímpar: 9
Ímpar: 11
Ímpar: 13

A instrução else

Também podemos adicionar uma instrução else a um laço while. Se break for encontrado, a instrução else não é executada, mas se for encontrado, a instrução else é executada.

No exemplo abaixo, a instrução break não é encontrada, pois nenhum dos números é par antes de a condição se tornar False. Por isso, a instrução else é executada.

x = 5

while x < 15:
	if x % 2 == 0:
		print("Número par encontrado")
		break
	print(x)
	x += 2
else:
	print("Todos os números eram ímpares")

Este é o resultado

5
7
9
11
13
Todos os números eram ímpares

Porém, nesta versão do exemplo, a instrução break é encontrada e a instrução else não é executada:

x = 5

while x < 15:
	if x % 2 == 0:
		print("Número par encontrado")
		break
	print(x)
	x += 1 # Agora, estamos aumentando o valor de 1 em 1
else:
	print("Todos os números eram ímpares")

O resultado é:

5
Número par encontrado

Laços while infinitos

Quando escrevemos e trabalhamos com laços while, podemos encontrar algo que chamamos de "laço infinito". Se a condição nunca for False, o laço nunca será interrompido sem intervenção externa.

Isso geralmente acontece quando as variáveis na condição não são atualizadas adequadamente durante a execução do laço.

💡 Dica: você deve fazer as atualizações necessárias a essas variáveis para garantir que a condição em algum momento se tornará False.

Por exemplo:

>>> x = 5

>>> while x > 2:
	print(x)

	
5
5
5
5
5
5
5
5
5
.
.
.
# O resultado seguirá indefinidamente

💡 Dica: para interromper esse processo, digite CTRL + C. Você verá uma mensagem KeyboardInterrupt.

🔸 Laços aninhados em Python

Podemos escrever laços for dentro de laços for e laços while dentro de laços while. Esses laços internos são chamados de laços aninhados.

💡 Dica: o laço interno executa para cada iteração do laço externo.

Laços for aninhados em Python

>>> for i in range(3):
	for j in range(2):
		print(i, j)

		
0 0
0 1
1 0
1 1
2 0
2 1

Se adicionarmos instruções print, podemos ver o que está acontecendo por debaixo dos panos:

>>> for i in range(3):
	print("===> Laço externo")
	print(f"i = {i}")
	for j in range(2):
		print("Laço interno")
		print(f"j = {j}")

		
===> Laço externo
i = 0
Laço interno
j = 0
Laço interno
j = 1
===> Laço externo
i = 1
Laço interno
j = 0
Laço interno
j = 1
===> Laço externo
i = 2
Laço interno
j = 0
Laço interno
j = 1

O laço interno completa duas iterações para cada iteração do laço externo. As variáveis de laço são atualizadas quando uma nova iteração é iniciada.

Aqui temos outro exemplo:

>>> num_linhas = 5

>>> for i in range(5):
	for num_colunas in range(num_linhas-i):
		print("*", end="")
	print()

	
*****
****
***
**
*

Laços while aninhados em Python

Aqui temos um exemplo de laços while aninhados. Neste caso, temos que atualizar as variáveis que são parte de cada condição para garantir que os loops serão interrompidos.

>>> i = 5

>>> while i > 0:
	j = 0
	while j < 2:
		print(i, j)
		j += 1
	i -= 1

	
5 0
5 1
4 0
4 1
3 0
3 1
2 0
2 1
1 0
1 1

💡 Dica: também podemos ter laços for dentro de laços while e laços while dentro de laços for.

🔹 Funções em Python

Em Python, podemos definir funções para tornar nosso código reutilizável, mais legível e organizado. Esta é a sintaxe básica de uma função em Python:

def <nome_da_função>(<parâmetro1>, <parâmetro2>, ...):
    <código>

💡 Dica: uma função pode ter zero, um ou vários parâmetros.

Função sem parâmetros em Python

Uma função sem parâmetros tem um par de parênteses vazios após seu nome na definição da função. Por exemplo:

def imprimir_padrao():
    tamanho = 4
    for i in range(tamanho):
        print("*" * tamanho)

Este é o resultado quando chamamos a função:

>>> imprimir_padrao()
****
****
****
****

💡 Dica: você precisa escrever o par vazio de parênteses depois do nome da função para poder chamá-la.

Função com um parâmetro em Python

Uma função com um ou mais parâmetros tem uma lista de parâmetros cercados por parênteses após seu nome na definição da função:

def boasvindas_estudante(nome):
    print(f"Olá, {nome}! Boas-vindas à aula.")

Quando chamamos a função, precisamos apenas passar um valor como argumento e o valor será substituído por aquele que usarmos no parâmetro na definição da função:

>>> boasvindas_estudante("Nora")
Olá, Nora! Boas-vindas à aula.

Aqui temos outro exemplo – uma função que imprime um padrão feito de asteriscos. Você precisa especificar quantas linhas quer imprimir:

def imprimir_padrao(num_linhas):
    for i in range(num_linhas):
        for num_colunas in range(num_linhas-i):
            print("*", end="")
        print()

Você pode ver resultados diferentes para valores diferentes de num_linhas:

>>> imprimir_padrao(3)
***
**
*

>>> imprimir_padrao(5)
*****
****
***
**
*

>>> imprimir_padrao(8)
********
*******
******
*****
****
***
**
*

Funções com dois ou mais parâmetros em Python

Para definir dois ou mais parâmetros, apenas separamos os parâmetros com vírgulas:

def imprime_soma(a, b):
    print(a + b)

Agora, ao chamar a função, devemos passar dois argumentos:

>>> imprime_soma(4, 5)
9

>>> imprime_soma(8, 9)
17

>>> imprime_soma(0, 0)
0

>>> imprime_soma(3, 5)
8

Podemos adaptar a função que vimos há pouco com um parâmetro para que funcione com dois parâmetros e imprimir um padrão com um caractere personalizado:

def imprimir_padrao(num_linhas, caractere):
	for i in range(num_linhas):
		for num_colunas in range(num_linhas-i):
			print(caractere, end="")
		print()

Você pode ver que o resultado com o caractere personalizado é o que ocorre ao chamarmos a função passando dois argumentos:

>>> imprimir_padrao(5, "A")
AAAAA
AAAA
AAA
AA
A

>>> imprimir_padrao(8, "%")
%%%%%%%%
%%%%%%%
%%%%%%
%%%%%
%%%%
%%%
%%
%

>>> imprimir_padrao(10, "#")
##########
#########
########
#######
######
#####
####
###
##
#

Como retornar um valor em Python

Ótimo. Agora que você já sabe definir uma função, vamos ver como você pode trabalhar com instruções de retorno de valores.

Precisamos com frequência retornar um valor a partir de uma função. Podemos fazer isso com a instrução return em Python. Precisamos apenas escrever isso no corpo da função:

return <valor_a_retornar>

💡 Dica: a função é interrompida imediatamente quando encontra return e o valor é retornado.

Aqui temos um exemplo:

def obter_area_do_retangulo(largura, comprimento):
    return largura * comprimento

Agora, chamamos a função e atribuímos o resultado a uma variável, pois o resultado é retornado pela função:

>>> area = obter_area_do_retangulo(4, 5)
>>> area
20

Também podemos usar return com um condicional para retornar um valor com base em uma condição ser True ou False.

Neste exemplo, a função retorna o primeiro elemento par encontrado na sequência:

def obter_primeiro_par(seq):
    for elem in seq:
        if elem % 2 == 0:
            return elem
        else:
            return None

Se chamamos a função, veremos os resultados esperados:

>>> valor1 = obter_primeiro_par([2, 3, 4, 5])
>>> valor1
2
>>> valor2 = obter_primeiro_par([3, 5, 7, 9])
>>> print(valor2)
None

💡 Dica: se uma função não tiver uma instrução return ou não encontrar uma durante a execução, ela retorna None (nenhum elemento encontrado) por padrão.

O Guia de estilo para o código em Python  (em inglês, mas também pode ser encontrado em português aqui) recomenda usar instruções de retorno consistentemente. Ele menciona que devemos:

Ser consistentes nas instruções return. Ou todas as instruções return em uma função devem retornar uma expressão, ou nenhuma delas. Se alguma instrução return retornar uma expressão, qualquer instrução return onde nenhum valor é retornado deve explicitamente declarar isso como return None, e uma instrução explícita de retorno deve estar presente ao final da função (se o final for atingível)

Argumentos padrão em Python

Podemos atribuir argumentos padrão para os parâmetros de nossas funções. Para fazer isso, precisamos apenas escrever <parâmetro>=<valor> na lista de parâmetros.

💡 Dica: o Guia de estilo para o código em Python (em inglês, ver acima) menciona que não devemos "usar espaços ao redor do sinal de igual (=) quando ele for usado para indicar um argumento de palavra-chave."

Neste exemplo, atribuímos o valor padrão 5 ao parâmetro b. Se omitirmos esse valor ao chamar a função, o valor padrão será usado.

def imprimir_produto(a, b=5):
    print(a * b)

Se chamarmos a função sem esse argumento, veremos o seguinte resultado:

>>> imprimir_produto(4)
20

Confirmamos que o argumento padrão 5 foi usado na operação.

Também podemos atribuir um valor personalizado para b passando um segundo argumento:

>>> imprimir_produto(3, 4)
12

💡 Dica: parâmetros com argumentos padrão têm de ser definidos ao final da lista de parâmetros. Do contrário, você verá este erro: SyntaxError: non-default argument follows default argument.

Aqui temos outro exemplo com a função que escrevemos para imprimir um padrão. Atribuímos o valor padrão "*" ao parâmetro char.

def imprimir_padrao(num_linhas, char="*"):
	for i in range(num_linhas):
		for num_colunas in range(num_linhas-i):
			print(char, end="")
		print()

Agora, temos a opção de usar o valor padrão ou de personalizá-lo:

>>> imprimir_padrao(5)
*****
****
***
**
*

>>> imprimir_padrao(6, "&")
&&&&&&
&&&&&
&&&&
&&&
&&
&

🔸 Recursão em Python

Uma função recursiva em Python é uma função que chama a si mesma. Essas funções têm um caso base que interrompe o processo recursivo e um caso recursivo que continua o processo recursivo fazendo outra chamada recursiva.

Aqui temos alguns exemplos em Python:

def fatorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * fatorial(n-1)
Função fatorial recursiva
def fibonacci(n):
    if n == 0 or n == 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)
Função de Fibonacci
def encontrar_potencia(a, b):
    if b == 0:
        return 1
    else:
        return a * encontrar_potencia(a, b-1)
Encontrar uma potência recursivamente

🔹 Tratamento de exceções em Python

Um erro ou evento inesperado que ocorre enquanto um programa está em execução é chamado de exceção. Graças aos elementos que veremos em instantes, podemos evitar de encerrar o programa de modo abrupto quando isso ocorre.

Vamos ver os tipos de exceções em Python e como lidar com elas.

Exceções comuns em Python

Esta é uma lista de exceções comuns em Python e dos motivos para que ocorram:

  • ZeroDivisionError: surge quando o segundo argumento de uma divisão ou operação de módulo é um zero.
>>> 5 / 0
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    5 / 0
ZeroDivisionError: division by zero

>>> 7 // 0
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    7 // 0
ZeroDivisionError: integer division or modulo by zero

>>> 8 % 0
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    8 % 0
ZeroDivisionError: integer division or modulo by zero
  • IndexError: surge quando tentamos usar um índice inválido para acessar um elemento de uma sequência.
>>> minha_lista = [3, 4, 5, 6]

>>> minha_lista[15]
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    minha_lista[15]
IndexError: list index out of range
  • KeyError: surge quando tentamos acessar um par chave-valor que não existe, pois a chave não está no dicionário.
>>> meu_dicionario = {"a": 1, "b": 2, "c": 3}

>>> meu_dicionario["d"]
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    my_dict["d"]
KeyError: 'd'
  • NameError: surge quando usamos uma variável que não foi definido anteriormente.
>>> b
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    b
NameError: name 'b' is not defined
  • RecursionError: surge quando o interpretador detecta que a profundidade máxima de recursão é excedida. Isso geralmente ocorre quando o processo nunca chega ao caso base.

No exemplo abaixo, obtemos um RecursionError. A função fatorial é implementado recursivamente, mas o argumento passado à chamada recursiva é n em vez de n-1. A menos que o valor já seja 0 ou 1, não se chegará ao caso base, pois o argumento não é reduzido, então o processo continuará indefinidamente e chegaremos a esse erro.

>>> def fatorial(n):
	if n == 0 or n == 1:
		return 1
	else:
		return n * fatorial(n)

	
>>> fatorial(5)
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    fatorial(5)
  File "<pyshell#5>", line 5, in fatorial
    return n * fatorial(n)
  File "<pyshell#5>", line 5, in fatorial
    return n * fatorial(n)
  File "<pyshell#5>", line 5, in fatorial
    return n * fatorial(n)
  [Previous line repeated 1021 more times]
  File "<pyshell#5>", line 2, in fatorial
    if n == 0 or n == 1:
RecursionError: maximum recursion depth exceeded in comparison

💡 Dica: para aprender mais sobre essas exceções, recomendo ler esse artigo (em inglês) da documentação.

try / except em Python

Podemos usar try/except em Python para pegar as exceções quando elas ocorrem e tratar delas apropriadamente. Dessa maneira, o problema pode ser encerrado adequadamente ou até mesmo conseguir recuperar o programa da exceção.

Esta é a sintaxe básica:

try:
    <código_que_pode_gerar_a_exceção>
except:
    <código_para_tratar_a_exceção_quando_ela_ocorre>

Por exemplo, se recebermos dados do usuário para acessar um elemento de uma lista, a entrada do usuário pode não ser um índice válido, o que geraria uma exceção:

indice = int(input("Insira o índice: "))

try:
    minha_lista = [1, 2, 3, 4]
    print(minha_lista[indice])
except:
    print("Insira um índice válido.")

Se inserirmos um valor inválido, como 15, o resultado será:

Insira um índice válido.

Isso ocorre porque a instrução except é executada. No entanto, se o valor for válido, o código em try executará conforme o esperado.

Aqui temos um outro exemplo:

a = int(input("Insira a: "))
b = int(input("Insira b: "))

try:
    divisao = a / b
    print(divisao)
except:
    print("Insira valores válidos.")

O resultado é:

Insira a: 5
Insira b: 0

Insira valores válidos.

Como pegar um tipo específico de exceção em Python

Em vez de pegar e tratar todos os tipos possíveis de exceção que possam ocorrer na instrução try, podemos pegar e tratar um tipo específico de exceção. Precisamos apenas especificar o tipo de exceção após a palavra-chave except:

try:
    <código_que_pode_gerar_uma_exceção>
except <tipo_de_exceção>:
    <código_para_lidar_com_uma_exceção_se_ela_ocorrer>

Por exemplo

indice = int(input("Insira o índice: "))

try:
    minha_lista = [1, 2, 3, 4]
    print(minha_lista[índice])
except IndexError: # especifica o tipo
    print("Insira um índice válido.")
a = int(input("Insira a: "))
b = int(input("Insira b: "))

try:
    divisao = a / b
    print(divisao)
except ZeroDivisionError: # especifica o tipo
    print("Insira valores válidos.")

Como atribuir um nome ao objeto de exceção em Python

Podemos especificar um nome para o objeto de exceção atribuindo-o a uma variável que podemos usar na instrução except. Isso nos permitirá acessar sua descrição e atributos.

Precisamos apenas adicionar as <nome>, assim:

try:
    <código_que_pode_gerar_uma_exceção>
except <tipo_de_exceção> as <nome>:
    <código_para_lidar_com_uma_exceção_se_ela_ocorrer>

Por exemplo:

indice = int(input("Insira o índice: "))

try:
    minha_lista = [1, 2, 3, 4]
    print(minha_lista[indice])
except IndexError as e:
    print("Exceção causada:", e)

Este é o resultado se inserirmos 15 como o índice:

Insira o índice: 15
Exceção causada: list index out of range

Este é um outro exemplo:

a = int(input("Insira a: "))
b = int(input("Insira b: "))

try:
    divisao = a / b
    print(divisao)
except ZeroDivisionError as err:
    print("Insira valores válidos.", err)

Este é o resultado se inserirmos o valor 0 para b:

Insira valores válidos. division by zero

try / except / else em Python

Podemos adicionar uma instrução else a essa estrutura após o except se quisermos escolher o que acontece quando não ocorrerem exceções durante a execução da instrução try:

try:
    <código_que_pode_gerar_uma_exceção>
except:
    <código_para_lidar_com_uma_exceção_se_ela_ocorrer>
else:
    <código_que_só_é_executado_se_não_houver_exceção_no_bloco_try>

Por exemplo:

a = int(input("Insira a: "))
b = int(input("Insira b: "))

try:
    divisao = a / b
    print(divisao)
except ZeroDivisionError as err:
    print("Insira valores válidos.", err)
else:
    print("Os dois valores eram válidos.")

Se inserirmos os valores 5 e 0 para a e b respectivamente, o resultado é:

Insira valores válidos. division by zero

Se os dois valores forem válidos, no entanto, como 5 e 4 para a e b respectivamente, por exemplo, a instrução else será executada após try ser concluído e veremos:

1.25
Os dois valores eram válidos.

try / except / else / finally em Python

Se também adicionarmos uma instrução finally quando a intenção é adicionar um código que seja executado sempre, mesmo que uma exceção ocorra em try.

Por exemplo:

a = int(input("Insira a: "))
b = int(input("Insira b: "))

try:
    divisao = a / b
    print(divisao)
except ZeroDivisionError as err:
    print("Insira valores válidos.", err)
else:
    print("Os dois valores eram válidos.")
finally:
    print("O programa terminou!")

Se os dois valores eram válidos, é mostrado o resultado da divisão e mais as seguintes mensagens:

Os dois valores eram válidos.
O programa terminou!

Se tivermos uma exceção pelo fato de b ser 0, teremos:

Insira valores válidos. division by zero
O programa terminou!

Como se pode ver, a instrução finally é executada sempre.

💡 Dica: essa instrução pode ser usada, por exemplo, para fechar arquivos mesmo que o código lance uma exceção.

🔸 Programação orientada a objetos em Python

Na Programação Orientada a Objetos (POO – ou OOP, em inglês), definimos classes que agem como "mapas" para a criação de objetos em Python, com atributos e métodos (funcionalidades associadas aos objetos).

Esta é a sintaxe geral para definir uma classe:

class <nomeDaClasse>:

    <nome_do_atributo_da_classe> = <valor>

    def __init__(self,<param1>, <param2>, ...):
        self.<attr1> = <param1>
        self.<attr2> = <param2>
        .
        .
        .
        # Tantos atributos quantos necessários
    
   def <nome_do_método>(self, <param1>, ...):
       <código>
       
   # Tantos métodos quantos necessários

💡 Dica: self se refere a uma instância da classe (um objeto criado com o "mapa" da classe).

Como você pode ver, uma classe pode ter diferentes elementos. Vamos analisá-los em detalhes:

Cabeçalho da classe

A primeira linha da definição da classe tem a palavra-chave class e o nome da classe:

class Cachorro:
class Casa:
class Bola:

💡 Dica: se a classe herdar atributos e métodos de outra classe, veremos o nome dessa classe entre parênteses:

class Poodle(Cachorro):
class Caminhao(Veiculo):
class Mae(MembroDaFamilia):

Em Python, escrevemos o nome da classe em Camel Case e letras maiúsculas iniciais (também conhecido como Pascal Case). Por exemplo: MembroDaFamilia

__init__ e atributos de instância

Vamos usar a classe para criar um objeto em Python, assim como usamos uma planta para construir uma casa de verdade.

Os objetos terão atributos que definiremos na classe. Em geral, inicializamos esses atributos em __init__. Este é um método que é executado quando criamos uma instância da classe.

Esta é a sintaxe geral:

def __init__(self, <parâmetro1>, <parâmetro2>, ...):
        self.<atributo1> = <parâmetro1>  # Atributo da instância
        self.<atributo2> = <parâmetro2>  # Atributo da instância
        .
        .
        .
        # Tantos atributos da instância quantos forem necessários

Especificamos tantos parâmetros quantos forem necessários para personalizar os valores dos atributos de objeto que serão criados.

Aqui está um exemplo da classe Cachorro com esse método:

class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

💡 Dica: perceba as duas sublinhas antes e depois de __init__.

Como criar uma instância

Para criar uma instância de Cachorro, precisamos especificar o nome e a idade da instância do cachorro para atribuir esses valores aos atributos:

meu_cachorro = Cachorro("Nora", 10)

Ótimo. Agora, temos nossa instância pronta para ser usada no programa.

Algumas classes não exigem argumentos para criar uma instância. Nesse caso, simplesmente escrevemos os parênteses vazios. Por exemplo:

class Circulo:

    def __init__(self):
        self.raio = 1

Para criar uma instância:

>>> meu_circulo = Circulo()

💡 Dica: self é como um parâmetro que age "por debaixo dos panos". Então, mesmo que você o veja na definição do método, não deve considerá-lo ao passar os argumentos.

Argumentos padrão

Também podemos atribuir valores padrão para os atributos e dar ao usuário a opção se ele quiser personalizar o valor.

Neste caso, escreveríamos <atributo>=<valor> na lista de parâmetros.

Este é um exemplo:

class Circulo:

    def __init__(self, raio=1):
        self.raio = raio

Agora, podemos criar uma instância de Circulo com o valor padrão para o raio, omitindo o valor, ou personalizando-o, passando um valor:

# Valor padrão
>>> meu_circulo1 = Circulo()

# Valor personalizado
>>> meu_circulo2 = Circulo(5)

Como acessar um atributo de instância

Para acessar um atributo de uma instância, usamos a seguinte sintaxe:

<variável_de_objeto>.<atributo>

Por exemplo:

# Definição de classe
>>> class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

# Criar instância        
>>> meu_cachoro = Cachorro("Nora", 10)

# Acessar atributo
>>> meu_cachorro.nome
'Nora'

>>> meu_cachorro.idade
10

Como atualizar um atributo de instância

Para atualizar um atributo de uma instância, usamos esta sintaxe:

<variável_de_objeto>.<atributo> = <novo_valor>

Por exemplo:

>>> class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

        
>>> meu_cachorro = Cachorro("Nora", 10)

>>> meu_cachorro.nome
'Nora'

# Atualizar o atributo
>>> meu_cachorro.nome = "Norinha"

>>> meu_cachorro.nome
'Norinha'

Como remover um atributo de instância

Para remover um atributo de instância, usamos esta sintaxe:

del <variável_de_objeto>.<atributo>

Por exemplo:

>>> class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

        
>>> meu_cachorro = Cachorro("Nora", 10)

>>> meu_cachorro.nome
'Nora'

# Excluir este atributo
>>> del meu_cachorro.nome

>>> meu_cachorro.nome
Traceback (most recent call last):
  File "<pyshell#77>", line 1, in <module>
    meu_cachorro.nome
AttributeError: 'Cachorro' object has no attribute 'nome'

Como excluir uma instância

Do mesmo modo, podemos excluir uma instância usando del:

>>> class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

        
>>> meu_cachorro = Cachorro("Nora", 10)

>>> meu_cachorro.nome
'Nora'

# Excluir a instância
>>> del meu_cachorro

>>> meu_cachorro
Traceback (most recent call last):
  File "<pyshell#79>", line 1, in <module>
    meu_cachorro
NameError: name 'meu_cachorro' is not defined

Atributos públicos e não públicos em Python

Em Python, não temos modificadores de acesso para restringir o acesso de modo funcional aos atributos de instância. Assim, precisamos confiar nas convenções de nomenclatura para especificar isso.

Por exemplo, ao adicionar uma sublinha antes de um atributo, sinalizamos aos outros desenvolvedores que esse atributo não deve ser público.

Por exemplo:

class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome  # Atributo público
        self._idade = idade   # Atributo não público

A documentação do Python menciona o seguinte:

Use uma sublinha antes do atributo somente para métodos e variáveis de instância não públicas.

Sempre decida se os métodos e variáveis de instância de uma classe (coletivamente chamados de "atributos") devem ser públicos ou não. Se estiver em dúvida, escolha não públicos. É mais fácil tornar público mais tarde do que tornar não público um atributo que é público.

Atributos não públicos são aqueles que não devem ser usados por terceiros; você não garante que atributos não públicos não possam mudar ou até ser removidos. - fonte em inglês

Porém, como também menciona a documentação:

Não usamos o termo "privado" aqui, pois nenhum atributo é privado de fato em Python (sem uma quantidade em geral desnecessária de trabalho). - fonte em inglês

💡 Dica: tecnicamente, ainda podemos acessar e modificar o atributo se quisermos adicionar a sublinha antetes de seu nome, mas não é recomendado fazer isso.

Atributos de classe em Python

Atributos de classe são compartilhados por todas as instâncias da classe. Todas elas têm acesso a esse atributo e também serão afetadas por quaisquer mudanças feitas a esses atributos.

class Cachorro:

    # Atributos de classe
    reino = "Animalia"
    especie = "Canis lupus"

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

💡 Dica: em geral, esses atributos são escritos antes do método __init__.

Como acessar um atributo de classe

Para acessar o atributo de classe, usamos essa sintaxe:

<nome_da_classe>.<atributo>

Por exemplo:

>>> class Cachorro:

    reino = "Animalia"

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

        
>>> Cachorro.reino
'Animalia'

💡 Dica: você pode usar essa sintaxe dentro da própria classe.

Como atualizar um atributo de classe

Para atualizar um atributo de classe, usamos esta sintaxe:

<nome_da_classe>.<atributo> = <valor>

Por exemplo:

>>> class Cachorro:

    reino = "Animalia"

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

        
>>> Cachorro.reino
'Animalia'

>>> Cachorro.reino = "Novo reino"

>>> Cachorro.reino
'Novo reino'

Como excluir um atributo de classe

Usamos del para excluir um atributo de classe. Por exemplo:

>>> class Cachorro:

    reino = "Animalia"

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

>>> Cachorro.reino
'Animalia'
        
# Excluir o atributo de classe
>>> del Cachorro.reino

>>> Cachorro.reino
Traceback (most recent call last):
  File "<pyshell#88>", line 1, in <module>
    Cachorro.reino
AttributeError: type object 'Cachorro' has no attribute 'reino'

Como definir métodos

Métodos representam a funcionalidade das instâncias de classe.

💡 Dica: métodos de instância podem funcionar com os atributos de instância que chamam o método se escrevermos self.<atributo> na definição do método.

Esta é a sintaxe básica de um método em uma classe. Eles geralmente estão localizados abaixo de __init__:

class <NomeDaClasse>:

    # Atributos da classe

    # __init__

    def <nome_do_método>(self, <param1>, ...):
        <código>

Eles podem ter zero,um ou mais parâmetros se necessário (como as funções!), mas métodos de instância devem sempre ter self como o primeiro parâmetro.

Por exemplo, este é o método latir sem parâmetros (além de self):

class Cachorro:

    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

    def latir(self):
        print(f"au-au. Meu nome é {self.nome}")

Para chamar esse método, usamos a seguinte sintaxe:

<variável_de_objeto>.<método>(<argumentos>)

Por exemplo:

# Criar a instância
>>> meu_cachorro = Cachorro("Nora", 10)

# Chamar o método
>>> meu_cachorro.latir()
au-au. Meu nome é Nora

Aqui temos uma classe Jogador com um método aumentar_velocidade com um parâmetro:

class Jogador:

    def __init__(self, nome):
        self.nome = nome
        self.velocidade = 50

    def aumentar_velocidade(self, valor):
        self.velocidade += valor

Para chamar o método:

# Criar instância        
>>> meu_jogador = Jogador("Nora")

# Verificar a velocidade inicial para ver a mudança
>>> meu_jogador.velocidade
50

# Aumentar a velocidade
>>> meu_jogador.aumentar_velocidade(5)

# Confirmar a mudança
>>> meu_jogador.velocidade
55

💡 Dica: para adicionar mais parâmetros, é preciso apenas separá-los com uma vírgula. Recomenda-se adicionar um espaço após a vírgula.

Propriedades, getters e setters em Python

Getters e setters são métodos que podemos definir para obter (get, em inglês) e definir (set, em inglês) o valor de um atributo de instância, respectivamente. Eles funcionam como intermediários para "proteger" os atributos de alterações diretas.

Em Python, normalmente utilizamos propriedades em vez de getters e setters. Vamos ver como podemos usá-las.

Para definir uma propriedade, escrevemos um método com esta sintaxe:

@property
def <nome_da_propriedade>(self):
    return self.<atributo>

Este método agirá como um getter, e será chamada quando tentarmos acessar o valor do atributo.

Agora, podemos definir um setter também:

@<nome_da_propriedade>.setter
def <nome_da_propriedade>(self, <parâmetro>):
    self.<atributo> = <parâmetro>

E um método de exclusão para excluir o atributo:

@<nome_da_propriedade>.deleter
def <nome_da_propriedade>(self):
    del self.<atributo>

💡 Dica: você pode escrever qualquer código de que precise nesses métodos para obter, definir e excluir um atributo. Recomendamos mantê-los o mais simples possível.

Este é um exemplo:

class Cachorro:

    def __init__(self, nome):
        self._nome = nome

    @property
    def nome(self):
        return self._nome

    @nome.setter
    def nome(self, novo_nome):
        self._nome = novo_nome

    @nome.deleter
    def nome(self):
        del self._nome

Se adicionarmos instruções print descritivas, podemos ver que elas são chamadas quando realizamos a operação:

>>> class Cachorro:

    def __init__(self, nome):
        self._nome = nome

    @property
    def nome(self):
        print("Chamando o getter")
        return self._nome

    @nome.setter
    def nome(self, novo_nome):
        print("Chamando o setter")
        self._nome = novo_nome

    @nome.deleter
    def nome(self):
        print("Chamando o deleter")
        del self._nome

        
>>> meu_cachorro = Cachorro("Nora")

>>> meu_cachorro.nome
Chamando o getter
'Nora'

>>> meu_cachorro.nome = "Norinha"
Chamando o setter

>>> meu_cachorro.nome
Chamando o getter
'Norinha'

>>> del meu_cachorro.nome
Chamando o deleter

🔹 Como trabalhar com arquivos em Python

Trabalhar com arquivos é muito importante para criar programas poderosos. Vamos ver como podemos fazer isso em Python.

Como ler arquivos em Python

Em Python, é recomendado usar uma instrução with para trabalhar com arquivos, porque ele os abre somente enquanto precisamos deles e os fecham automaticamente quando o processo está concluído.

Para ler um arquivo, utilizamos esta sintaxe:

with open("<caminho_do_arquivo>") as <variável_de_arquivo>:
    <código>

Também podemos especificar que queremos abrir o arquivo em modo de leitura com um "r":

with open("<caminho_do_arquivo>", "r") as <variável_de_arquivo>:
    <código>

Esse, no entanto, já é o modo padrão. Assim, podemos omitir o parâmetro do primeiro exemplo.

Veja aqui os exemplos:

with open("frases_famosas.txt") as arquivo:
    for linha in arquivo:
        print(linha)

ou...

with open("frases_famosas.txt", "r") as arquivo:
    for linha in arquivo:
        print(linha)

💡 Dica: é isso! Podemos iterar sobre as linhas do arquivo usando um laço for. O caminho do arquivo pode ser relativo ao script em Python que estamos executando ou pode ser um caminho absoluto.

Como escrever em um arquivo em Python

Existem duas maneiras de escrever em um arquivo. Você pode substituir todo o conteúdo do arquivo antes de adicionar o novo conteúdo ou anexar o conteúdo ao que já existe no arquivo.

with open("<caminho_do_arquivo>", "w") as <variável_de_arquivo>:
    <código>

Para substituir o conteúdo inteiro, usamos o modo "w", então passamos essa string como o segundo argumento para open(). Chamamos o método .write() no objeto de arquivo passando o conteúdo que queremos escrever como argumento.

Por exemplo:

palavras = ["Código", "Python", "Verde", "Incrível"]

with open("frases_famosas.txt", "w") as arquivo:
    for palavra in palavras:
        arquivo.write(palavra + "\n")

Ao executar o programa, um novo arquivo será criado, se ele já não existir, no caminho que especificamos.

Este será o conteúdo do arquivo:

Código
Python
Verde
Incrível

Como anexar a um arquivo em Python

No entanto, se quiser anexar o novo conteúdo ao antigo, você precisa usar o modo "a":

with open("<caminho_do_arquivo>", "a") as <variável_de_arquivo>:
    <código>

Por exemplo:

palavras = ["Código", "Python", "Verde", "Incrível"]

with open("frases_famosas.txt", "a") as arquivo:
    for palavra in palavras:
        arquivo.write(palavra + "\n")

Essa pequena mudança (trocar "w" por "a") manterá o conteúdo existente do arquivo e adicionará o novo conteúdo ao final.

Se executarmos o programa novamente, essas strings serão adicionadas ao final do arquivo:

Código
Python
Verde
Incrível
Código
Python
Verde
Incrível

Como excluir um arquivo em Python

Para excluir um arquivo com o nosso script, podemos usar o módulo os. É recomendado verificar com um condicional se o arquivo existe antes de chamar a função remove() desse módulo:

import os

if os.path.exists("<caminho_do_arquivo>"):
  os.remove("<caminho_do_arquivo>")
else:
  <código>

Por exemplo:

import os

if os.path.exists("frases_famosas.txt"):
  os.remove("frases_famosas.txt")
else:
  print("O arquivo não existe")

Você pode ter percebido que a primeira linha diz import os. Essa é uma instrução de import. Vejamos a utilidade dessa instrução e como você pode trabalhar com ela.

🔸 Instruções de import em Python

Organizar seu código em vários arquivos quando seu programa começa a aumentar de tamanho e em complexidade é uma boa prática. Porém, precisamos encontrar um modo de combinar esses arquivos para fazer com que o programa funcione corretamente. É exatamente isso que as instruções import fazem.

Ao escrever uma instrução import, podemos importar um módulo (um arquivo que contém definições e instruções em Python) para outro arquivo.

Estas são várias alternativas para instruções de import:

Primeira alternativa:

import <nome_do_módulo>

Por exemplo:

import math

💡 Dica: math é um módulo integrado do Python.

Se usarmos essa instrução de import, precisamos adicionar o nome do módulo antes do nome da função ou elemento que estamos referenciando em nosso código:

>>> import math
>>> math.sqrt(25)
5.0

Mencionamos explicitamente em nosso código o módulo ao qual o elemento pertence.

Segunda alternativa:

import <módulo> as <novo_nome>

Por exemplo:

import math as m

Em nosso código, podemos usar o novo nome que atribuímos em vez do nome original do módulo:

>>> import math as m
>>> m.sqrt(25)
5.0

Terceira alternativa:

from <nome_do_módulo> import <elemento>

Por exemplo:

from math import sqrt

Com essa instrução de import, podemos chamar a função diretamente sem especificar o nome do módulo:

>>> from math import sqrt
>>> sqrt(25)
5.0

Quarta alternativa:

from <nome_do_módulo> import <elemento> as <novo_nome>

Por exemplo:

from math import sqrt as raiz_quadrada

Com essa instrução de import, podemos atribuir um novo nome ao elemento importado do módulo:

>>> from math import sqrt as raiz_quadrada
>>> raiz_quadrada(25)
5.0

Quinta alternativa:

from <nome_do_módulo> import *

Esta instrução importa todos os elementos do módulo e você pode fazer referência a eles diretamente pelo nome sem especificar o nome do módulo.

Por exemplo:

>>> from math import *

>>> sqrt(25)
5.0

>>> factorial(5)
120

>>> floor(4.6)
4

>>> gcd(5, 8)
1

💡 Dica: esse tipo de instrução de import pode tornar mais difícil de sabermos quais elementos pertencem a qual módulo, especialmente quando estamos importando elementos de vários módulos.

De acordo com o Guia de estilo do código em Python:

Imports com caractere curinga (from <módulo> import *) devem ser evitados, pois deixam menos preciso quais nomes estão presentes no namespace, confundindo tanto os leitores quanto as ferramentas automatizadas.

🔹 Compreensão de listas e dicionários em Python

Um recurso realmente interessante do Python que você deve conhecer é a compreensão de listas e dicionários. Essa é apenas uma maneira de criar listas e dicionários de modo mais compacto.

Compreensão de listas em Python

A sintaxe usada para definir a compreensão de listas geralmente segue um destes quatro padrões:

[<valor_a_ser_incluído> for <variável> in <sequência>]
[<valor_a_ser_incluído> for <variável1> in <sequência1> for <variável2> in <sequência2>]
[<valor_a_ser_incluído> for <variável> in <sequência> if <condição>]
[<valor> for <variável1> in <sequência1> for <variável2> in <sequência2> if <condição>]

💡 Dica: você deve usar um deles somente quando eles não tornarem seu código mais difícil de ler e compreender.

Aqui temos alguns exemplos:

>>> [i for i in range(4, 15)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

>>> [chr(i) for i in range(67, 80)]
['C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O']

>>> [i**3 for i in range(2, 5)]
[8, 27, 64]

>>> [i + j for i in range(5, 8) for j in range(3, 6)]
[8, 9, 10, 9, 10, 11, 10, 11, 12]

>>> [k for k in range(3, 35) if k % 2 == 0]
[4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34]

>>> [i * j for i in range(2, 6) for j in range(3, 7) if i % j == 0]
[9, 16, 25]

Compreensões de lista x expressões geradoras em Python

As compreensões de lista são definidas com colchetes []. É diferente das expressões geradoras, que são definidas com parênteses (). Elas são semelhantes, mas muito diferentes. Vamos ver o motivo.

  • Compreensões de lista geram a sequência inteira de uma vez e a armazenam na memória.
  • Expressões geradoras fornecem os elementos um por vez quando eles são solicitados.

Podemos verificar isso com o módulo sys. No exemplo abaixo, você pode ver que o tamanho na memória dos dois tipos é bem diferente:

>>> import sys
>>> sys.getsizeof([i for i in range(500)])
2132
>>> sys.getsizeof((i for i in range(500)))
56

Podemos usar expressões geradoras para iterar em um laço for e obter os elementos um de cada vez. Porém, se precisarmos armazenar os elementos em uma lista, devemos usar a compreensão de lista.

Compreensão de dicionários em Python

Agora, vamos falar da compreensão de dicionários. A sintaxe básica que precisamos usar para definir uma compreensão de dicionário é:

{<valor_chave>: <valor> for <variável> in <sequência>}
{<valor_chave>: <valor> for <variável> in <sequência> if <condição>}

Aqui temos alguns exemplos de compreensão de dicionário:

>>> {num: num**3 for num in range(3, 15)}
{3: 27, 4: 64, 5: 125, 6: 216, 7: 343, 8: 512, 9: 729, 10: 1000, 11: 1331, 12: 1728, 13: 2197, 14: 2744}

>>> {x: x + y for x in range(4, 8) for y in range(3, 7)}
{4: 10, 5: 11, 6: 12, 7: 13}

Este é um exemplo com um condicional quando pegamos um dicionário existente e criamos um novo dicionário apenas com os alunos que receberam uma nota de aprovação maior que ou igual a 60:

>>> notas = {"Nora": 78, "Gino": 100, "Tais": 56, "Elizabete": 45, "Lulu": 67}

>>> alunos_aprovados = {aluno: nota for (aluno, nota) in notas.items() if nota >= 60}

>>> alunos_aprovados
{'Nora': 78, 'Gino': 100, 'Lulu': 67}

Espero realmente que você tenha gostado deste artigo e que tenha achado que ele foi útil. Agora, você já sabe como escrever e trabalhar com os elementos mais importantes do Python.

Inscreva-se no canal do YouTube da autora e siga-a no Twitter para ver mais tutoriais e dicas de programação. Confira, também, o curso on-line da autora, chamado Python Exercises for Beginners: Solve 100+ Coding Challenges (em inglês)