No Python a sintaxe se refere ao uso correto das palavras reservadas, das declarações de variáveis, funções, classes e outros recursos, nas instruções da linguagem, enquanto a semântica se refere ao uso correto da lógica na programação.
Se a instrução contiver um erro de sintaxe, o erro será apresentado no console e o programa será encerrado na linha de instrução em que ocorreu o erro, se estiver rodando um Script-Python.
Já se o programa contiver algum código com um erro de semântica, o código funcionará sem causar excessões críticas que interrompam o programa, entretanto não atendendo corretamente ao objetivo desejado.
O código Python a seguir exemplifica operações de atribuição de textos para as variáveis a, b e c, com a ocorrência de um erro de sintaxe na atribuição de c.
Textos são sequências de caracteres entre aspas simples ou duplas.
Declaramos a usando uma aspas simples e b usando uma aspas duplas.
a = 'A'
b = "B"
print(f"a={a} ({type(a)})")
print(f"b={b} ({type(b)})")
A sintaxe está correta nas declarações das variáveis a e b, que recebem textos delimitados de modo uniforme por aspas simples e duplas, respectivamente.
Entretanto na atribuição da variável c o texto inicia com aspas simples e finaliza com aspas duplas, causando erro de sintaxe durante a interpretação da instrução, e a interrupção do programa.
c = "C'
print(f"c={c} ({type(c)})")
O código Python a seguir apresenta um erro semântico em um laço de repetição, ocorrendo enquanto a condição da variável i, iniciada com 0, estiver menor que 1000.
Neste código a variável recebendo o incremento de i é a variável j, com o valor de i permanecendo zerado durante todos o tempo de execução do laço.
Sem o incremento de i, o laço se torna-se "infinito", as instruções no seu bloco são executadas indefinidamente, até ocorrer algum tipo de erro fatal que interrompa o programa, por exemplo excesso de consumo de memória.
i = 0
total = 0.0
while i < 1000:
j = i + 1
total = total + i
print("Total = ", total)
No exemplo acima, o código não apresenta erros de sintaxe, mas sim de semântica, pois a variável j é utilizada sem causar erro, recebendo todas as vezes o valor do incremento que deveria ser de i.
Sem a variável i ser incrementada, jamais a condição do laço será atendida.
Os erros de sintaxe são detectados assim que ocorrem, durante a execução do programa, enquanto os erros de semântica dependem do programador para não ocorrerem, utilizando corretamento os recursos de programação disponíveis e aplicando a lógica correta na declaração das instruções necessárias para o processo desejado ser realizado precisamente.
Nos idiomas em geral, a sintaxe é a parte da gramática que estuda as palavras enquanto elementos de uma frase, as suas relações de concordância, de subordinação e de ordem, sendo componente do sistema linguístico que determina as relações formais que interligam os constituintes da sentença, atribuindo-lhe uma estrutura.
A sintaxe do Python tem palavras reservadas, literais, siglas e simbolos que estabelecem relações uns com os outros construindo a funcionalidade da linguagem através de estruturas de código.
O Python executa comandos que disparam uma instrução ou conjuntos de instruções executadas em sequência.
A programação básica do Python é realizada com a declaração de instruções simples e em estruturas de blocos de instruções.
Construções de Python incluem instruções com:
A tipagem de Python é forte, pois os valores e objetos têm tipos bem definidos e não sofrem coerções como em C ou Perl. São disponibilizados diversos tipos de dados nativos:
Tipo de dado | Descrição | Exemplo da sintaxe |
---|---|---|
bool | Booleano | True ou False |
int | Número de precisão fixa | 42 |
float | Número de precisão de ponto flutuante | 3.1415927 |
complex | Número complexo | 3+2j |
str, unicode | Uma cadeia de caracteres imutável | 'Wikipedia', u'Wikipedia' |
list | Lista heterogênea mutável | [4.0, 'string', True] |
tuple | Tupla heterogênea imutável | (4.0, 'string', True) |
set, frozenset | Conjunto não ordenado e sem elementos duplicados | {4.0, 'string', True}, frozenset([4.0, 'string', True]) |
dict | Conjunto associativo | {'key1': 1.0, 'key2': False} |
range | Sequência de números imutável que pode ser transformada em lista | range(10), range(0, 10), range(-1, -10, -1) |
bytes, bytearray, memoryview | Sequência binária | b'Wikipedia', bytearray(b'Wikipedia'), memoryview(b'Wikipedia') |
Python também permite a definição dos tipos de dados próprios, através de classes.
Instâncias são construídas invocando a classe, e as classes são instância da classe type, o que permite metaprogramação e reflexão.
Reflexão é um mecanismo que dá informações sobre o próprio código e permite modificá-lo, em tempo de compilação ou em tempo de execução, mais comum de ocorrer, sendo frequentemente usada para obter as informações necessárias e alterar o que precisa, embora não seja a única forma. O importante é o acesso à informação para manipulá-la (se não manipular é só introspecção).
Metaprogramação é um paradigma que permite a manipulação do código de forma mais geral, você programa como o código deve ser programado. É mais comum ocorrer em tempo de compilação.
Métodos são definidos como funções anexadas à classe, e a sintaxe instância.método(argumento) é um atalho para Classe.método(instância, argumento).
Os métodos devem referenciar explicitamente a referência para o objeto incluindo o parâmetro self como o primeiro argumento do método.
O Python 3 define as seguintes palavras reservadas:
and, as, assert, async, await
break
case, class, continue
def, del
elif, else, except
False, finally, for, from
global
if, import, in, is
lambda
match
None, nonlocal, not
or
pass
raise, return
True, try
while, with
yield
Para saber quais são as palavras reservadas em Python, você pode usar o módulo keyword que vem com a Biblioteca-Padrão do Python:
import keyword
# Lista todas as palavras reservadas em Python
palavras_reservadas = keyword.kwlist
print(palavras_reservadas)
A versão 3.10.0 implementou a correspondência de Padrão Estrutural, semelhante ao Switch-Case de outras linguagens, e por isso as palavras match e case passaram a ser reservadas.
Não há uma função direta no Python que liste os operadores e símbolos reservados, mas você pode criar uma lista manualmente para referência.
Aqui está um exemplo de como você pode fazer isso:
# Lista de símbolos de operadores reservados em Python
operadores = {
'Aritméticos':['+', '-', '*', '/', '%', '**', '//'],
'Atribuição':['=', '+=', '-=', '*=', '//=', '/=', '%=', '**=', '&=', '|=','^=', '>>=', '<<=', '@='],
'Relacionais':['==', '|=', '>', '<', '>=', '<='],
'Lógicos':['&', '|', '^', '~','<<', '>>'],
'Agrupamento':['(', ')', '[', ']', '{', '}'],
'Outros':['@', ',', ':', '.','`', '->']
}
for key in operadores.keys():
print(f"{key:<12}: {' '.join(operadores[key])}")
Os operadores básicos de comparação como ==, <, >=, entre outros são usados em todos os tipos de dados, como números, cadeias de texto, listas e mapeamentos. Comparações em cadeia como a < b < c possuem o mesmo significado básico que na matemática: os termos são comparadas na ordem. É garantido que o processamento da expressão lógica irá terminar tão cedo o veredito seja claro, o princípio da avaliação mínima. Usando a expressão anterior, se a < b é falso, c não é avaliado.
Os operadores lógicos tratam "", 0, None, 0.0, [] e {} como falso, enquanto o restante é tratado como verdadeiro de modo geral. As constantes True e False representam 1 e 0, respectivamente. A comparação binária retorna uma das duas constantes acima.
Os operadores booleanos and e or também seguem a avaliação mínima. Por exemplo, (y == 0 and x/y > 100) nunca lançará a exceção de divisão por zero, pois (y == 0) retornará false e a cláusula and determinará que a expressão será avaliada automaticamente para falso e encerrada, e a expressão x/y > 100 não necessitará ser avaliada.
O interpretador interativo é uma característica diferencial da linguagem, porque há a possibilidade de testar o código de um programa e receber o resultado em tempo real, antes de iniciar a compilação ou incluí-las nos programas.
Por exemplo:
>>> 1 + 1
2
>>>
>>> a = 1 + 1
>>> print(a)
2
>>>
Se uma expressão não for atribuida a uma variável ou impressa com a função print, o valor do objeto do seu resultado será apresentado direcionado ao console e descartado em seguida.
A análise léxica é uma análise do interpretador em si, os programas são lidos por um analisador sintático que divide o código em tokens.
Todo programa é dividido em linhas lógicas que são separadas pelo token NEWLINE (NOVA LINHA), as linhas físicas são trechos de código divididos pelo caractere ENTER.
Linhas lógicas não podem ultrapassar linhas físicas com exceção de junção de linhas.
Exemplo:
resultado = 4
if resultado > 2 and \
resultado <= 5 and \
(resultado * 2) < 10:
print (f'Resultado: {resultado}')
ou
MESES_DO_ANO = [
'janeiro', 'fevereiro', 'março',
'abril', 'maio', 'junho',
'julho', 'agosto', 'setembro',
'outubro', 'novembro', 'dezembro'
]
Para a delimitação de blocos de códigos, os delimitadores são colocados em uma pilha e diferenciados por sua indentação, iniciando a pilha com valor 0 (zero) e colocando valores maiores que os anteriores na pilha.
Para cada começo de linha, o nível de indentação é comparado com o valor do topo da pilha. Se o número da linha for igual ao topo da pilha, a pilha não é alterada.
Se o valor for maior, a pilha recebe o nível de indentação da linha e o nome INDENT (empilhamento).
Se o nível de indentação for menor, então é desempilhado até chegar a um nível de indentação recebendo o nome DEDENT (desempilhamento).
Se não encontrar nenhum valor, é gerado um erro de indentação.
Abaixo um exemplo de permutação, sobre a estrutura de linhas na análise léxica:
def perm(l): NOVA LINHA
INDENT if len(l) <= 1: NOVA LINHA
INDENT return[1] NOVA LINHA
DEDENT r = [ ] NOVA LINHA
for i in range(len(l)): NOVA LINHA
INDENT s = l[:i] + l[i+1:] NOVA LINHA
p = perm(s) NOVA LINHA
DEDENT for x in p: NOVA LINHA
INDENT r.append(l[i:i+1]+x) NOVA LINHA
DEDENT return r
Python foi desenvolvido para ser uma linguagem de fácil leitura, com um visual agradável, frequentemente usando palavras e não pontuações como em outras linguagens.
Para a separação de blocos de código, a linguagem usa espaços em branco e indentação ao invés de delimitadores visuais como chaves (C, Java) ou palavras (BASIC, Fortran, Pascal).
Diferente de linguagens com delimitadores visuais de blocos, em Python a indentação é obrigatória.
O aumento da indentação indica o início de um novo bloco, que termina da diminuição da indentação.
Usando um editor de texto comum é muito fácil existir erros de indentação, o recomendado é configurar o editor conforme a análise léxica do Python ou utilizar uma IDE. Todas as IDE que suportam a linguagem fazem indentação automaticamente.
Exemplo: Indentação correta.
def valor1():
while True:
try:
c = int(input('Primeiro Valor: '))
return c
except ValueError:
print 'Inválido!'
Exemplo: Indentação incorreta.
def valor1():
while True:
try:
c = int(input('Primeiro Valor: '))
return c
except ValueError:
print 'Inválido!'
O código está correto para os dois exemplos, mas o analisador léxico verificará se a indentação está coerente.
O analisador reconhecerá as palavras reservadas while, def, try, except, return, print e as cadeias de caracteres entre aspas simples e a indentação, e se não houver problemas o programa executará normalmente, senão apresentará a exceção: "Seu programa está com erro no bloco de indentação".
A linguagem Python é de altíssimo nível, e o Programa-Interpretador pode também compilar seus programas, para que na próxima vez que os executar não precise os compilar, reduzindo o tempo de carga na execução.
Utilizando o interpretador interativo não é necessário a criação do arquivo de Python compilado, os comandos são executados interativamente. Porém quando um programa ou um módulo é evocado, o interpretador realiza a análise léxica e sintática, compila o código de alto nível se necessário e o executa na Máquina-Virtual da linguagem.
O bytecode é armazenado em arquivos com extensão '.pyc' ou '.pyo', este último no caso de bytecode otimizado. Interessante notar que o bytecode da linguagem também é de alto nível, ou seja, é mais legível aos seres humanos que o código de byte do C, por exemplo. Para descompilar um código de byte é utilizado o módulo dis da biblioteca padrão da linguagem e existem módulos de terceiros que tornam o bytecode mais confuso, tornando a descompilação ineficaz.
Normalmente, o Python trabalha com dois grupos de arquivos:
Python suporta a maioria das técnicas da programação orientada a objeto. Qualquer objeto pode ser usado para qualquer tipo, e o código funcionará enquanto haja métodos e atributos adequados. O conceito de objeto na linguagem é bastante abrangente: classes, funções, números e módulos são todos considerados objetos. Também há suporte para metaclasses, polimorfismo e herança (inclusive herança múltipla). Há um suporte limitado para variáveis privadas.
Na versão 2.2 de Python foi introduzido um novo estilo de classes em que objetos e tipos foram unificados, permitindo a especialização de tipos. Já a partir da versão 2.3 foi introduzido um novo método de resolução de ambiguidades para heranças múltiplas.
Uma classe é definida com a palavra-chave class seguida do nome da classe e dois-pontos. O corpo da classe define os atributos e os métodos, e o código seguinte é a composição dos atributos. Todos os métodos da classe recebem uma referência a uma instância da própria classe como seu primeiro argumento, e a convenção é que se chame este argumento self. Assim os métodos são chamados objeto.método(argumento1, argumento2, ...) e são definidos iguais a uma função, como método(self, argumento1, argumento2, ...). Veja que o parâmetro self conterá uma referência para a instância da classe definida em objeto quando for efetuada esta chamada. Os atributos da classe podem ser acessados em qualquer lugar da classe, e os atributos de instância (ou variável de instância) devem ser declarados dentro dos métodos utilizando a referência à instância atual (self) (ver código contextualizado em anexo).
Em Python não existe proteção dos membros duma classe ou instância pelo interpretador, o chamado encapsulamento. Convenciona-se que atributos com o nome começando com um _ são de uso privado da classe, mas não há um policiamento do interpretador contra acesso a estes atributos. Uma exceção são nomes começando com __, no caso em que o interpretador modifica o nome do atributo (ver código contextualizado em anexo).
Python permite polimorfismo, que condiz com a reutilização de código. É fato que funções semelhantes em várias partes do software sejam utilizadas várias vezes, então definimos esta função como uma biblioteca e todas as outras funções que precisarem desta a chamam sem a necessidade de reescrevê-la (ver código contextualizado em anexo).
Python não possui overloading; não é possível criar duas funções com o mesmo nome, pois elas são consideradas atributos da classe. Caso o nome da função se repita em outra assinatura, o interpretador considera esta última como override e sobrescreve a função anterior. Algumas operações entre diferentes tipos são realizadas através de coerção (ex.: 3.2 + 3).
É possível encapsular abstrações em módulos e pacotes. Quando um arquivo é criado com a extensão .py, ele automaticamente define um módulo. Um diretório com vários módulos é chamado de pacote e deve conter um modulo chamado __init__, para defini-lo como principal. Estas diferenciações ocorrem apenas no sistema de arquivos. Os objetos criados são sempre módulos. Caso o código não defina qual dos módulos será importado, o padrão é o __init__.
Uma das construções funcionais de Python é compreensão de listas, uma forma de construir listas. Por exemplo, pode-se usar a técnica para calcular as cinco primeiras potências de dois. O algoritmo quicksort também pode ser expressado usando a mesma técnica (ver códigos contextualizados para ambos os casos em anexo).
Em Python, funções são objetos de primeira classe que podem ser criados e armazenados dinamicamente. O suporte a funções anônimas está na construção lambda (cálculo Lambda). Não há disponibilidade de funções anônimas de fato, pois os lambdas contêm somente expressões e não blocos de código.
Python também suporta clausuras léxicas desde a versão 2.2 (ver códigos contextualizados para ambos os casos em anexo). Já geradores foram introduzidos na versão 2.2 e finalizados na versão 2.3, e representam o mecanismo de Python para a avaliação preguiçosa de funções (ver códigos contextualizados para ambos os casos em anexo).
Python suporta e faz uso constante de tratamento de exceções como uma forma de testar condições de erro e outros eventos inesperados no programa. É inclusive possível capturar uma exceção causada por um erro de sintaxe. O estilo da linguagem apóia o uso de exceções sempre que uma condição de erro pode aparecer. Por exemplo, ao invés de testar a disponibilidade de acesso a um recurso, a convenção é simplesmente tentar usar o recurso e capturar a exceção caso o acesso seja rejeitado (recurso inexistente, permissão de acesso insuficiente, recurso já em uso, ...).
Exceções são usadas frequentemente como uma estrutura de seleção, substituindo blocos if-else, especialmente em situações que envolvem threads. Uma convenção de codificação é o EAFP, do inglês, "é mais fácil pedir perdão que permissão". Isso significa que em termos de desempenho é preferível capturar exceções do que testar atributos antes de os usar. Segue abaixo exemplos de código que testam atributos ("pedem permissão") e que capturam exceções ("pedem perdão"):
Teste de atributo:
if hasattr(spam, 'eggs'):
ham = spam.eggs
else:
handle_error()
Captura de exceção:
try:
ham = spam.eggs
except AttributeError:
handle_error()
Ambos os códigos produzem o mesmo efeito, mas há diferenças de desempenho. Quando spam possui o atributo eggs, o código que captura exceções é mais rápido. Caso contrário, a captura da exceção representa uma perda considerável de desempenho, e o código que testa o atributo é mais rápido. Na maioria dos casos o paradigma da captura de exceções é mais rápido, e também pode evitar problemas de concorrência.[32] Por exemplo, num ambiente multitarefa, o espaço de tempo entre o teste do atributo e seu uso de fato pode invalidar o atributo, problema que não acontece no caso da captura de exceções.
Python possui uma grande biblioteca padrão, geralmente citada como um dos maiores trunfos da linguagem,[33] fornecendo ferramentas para diversas tarefas. Por conta da grande variedade de ferramentas fornecida pela biblioteca padrão, combinada com a habilidade de usar linguagens de nível mais baixo como C e C++, Python pode ser poderosa para conectar componentes diversos de software.
A biblioteca padrão conta com facilidades para escrever aplicações para a Internet, contando com diversos formatos e protocolos como MIME e HTTP. Também há módulos para criar interfaces gráficas, conectar em bancos de dados relacionais e manipular expressões regulares.
Algumas partes da biblioteca são cobertas por especificações (por exemplo, a implementação WSGI da wsgiref segue o PEP 333[34]), mas a maioria dos módulos não segue.
Um outro ponto forte da linguagem é sua capacidade de interoperar com várias outras linguagens, principalmente código nativo. A documentação da linguagem inclui exemplos de como usar a Python C-API para escrever funções em C que podem ser chamadas diretamente de código Python - mas atualmente esse sequer é o modo mais indicado de interoperação, havendo alternativas tais como Cython, Swig ou cffi. A biblioteca Boost do C++ inclui uma biblioteca para permitir a interoperabilidade entre as duas linguagens, e pacotes científicos fazem uso de bibliotecas de alta performance numérica escritos em Fortran e mantidos há décadas.
Python fornece duas alternativas para documentar o código. A primeira é o uso de comentários para indicar o que certo código faz. Comentários começam com # e são terminados pela quebra da linha. Não há suporte para comentários que se estendem por mais de uma linha; cada linha consecutiva de comentário deve indicar #. A segunda alternativa é o uso de cadeias de caractere, literais de texto inseridos no código sem atribuição. Cadeias de caracteres em Python são delimitadas por " ou ' para única linha e por """ ou ''' para múltiplas linhas. Entretanto, é convenção usar o métodos de múltiplas linhas em ambos os casos.
Diferente de comentários, a cadeias de caracteres usadas como documentação são objetos Python e fazem parte do código interpretado. Isso significa que um programa pode acessar sua própria documentação e manipular a informação. Há ferramentas que extraem automaticamente essa documentação para a geração da documentação de API a partir do código. Documentação através de cadeias de caracteres também pode ser acessada a partir do interpretador através da função help().
No Python todos os dados são objetos.
Por exemplo, ao atribuirmos um literal a uma variável, é instanciado um objeto da classe do tipo do literal, e o endereço do objeto é atribuido à variável, que passa a apontar para o objeto.
x = 10
print(f"x = {x}, tipo '{type(x)}'")
print(f"representação de x com o endereço do objeto = '{(x.__repr__)}'")
Se solitarmos os métodos de um literal qualquer com a função dir(), observaremos a existência de diversos, neste simples literal, porque ele é instanciado como objeto com o tipo do literal.
print(dir(10))
As classes são os modelos dos objetos. Todos os objetos no Python são de determinada classe, e o Python tem diversas classes nativas implementadas na linguagem.
As principais classes nativas são:
Podemos imprimir o tipo dessas classes:
print(f"int = {int}, tipo '{type(int)}'")
print(f"float = {float}, tipo '{type(float)}'")
print(f"str = {str}, tipo '{type(str)}'")
print(f"bool = {bool}, tipo '{type(bool)}'")
print(f"list = {list}, tipo '{type(list)}'")
print(f"tuple = {tuple}, tipo '{type(tuple)}'")
print(f"set = {set}, tipo '{type(set)}'")
print(f"dict = {dict}, tipo '{type(dict)}'")
print(f"range = {range}, tipo '{type(range)}'")
print(f"bytes = {bytes}, tipo '{type(bytes)}'")
print(f"bytearray = {bytearray}, tipo '{type(bytearray)}'")
print(f"memoryview = {memoryview}, tipo '{type(memoryview)}'")
Quando usamos um literal, o objeto será uma instância da classe do tipo do literal.
for x in [10, 10.1, "10", True, [10], (10,), {10}, {"x":10}, range(10), bytes(10), bytearray(10), memoryview(bytes(10))]:
print(f"x = {x}, tipo '{type(x)}'")
As classes são definições de atributos (ou propriedades) e métodos estrututurados juntos, onde os atributos e os métodos são as variáveis e as funções pertencentes às classes, respectivamente.
Quando uma classe é instanciada na memória, é alocado um objeto. Todos os tipos de dados do Python são objetos.
Quando você declara um dado inteiro, ou texto, ou lógico, são todos objetos com métodos próprios relacionados a cada tipo.
Observe o diagrama abaixo:
Neste exemplo, a classe Classe contém os atributos iniciais dos objetos da classe ao serem instanciados na memória, e métodos que serão compartilhados pelos objetos.
Os objetos Objeto 1 e Objeto 2 são instâncias da classe Classe.
Chamamos instâncias de objetos da classe ao espaço ocupado na memória e apontado pela variável à qual cada objeto foi atribuído.
Classe contém atributos que são criados nos objetos ao serem instanciados na memória.
Entretanto os métodos Métodos Compartilhados são funções que são criados na classe e não nos objetos, e são chamados pela classe usando os atributos Atributos 1 e Atributos 2 de cada objeto instanciado.
Em programação, um literal refere-se a uma notação para representar um valor fixo no código.
No Python, assim como em outras linguagens de programação, os literais são usados para inicializar variáveis com um valor diretamente no código-fonte, sem necessidade de cálculos ou funções adicionais.
Existem diferentes tipos de literais em Python, cada um correspondendo a um tipo de dado específico. Aqui estão os principais tipos de literais:
Esses literais são a forma mais básica de inserir dados no seu código em Python.
Cada um desses tipos de literais é diretamente mapeado para um tipo de dado correspondente no Python, e eles são extremamente úteis para configurar valores iniciais, fazer comparações, operações e muito mais.
Variáveis são apontadores para objetos de dados armazenados na memória pelo Python.
Os dados criados pelo Python são objetos com atributos e métodos, que podem ser unitários, como literais de números, textos e booleanos, ou compostos, como coleções de llistas, tuplas, conjuntos e dicionários.
Todos os dados do Python são objetos, mesmo os unitários.
Ao ser atribuido um valor a uma variável, o objeto do dado é alocado na memória e a variável aponta para esse objeto.
Isso é conhecido popularmente na programação como "atribuição de valores a variáveis".
a = 1
b = True
c = "ABC"
print(a,b,c)
Python não declara variáveis sem a atribuição de um valor.
Para declarar uma variável para uso futuro atribui-se o valor None.
i = None
print(i)
print(type(i))
Uma variável é criada no momento em que é atribuido um valor a ela.
x = 5
y = "Alô, mundo!"
print("x = {}, y = {}".format(x,y))
As variáveis não precisam ser declaradas com nenhum tipo específico e podem mudar de tipo depois de terem sido definidas.
x = 4 # x é do tipo int
print(x)
x = "Roberto" # x agora é do tipo str
print(x)
Você pode obter o tipo de dado de uma variável com a função type().
x = 5
y = "John"
print(f"x={x} ({type(x)})")
print(f"y={y} ({type(y)})")
Para alterar o tipo de dado de uma variável use a conversão instanciando um objeto usando um literal ou variável de outro tipo.
x = str(3) # x será '3'
y = int(x) # y será 3
z = float(y) # z será 3.0
print(f"x={x} ({type(x)})")
print(f"y={y} ({type(y)})")
print(f"z={z} ({type(z)})")
Textos são declarados entre aspas simples ou duplas e atribuidos a variáveis.
x = "Roberto"
# é o mesmo que
y = 'Roberto'
print(x)
print(y)
Os nomes de variáveis diferenciam letras maiúsculas de minúsculas.
x = 4
X = "Roberto"
# X não irá sobrepor x
print("x =",x)
print("X =",X)
Variáveis podem armazenar valores de diferentes tipos, com diferentes funcionalidades.
O Python tem os seguintes tipos de dados:
Tipo de texto | str |
---|---|
Tipos Numéricos | int, float, complex |
Tipos de sequências | str, list, tuple, range |
Tipo de mapeamento | dict |
Tipos de conjunto | set, frozenset |
Tipo booleano | bool |
Tipos binários | bytes, bytearray, memoryview |
Nenhum Tipo | NoneType |
O tipo de dado de uma variável é obtido o método type().
x = 5
print(type(x))
Em Python, o tipo de dado é definido quando você atribui um valor a uma variável:
Atribuição da variável x | Tipo de x | ||
---|---|---|---|
x = "Hello World" | str | ||
x = 20 | int | ||
x = 20.5 | float | ||
x = 1j | complex | ||
x = ["maçã", "banana", "cereja"] | list | ||
x = ("maçã", "banana", "cereja") | tuple | ||
x = range(6) | range | ||
x = {"name" : "John", "age" : 36} | dict | ||
x = {"maçã", "banana", "cereja"} | set | ||
x = frozenset({"maçã", "banana", "cereja"}) | frozenset | ||
x = True | bool | ||
x = b"Hello" | bytes | ||
x = bytearray(5) | bytearray | ||
x = memoryview(bytes(5)) | memoryview | ||
x = None | NoneType |
Atribuição da variável x com especificação de tipo | Tipo de x |
---|---|
x = str("Hello World") | str |
x = int(20) | int |
x = float(20.5) | float |
x = complex(1j) | complex |
x = list(("maçã", "banana", "cereja")) | list |
x = tuple(("maçã", "banana", "cereja")) | tuple |
x = range(6) | range |
x = dict(name="Roberto", age=58) | dict |
x = set(("maçã", "banana", "cereja")) | set |
x = frozenset(("maçã", "banana", "cereja")) | frozenset |
x = bool(5) | bool |
x = bytes(5) | bytes |
x = bytearray(5) | bytearray |
x = memoryview(bytes(5)) |
As operações no Python envolvem operadores e operandos na produção dos resultados.
Os operadores são usados nas operações conectando os operandos, que são literais ou variáveis.
No exemplo abaixo, usamos o operador aritmético "+" em uma operação de soma de dois valores dfe literais numéricos, com impressão do resultado na tela.
print(10 + 5)
Os tipos de operadores são:
Os operadores de atribuição são utilizados para lançar valores em variáveis.
Operador | Exemplo | O mesmo que |
---|---|---|
= | x = 5 | x = 5 |
+= | x += 3 | x = x + 3 |
-= | x -= 3 | x = x - 3 |
*= | x *= 3 | x = x * 3 |
/= | x /= 3 | x = x / 3 |
%= | x %= 3 | x = x % 3 |
//= | x //= 3 | x = x // 3 |
**= | x **= 3 | x = x ** 3 |
&= | x &= 3 | x = x & 3 |
|= | x |= 3 | x = x | 3 |
^= | x ^= 3 | x = x ^ 3 |
>>= | x >>= 3 | x = x >> 3 |
<<= | x <<= 3 | x = x << 3 |
Os operadores aritméticos são usados com valores numéricos para realizar operações matemáticas comuns.
Operador | Nome | Exemplo |
---|---|---|
+ | Adição | x + y |
- | Subtração | x - y |
* | Multiplicação | x * y |
/ | Divisão | x / y |
% | Módulo | x % y |
** | Exponenciação | x ** y |
// | Divisão do andar | x // y |
Os operadores de comparação são usados para comparar dois valores.
Operador | Nome | Exemplo |
---|---|---|
== | Igual | x == y |
!= | Diferente | x != y |
> | Maior | x > y |
< | Menor | x < y |
>= | Maior ou igual | x >= y |
<= | Menor ou igual | x <= y |
Os operadores lógicos são usados para combinar instruções condicionais.
Operador | Descrição | Exemplo |
---|---|---|
and | Comparação se dois valores são verdadeiros | x > 5 and y < 10 |
or | Comparação se pelo menos um de dois operadores é verdadeiro | x < 5 or y > 4 |
not | Inverte o resultado de um valor lógico | not x |
Os operadores de identidade são usados para comparar os objetos, não se forem iguais, mas se forem realmente o mesmo objeto, com a mesma localização de memória.
Operador | Descrição | Exemplo |
---|---|---|
is | Retorna True se ambas as variáveis são o mesmo objeto | x is y |
is not | Retorna True se ambas as variáveis não forem o mesmo objeto | x is not y |
Os operadores de associação são usados para testar se uma sequência é apresentada em um objeto.
Operador | Descrição | Exemplo |
---|---|---|
in | Retorna True se o valor especificado estiver presente no objeto | 3 in [1,2,3] |
not in | Retorna True se o valor especificado não estiver presente no objeto | 3 not in [1,2,3] |
Operadores bit a bit são usados para comparar números inteiros (binários).
Operador | Nome | Descrição | Exemplo |
---|---|---|---|
& | AND | Define cada bit como 1 se ambos os bits forem 1 | x & y |
| | OR | Define cada bit como 1 se um dos dois bits for 1 | x | y |
^ | XOR | Define cada bit como 1 se apenas um dos dois bits for 1 | x ^ y |
~ | NOT | Inverte todos os bits | ~x |
<< | LEFT | Desloca os bits do valor binário para a esquerda, preenchendo com zeros à direita | x << 2 |
>> | RIGHT | Desloca os bits do valor binário para direita, copiando os bits à esquerda | x >> 2 |
A linguagem Python utiliza programação estruturada de instruções sequenciais, com controle de fluxo através da utilização de blocos de instruções.
Blocos são estruturas de código contendo um cabeçalho definindo sua funcionalidade e um corpo contendo instruções.
Existem diferentes estruturas de bloco usados no Python:
Os blocos condicionais, de repetição, de funções e excessões são chamados de blocos de controle de fluxo contínuo, pois são utilizados para controlar o fluxo de instruções de modo sequêncial.
Os blocos condicionais são definidos com as palavras reservadas if... elif... else ou match... case... case _ iniciando a linha no cabeçalho.
Os blocos de repetição são definidos com as palavras reservadas for e while iniciando a linha no cabeçalho.
Os blocos de funções são definidos com as palavras reservadas def iniciando a linha no cabeçalho.
Os blocos de classes são definidos com as palavras reservadas class iniciando a linha no cabeçalho.
Os blocos de exceções são definidos com as palavras reservadas try, except, else e finally no cabeçalho.
A instrução no corpo de um bloco são definidos por uma sequência de instruções separadas por espaços em branco iniciando a linha, com o mesmo recuo.
Os recuos são os espaços em branco no início de uma linha de código que definem blocos de instruções.
Após iniciado um bloco, o recuo não pode ser alterado para linha seguinte no bloco, e o bloco conterá as instruções sempre com o mesmo recuo.
Os blocos podem ser aninhados dentro de outros blocos, sempre seguindo a regra de recuo para cada bloco aninhado.
Onde em outras linguagens de programação o recuo no código tem efeito apenas na legibilidade, o recuo em Python faz parte da sintaxe, sendo, portanto, bastante importante.
O bloco principal de um Script-Python não tem espaços em branco no início da linha.
x = 2
y = 3
print (x + y)
Recuos são utilizados com blocos condicionais, blocos de repetição, blocos de funções e blocos de classes para agrupar instruções em um mesmo escopo.
z
Os blocos condicionais são estruturas de controle de fluxo que permitem que as instruções sejam executadas somente se uma determinada condição for atendida.
Se uma condição for atendida, as instruções dentro do bloco são executadas. Se nenhuma das condições forem atendidas, as instruções dentro do bloco são ignoradas.
São de dois tipos de sintaxe:
Exemplo com a cláusula if:
a = 10
b = 5
if (a > b):
c = a / b
print(c)
Exemplo com as cláusulas if... elif... else:
a = 1
b = 2
if (a > b):
print("a > b")
elif (a < b):
print("a < b")
else:
print("a = b")
Exemplo com a cláusula match... case... case _:
a = 10
match a:
case 1:
print("a = 1")
case 2:
print("a = 2")
case 3:
print("a = 3")
case _:
print("a não é 1, 2 ou 3")
Blocos de repetição são aqueles em que as instruções são executadas somente se uma determinada condição for atendida com o uso das cláusulas for/while.
Exemplo com a cláusula for e uma lista:
lista = [1,2,3]
for item in lista:
print(item)
Exemplo com o laço for e a cláusula range:
for i in range(10): # de 0 a 9
print(i)
Exemplo com o laço while:
i = 0
while i < 10: # de 0 a 9
print(i)
i += 1
Os recuos devem ser utilizados com as cláusulas de bloco (condicionais, repetitivos, funções e classes) e seu uso sem necessidade gera erro.
Observe no script a seguir com um recuo de 4 espaços sem necessidade causando erro:
x = 5
O recuo serve para determinar um bloco de instruções.
if 5 > 2:
print("Cinco é maior que dois!")
Ocorrerá erro se o recuo não for respeitado.
if 5 > 2:
print("Cinco é maior que dois!")
O número de espaços fica ao critério do programador.
O uso mais comum são quatro espaços, entretanto pode ser qualquer quantidade de espaços, em um mesmo bloco de instruções.
if 5 > 2:
print("Um espaço!") # um espaço em branco, no bloco
if 5 > 2:
print("Oito espaços!") # oito espaços no bloco
Você precisa usar o mesmo número de espaços em um mesmo bloco de instruções, caso contrário, ocorrerá erro.
if 5 > 2:
print("Cinco é maior que dois!")
print("Cinco é maior que dois!")
Uma variável só está disponível dentro da região em que foi criada. Isso é chamado de escopo.
Uma variável criada dentro de uma função pertence ao escopo local dessa função e só pode ser usada dentro dela.
def funcao_x_local():
x = 300
print(x)
#
funcao_x_local()
Conforme explicado no exemplo acima, a variável x não está disponível fora da função, mas está disponível para qualquer função dentro da função.
Exemplo: a variável local pode ser acessada em uma função dentro da função.
def minha_funcao():
x = 300
#
def minha_funcao_interna():
print(x)
#
minha_funcao_interna()
#
minha_funcao()
Variáveis declaradas no corpo principal do código têm escopo global.
Podem ser acessadas nas funções e classes com a declaração da variável como global.
x = 300
#
def funcao_x_global():
global x
print(x)
#
funcao_x_global()
Se você operar com o mesmo nome de variável dentro e fora de uma função, o Python as tratará como duas variáveis diferentes, uma disponível no escopo global (fora da função) e outra disponível no escopo local (dentro da função).
x = 300
def minha_funcao():
x = 200
print('x dentro da função =', x)
minha_funcao()
print('x fora da função =', x)
Python é uma linguagem de programação extremamente rica e versátil, muito conhecida por sua clareza sintática e eficiência.
Parte dessa eficiência advém do robusto conjunto de funções nativas que a linguagem oferece, permitindo que os programadores realizem uma variedade de tarefas fundamentais de maneira rápida e intuitiva.
Estas funções nativas são incorporadas diretamente no interpretador Python, o que significa que estão sempre disponíveis para uso, sem a necessidade de importar módulos externos.
Exemplos populares incluem print(), para imprimir saída para o terminal; len(), que retorna o tamanho de um objeto; e range(), usada frequentemente em loops para gerar sequências de números.
Além de facilitar a escrita de código eficiente, as funções nativas de Python são projetadas para serem altamente interoperáveis com os tipos de dados incorporados da linguagem, como listas, strings, e dicionários. Funções como sum(), que calcula a soma dos itens de um iterável, min() e max(), que retornam o menor e o maior valor, respectivamente, e sorted(), que retorna uma nova lista ordenada, são extremamente úteis para manipulação de dados. Outras funções, como input(), facilitam a interação com o usuário, capturando entradas do console, enquanto open() é essencial para ler e escrever arquivos.
A compreensão e utilização dessas funções nativas podem significativamente acelerar o processo de desenvolvimento de software e aumentar a legibilidade do código. Por serem bem otimizadas e parte integrante da linguagem, essas funções oferecem um desempenho superior quando comparadas a funções equivalentes implementadas manualmente. Ademais, o uso consistente dessas funções nativas permite que os programadores adotem práticas de programação mais pythonicas, aproveitando ao máximo as convenções e capacidades da linguagem. Assim, um bom domínio das funções nativas é crucial para qualquer desenvolvedor que deseja explorar profundamente os recursos e a eficácia do Python.
Função | Descrição |
---|---|
abs() | Valor absoluto; módulo no caso de complexo. |
all() | Retorna True se todos os elementos do argumento são verdadeiros. |
any() | Retorna True se algum elemento do argumento é verdadeiro. |
bin() | Converte um int em binário. |
bool() | Retorna True se o argumento é verdadeiro, False se não há argumento ou ele é falso. |
bytearray() | Retorna um array de bytes. |
callable() | Retorna True se o argumento é uma função ou método. |
chr() | Caractere correspondente ao código ASCII do argumento (entre 0 e 255). |
clear() | A função clear(x) remove todos os elementos do conjunto x. |
compile() | Retorna um objeto de código compilado. |
complex() | A função complex(re, im) retorna um número complexo com parte real re e imaginária im. |
delattr() | Remove o atributo do objeto. |
dict() | Retorna um dicionário. |
dir() | Retorna uma lista de atributos do objeto. |
divmod() | A função divmod(x,y) retorna o par da dupla ordenada (x // y, x % y). |
enumerate() | Retorna um iterador de tuplas (índice, valor). |
eval() | Avalia uma string como uma expressão Python. |
execfile() | Executa um arquivo Python. |
file() | Retorna um objeto de arquivo. |
filter() | A função filter(f, L) Aplica a função f a cada elemento da lista L, e resulta nos elementos de L para os quais f for True. |
float() | Converte para float. |
format() | Retorna uma string formatada. |
frozenset() | Constroi um conjunto que não pode ser mudado. |
getattr() | Retorna o valor do atributo do objeto. |
globals() | Retorna um dicionário com os nomes globais. |
hasattr() | Retorna True se o objeto tem o atributo. |
hash() | Retorna o hash do objeto. |
help() | No modo interativo (IDLE), dá a documentação do argumento. |
hex() | Converte um int para um hexadecimal. |
id() | Retorna o identificador do objeto. |
input() | Dá o valor da entrada de um dado em forma de string; pode exibir uma mensagem. |
int() | Converte para int. |
isinstance() | Retorna True se o objeto é uma instância da classe. |
issubclass() | Retorna True se a classe é subclasse da classe. |
iter() | Retorna um iterador. |
len() | A função len(obj) retorna o número de elementos de um objeto que pode ser texto, lista, n-pla ou conjunto (neste caso, a cardinalidade). |
list() | Converte os elementos de uma string ou n-pla em lista; sem argumento dá a lista vazia. |
locals() | Retorna um dicionário com os nomes locais. |
long() | Converte para long. |
map() | A função map(f,L) Aplica a função f a cada elemento de uma lista. |
max() | Dá o maior dos elementos do argumento. |
memoryview() | Retorna um objeto de visualização de memória. |
min() | Dá o menor dos elementos do argumento. |
next() | Retorna o próximo elemento de um iterador. |
object() | Retorna um objeto. |
oct() | Converte para octal. |
open() | Retorna um objeto de arquivo. |
ord() | Contrário de chr. |
pow() | A função pow(x,y) é equivalente a x**y. |
print() | Saída de dados. |
property() | Retorna uma propriedade. |
range() | Cria uma lista com uma faixa de itens. |
reduce() | Aplica uma função a uma sequência de elementos. |
reload() | Recarrega um módulo. |
repr() | Retorna uma string que representa o objeto. |
reversed() | Retorna um iterador reverso. |
round() | A função round(x,n) retorna x arredondado na n-ésima casa decimal; sem n arredonda para o inteiro. |
set() | Constroi um conjunto que pode ser mudado. |
setattr() | Define o valor do atributo do objeto. |
slice() | Retorna um objeto de fatia. |
sorted() | Ordena uma lista. |
staticmethod() | Retorna um método estático. |
str() | Converte int ou float para string. |
sum() | Soma os elementos de uma lista, n-pla ou conjunto. |
super() | Retorna um objeto proxy que delega os métodos para a classe pai. |
tuple() | Dá uma lista ordenada. |
type() | Se o argumento for uma variável, dá seu tipo; se for um objeto, o tipo do mesmo. |
upper() | Converte as letras de uma string para maiúsculas. |
vars() | Retorna um dicionário com os atributos do objeto. |
zip() | Cria uma lista de tuplas, onde cada tupla é formada pelos elementos de uma lista. |
Comentários são partes do código sem efeito, que são ignorados e não são interpretados pelo Python.
Os comentários começam com o simbolo "#" e o Python tratará o restante da linha como comentário.
# Este é um comentário.
print("Alô, mundo!")
Os comentários são usados para documentação diversa no código.
Comentários podem ser usados para tornar o código mais legível.
Os comentários podem ser usados para desabilitar a execução de código em testes.
Os comentários começam com #, e o Python ignorará o restante da linha em que aparece.
# Este é um comentário
print("Alô, mundo!")
O comentário pode ser colocado no final de uma linha com uma instrução e o interpretador irá ignorar o restante da linha.
print("Alô, mundo!") # Este é um comentário
Um comentário não precisa ser um texto que explique o código, ele também pode ser usado para impedir que o Python execute o código na linha durante testes.
# print("Alô, mundo!")
print("Abraço, companheiro!")
O Python não possui uma sintaxe para comentários de várias linhas.
Para comentar várias linhas inserimos # para cada linha.
# Este é um comentário
# escrito em
# mais de uma linha
print("Alô, mundo!")
Ou, não exatamente como pretendido, você pode usar um texto de várias linhas sem atribuir a nenhuma variável.
Como o Python ignora textos não atribuídos a variáveis, um texto contendo várias linhas (entre aspas triplas ''' ou """) pode ser incluído no código funcionando como comentário.
"""
Este é um texto
funcionando como comentário
escrito em mais do que
apenas uma linha
"""
print("Alô, mundo!")
Contando que a string não seja atribuída a uma variável, o Python interpretará o código, descartando texto, permitindo que funcione como um comentário de várias linhas.
Os erros semânticos em Python são erros que ocorrem quando o código não funciona conforme o esperado, mesmo que seja sintaticamente correto.
Esses erros são mais difíceis de detectar porque o programa executa sem lançar exceções, mas não produz o resultado correto.
Corrigir esses erros geralmente requer um bom entendimento do que o programa deveria fazer e um uso cuidadoso de ferramentas de depuração ou impressão de estados intermediários do programa para verificar onde as coisas estão desviando do esperado.
Seguem alguns dos erros semânticos mais comuns em Python.
Confundir ou usar o nome de uma variável errada pode levar a comportamentos inesperados. Por exemplo, atribuir um valor a uma variável e, por engano, usar outra com nome similar em operações subsequentes.
Vamos considerar um exemplo simples de erro semântico em Python envolvendo o uso incorreto de variáveis. No cenário a seguir, o desenvolvedor pretende calcular a soma de uma série de números, mas acaba utilizando variáveis de forma confusa, resultando em um resultado inesperado.
# Intenção: Calcular a soma dos números de 1 a 5
total = 0
# Erro: a variável 'contador' está sendo usada no lugar de 'total'
for i in range(1, 6):
contador = total + i
# Esperado que total seja 15, mas vamos verificar o valor de 'total' e 'contador'
print("Total:", total) # Saída será 0
print("Contador:", contador) # Saída será 15
No código acima, o desenvolvedor pretendia adicionar cada número de 1 a 5 à variável total. No entanto, ele acidentalmente usou uma nova variável chamada contador para armazenar os resultados intermediários. Embora contador receba o valor correto ao final do loop, a variável total permanece inalterada, pois nunca é atualizada dentro do loop.
Para corrigir o código, você deve garantir que a variável total seja atualizada a cada iteração do loop, como mostrado abaixo:
# Correção: Usar a variável 'total' corretamente para acumular a soma
total = 0
for i in range(1, 6):
total += i # Correção: atualizar 'total' diretamente
# Agora 'total' deve ser 15, que é a soma de 1+2+3+4+5
print("Total:", total) # Saída será 15
Este exemplo ilustra a importância de usar consistentemente o nome correto da variável para evitar resultados inesperados.
Usar a condição errada em uma instrução if ou while pode causar um fluxo de execução incorreto. Por exemplo, usar == em vez de != ou confundir and com or.
Vamos explorar um exemplo de erro de lógica em condições no Python. Nesse tipo de erro, a lógica usada para testar uma condição em uma instrução if ou while é incorreta, levando a comportamentos inesperados ou resultados errados.
Suponha que você deseja imprimir uma mensagem se uma pessoa é menor de idade. No entanto, o erro está na condição usada para determinar se a pessoa é menor de idade.
idade = 20
# Erro de lógica: a condição deveria verificar se a pessoa é menor de 18 anos
if idade > 18:
print("Você é menor de idade.") # Esta mensagem está logicamente incorreta
Neste exemplo, a condição if idade > 18: é usada para determinar se uma pessoa é menor de idade. No entanto, essa lógica está errada porque verifica se a pessoa é maior de 18 anos, não menor. Portanto, a mensagem que diz "Você é menor de idade" está sendo impressa sob a condição errada.
Para corrigir o erro, você precisa ajustar a condição de modo que verifique se a pessoa tem menos de 18 anos.
idade = 20
# Correção: verificar se a pessoa é menor de 18 anos
if idade < 18:
print("Você é menor de idade.")
else:
print("Você é maior de idade.") # Mensagem correta para quem tem 18 anos ou mais
Outro Exemplo Comum de Erro Lógico: Confundir AND com OR
Considere o cenário onde você quer verificar se um número está fora de um intervalo:
numero = 10
# Erro: Uso incorreto do operador lógico
if numero > 1 and numero < 10:
print("O número está fora do intervalo 1-10.")
else:
print("O número está dentro do intervalo 1-10.") # Esta saída é incorreta dado o erro lógico.
Você deve usar o operador or para testar se o número está fora do intervalo, ao invés de and:
numero = 10
# Correção: Uso correto do operador OR para verificar se o número está fora do intervalo
if numero < 1 or numero > 10:
print("O número está fora do intervalo 1-10.")
else:
print("O número está dentro do intervalo 1-10.") # Corrigido
Esses exemplos mostram como pequenos erros na lógica das condições podem levar a grandes equívocos no comportamento esperado do programa.
Como modificar uma lista enquanto a está iterando. Em Python, modificar uma lista em um loop pode resultar em comportamentos inesperados ou erros.
Um erro comum ao manipular coleções em Python é tentar modificar a coleção (como uma lista) enquanto se está iterando sobre ela. Isso pode levar a comportamentos inesperados ou erros difíceis de rastrear. Vamos ver um exemplo disso:
Suponha que você quer remover números negativos de uma lista iterando sobre ela diretamente:
numeros = [10, -1, 3, -2, 5, -6, 7]
# Tentativa errada de remover números negativos enquanto itera
for numero in numeros:
if numero < 0:
numeros.remove(numero)
print(numeros) # Saída pode não ser o esperado
Ao modificar a lista numeros enquanto se itera sobre ela com um loop for, você altera os índices dos elementos da lista durante a iteração. Isso pode fazer com que alguns elementos (especialmente se forem consecutivos) não sejam verificados pelo loop, resultando em uma lista que ainda contém alguns números negativos.
Uma maneira correta e segura de modificar a lista enquanto se itera é criar uma nova lista apenas com os elementos desejados ou iterar sobre uma cópia da lista original. Aqui estão duas abordagens corretas:
Abordagem 1: Criar uma nova lista
numeros = [10, -1, 3, -2, 5, -6, 7]
numeros_positivos = [numero for numero in numeros if numero >= 0]
print(numeros_positivos) # Saída será [10, 3, 5, 7]
Abordagem 2: Iterar sobre uma cópia da lista
numeros = [10, -1, 3, -2, 5, -6, 7]
# Iterar sobre uma cópia da lista original
for numero in numeros[:]: # O fatiamento cria uma cópia da lista
if numero < 0:
numeros.remove(numero)
print(numeros) # Saída será [10, 3, 5, 7]
Essas correções garantem que a manipulação da lista seja feita de forma segura, evitando erros de modificação durante a iteração. Isso é crucial para evitar bugs sutis que podem ser difíceis de diagnosticar em programas mais complexos.
Esperar um tipo de dado, mas trabalhar com outro. Isso pode ocorrer, por exemplo, quando se espera uma lista, mas recebe-se uma string, ou vice-versa.
A confusão entre tipos de dados é um erro semântico comum em Python, que ocorre quando se espera um tipo de dado, mas, inadvertidamente, trabalha-se com outro. Isso pode levar a erros inesperados ou comportamentos incorretos do programa. Vamos ver um exemplo disso:
Suponha que você está escrevendo uma função que deveria concatenar uma lista de strings, mas acidentalmente recebe uma lista de inteiros.
def concatenar_elementos(lista):
resultado = ""
for elemento in lista:
resultado += elemento # Erro: tentando concatenar inteiro com string
lista_de_inteiros = [1, 2, 3, 4, 5]
concatenar_elementos(lista_de_inteiros) # Isso vai levantar uma exceção TypeError
O erro ocorre porque o operador += está sendo usado para adicionar um inteiro a uma string. Em Python, isso resulta em um TypeError, pois você não pode diretamente concatenar números inteiros com strings.
Para corrigir o erro, você deve garantir que todos os elementos sejam convertidos para strings antes de tentar concatená-los. Isso pode ser feito usando a função str() para converter cada elemento para string dentro do loop.
def concatenar_elementos(lista):
resultado = ""
for elemento in lista:
resultado += str(elemento) # Correção: converter elemento para string
lista_de_inteiros = [1, 2, 3, 4, 5]
resultado = concatenar_elementos(lista_de_inteiros)
print(resultado) # Saída será '12345'
Esse exemplo ilustra como a confusão entre tipos de dados pode causar erros e como é importante assegurar que os tipos de dados usados sejam compatíveis com as operações que você está tentando realizar.
Acessar índices que não existem em uma lista (por exemplo, tentar acessar o 10º elemento de uma lista com apenas 5 elementos) ou erros por off-by-one (erro comum onde um loop ou acesso de índice vai um elemento a mais ou a menos do necessário).
Erros com índices em listas ou arrays são comuns em Python, especialmente quando se tenta acessar índices que não existem. Isso resulta em um IndexError. Vamos examinar um exemplo para ilustrar como isso pode acontecer e como evitar tais erros.
Suponha que você tenha uma lista de elementos e deseja acessar um elemento específico baseado em um índice que você presume que existe na lista:
numeros = [10, 20, 30, 40, 50]
# Tentativa de acessar um índice que não existe
indice = 5
print(numeros[indice]) # Erro: IndexError, pois não há um elemento no índice 5
A lista numeros tem índices de 0 a 4, portanto, tentar acessar o índice 5 resulta em um IndexError porque este índice está fora do alcance da lista. Esse tipo de erro é muito comum, especialmente em casos onde o tamanho da lista pode não ser conhecido antecipadamente.
Para evitar esse tipo de erro, você pode adicionar verificações para garantir que o índice está dentro do intervalo válido da lista. Uma maneira de fazer isso é verificar se o índice é menor que o comprimento da lista:
numeros = [10, 20, 30, 40, 50]
indice = 5
if indice < len(numeros):
print(numeros[indice])
else:
print("Índice fora de alcance") # Saída segura que evita o erro
Outra maneira de evitar erros de índice é utilizar métodos de listas que são seguros contra erros de índice, como o método get() de dicionários (que listas não possuem, mas uma estrutura similar pode ser criada). Para listas, pode-se pensar em formas alternativas de acessar elementos que não resultem em erros fatais, como iterar sobre a lista ou usar slices que são seguros contra índices fora de alcance:
numeros = [10, 20, 30, 40, 50]
# Uso de slice para evitar IndexError
indice = 5
elemento = numeros[indice:indice+1] # Retorna uma lista vazia se o índice estiver fora de alcance
print(elemento if elemento else "Índice fora de alcance") # Saída segura
Neste exemplo, o uso de slicing (numeros[indice:indice+1]) retorna uma lista vazia quando o índice está fora de alcance, evitando o IndexError e permitindo um tratamento de erro mais amigável.
Escrever uma função que deveria retornar um valor, mas esquecer de incluir a instrução return, resultando em um retorno de None.
Esquecer de retornar um valor em funções é um erro semântico comum em Python, que ocorre quando a função deveria fornecer um resultado, mas não possui uma instrução return adequada. Isso faz com que a função retorne None por padrão, o que pode causar confusão ou erros em partes do código que dependem do valor retornado.
Suponha que você está escrevendo uma função para calcular a média de uma lista de números, mas esquece de incluir a instrução de retorno:
def calcular_media(numeros):
soma = sum(numeros)
media = soma / len(numeros)
# Esquecido de retornar o valor da média
# Lista de números
numeros = [10, 20, 30, 40, 50]
# Tentativa de usar o resultado da função
resultado = calcular_media(numeros)
print("A média é:", resultado) # Saída será "A média é: None"
Na função calcular_media, o cálculo da média é realizado corretamente, mas a falta da instrução return faz com que a função retorne None por padrão. Quando você tenta imprimir o resultado, a saída mostra que o valor é None, o que pode levar a erros difíceis de rastrear se o valor retornado fosse usado em cálculos ou operações subsequentes.
Para corrigir o erro, você deve incluir uma instrução return na função para garantir que o valor calculado seja retornado:
def calcular_media(numeros):
soma = sum(numeros)
media = soma / len(numeros)
return media # Correção: incluir retorno do valor calculado
# Lista de números
numeros = [10, 20, 30, 40, 50]
# Usando o resultado da função corretamente
resultado = calcular_media(numeros)
print("A média é:", resultado) # Saída será "A média é: 30.0"
Esse exemplo destaca a importância de sempre verificar se as funções estão retornando os valores esperados, especialmente em linguagens como Python, onde a falta de uma instrução de retorno implica um retorno de None. Isso é crucial para evitar bugs sutis e garantir a corretude dos programas.
Chamar métodos com parâmetros errados ou em um contexto inadequado. Por exemplo, usar incorretamente métodos de strings ou listas esperando um resultado diferente.
O uso inadequado de funções ou métodos de bibliotecas é um erro comum que ocorre quando os desenvolvedores aplicam métodos de maneira incorreta ou em contextos não adequados. Isso pode levar a resultados inesperados ou erros. Vamos ver um exemplo específico envolvendo a biblioteca de manipulação de dados Python, Pandas.
Suponha que você está trabalhando com um DataFrame do Pandas e deseja remover duplicatas com base em uma coluna específica. No entanto, você acaba usando um método de maneira inadequada.
import pandas as pd
# Criando um DataFrame de exemplo
data = {
'ID': [1, 2, 2, 3, 4],
'Valor': [10, 20, 20, 30, 40]
}
df = pd.DataFrame(data)
# Tentativa errada de remover duplicatas
df.drop_duplicates('ID')
print(df)
Neste exemplo, o desenvolvedor tentou usar drop_duplicates('ID') para remover linhas duplicadas com base na coluna 'ID'. No entanto, o método drop_duplicates() em Pandas não altera o DataFrame original a menos que você especifique o argumento inplace=True ou reatribua o DataFrame. Além disso, o argumento deve ser passado corretamente como subset='ID'.
Para corrigir o erro, você deve especificar corretamente o argumento subset e considerar o uso do argumento inplace=True ou reatribuir o DataFrame:
import pandas as pd
# Criando um DataFrame de exemplo
data = {
'ID': [1, 2, 2, 3, 4],
'Valor': [10, 20, 20, 30, 40]
}
df = pd.DataFrame(data)
# Correção: removendo duplicatas corretamente
df = df.drop_duplicates(subset='ID')
print(df)
Agora o DataFrame df será atualizado para remover as duplicatas com base na coluna 'ID'. A saída mostrará um DataFrame sem duplicatas para a coluna 'ID'.
Outro exemplo de uso inadequado: apply() em vez de operações vetoriais
Outro erro comum é usar o método apply() para operações que poderiam ser realizadas mais eficientemente com operações vetoriais. Por exemplo, ao invés de usar apply() para calcular o logaritmo de cada elemento de uma coluna, é mais eficiente usar operações vetoriais diretamente com o NumPy:
import pandas as pd
import numpy as np
# Criando um DataFrame de exemplo
df = pd.DataFrame({
'Valor': [1, 10, 100, 1000, 10000]
})
# Uso inadequado: usando apply()
df['Log'] = df['Valor'].apply(np.log)
# Uso mais eficiente: operação vetorial
df['Log'] = np.log(df['Valor'])
print(df)
Este exemplo mostra a importância de entender bem as funções das bibliotecas e aplicá-las corretamente para garantir eficiência e corretude no código.
Divisão por zero, usar tipos incompatíveis em operações matemáticas, ou confundir operadores de divisão (/ para divisão real, // para divisão inteira).
Erros em operações matemáticas em Python ocorrem quando as operações são aplicadas de maneira inadequada ou com tipos incompatíveis, podendo levar a resultados inesperados ou falhas no programa. Aqui está um exemplo detalhado para ilustrar esses tipos de erros.
Vamos considerar o cenário onde você está tentando calcular a média de uma lista de números, mas acidentalmente inclui uma operação que pode resultar em divisão por zero.
def calcular_media(numeros):
if len(numeros) == 0:
return "Lista vazia, não é possível calcular a média."
return sum(numeros) / len(numeros)
# Lista de números está vazia
numeros_vazios = []
# Tentativa de calcular a média de uma lista vazia
resultado = calcular_media(numeros_vazios)
print(resultado) # Saída pode ser um erro se não manuseado corretamente
No código acima, a função calcular_media tenta calcular a média de uma lista de números. No entanto, se a lista estiver vazia, a função tentará realizar uma divisão por zero (sum(numeros) / len(numeros)), o que é uma operação indefinida e resulta em um erro de divisão por zero (ZeroDivisionError) se não for manuseada.
Para evitar a divisão por zero e outros problemas potenciais, você pode modificar a função para retornar um valor adequado ou lançar uma exceção quando a lista estiver vazia, além de garantir que todos os elementos da lista sejam numéricos:
def calcular_media(numeros):
if not numeros: # Verifica se a lista está vazia
return "Lista vazia, não é possível calcular a média."
return sum(numeros) / len(numeros)
# Lista de números está vazia
numeros_vazios = []
# Tentativa segura de calcular a média de uma lista vazia
resultado = calcular_media(numeros_vazios)
print(resultado) # Saída correta sem erro
Outro Exemplo Comum: Operações com Tipos Incompatíveis
Outro tipo comum de erro em operações matemáticas é tentar operar em tipos incompatíveis:
numero = "10"
incremento = 5
# Erro: tentando somar uma string com um inteiro
resultado = numero + incremento
print(resultado)
Para corrigir esse erro, você precisa garantir que ambos os operandos sejam do mesmo tipo.
Se o objetivo é somar números, ambos os valores devem ser convertidos para tipo numérico:
numero = "10"
incremento = 5
# Correção: converter a string para inteiro antes da soma
resultado = int(numero) + incremento
print(resultado) # Saída será 15
Esses exemplos destacam a importância de entender e aplicar corretamente as operações matemáticas, bem como de verificar e validar os tipos de dados antes de operar sobre eles para evitar erros e garantir a precisão dos resultados.