Python Novidades do 3.14 e do 3.15
O Python ganha uma versão nova todo ano, em outubro. Este guia ensina o Python 3.14, lançado em 7 de outubro de 2025: é o que vem no Ubuntu 26.04 e o que roda no editor do guia. Um ano depois, em 9 de outubro de 2026, saiu o Python 3.15. Esta página reúne o que mudou nas duas versões, do jeito que interessa a quem está aprendendo: o que você vai ver de diferente, o que pode escrever agora e o que vai encontrar no código dos outros. Tudo foi conferido nas páginas oficiais What's New ("O que há de novo") em docs.python.org/3/whatsnew/; o que é do 3.14 foi rodado no Python 3.14 de verdade.
- Como saber qual Python você tem, e como as versões são lançadas.
- As novidades do 3.14 que você sente logo: mensagens de erro mais espertas e o modo interativo colorido.
except A, B:sem parênteses (PEP 758).- As template strings,
t"…": parentes das f-strings, mas com um superpoder (PEP 750). - As anotações de tipo adiadas (PEP 649) e o aviso de
returndentro dofinally(PEP 765). - Melhorias pequenas e úteis:
Path.copy(),map(strict=True),uuid7()e outras. - O que chegou no 3.15:
lazy import,frozendict, desempacotamento em comprehensions, UTF-8 por padrão, dicas de erro novas.
A ideia: um celular que recebe atualizações
O seu celular de hoje faz o mesmo que fazia ontem, mas a cada atualização ganha alguma coisa: um atalho novo, uma mensagem mais clara, uma função que antes precisava de um aplicativo à parte. Raramente algo some, e quando some há aviso com antecedência. As versões do Python são assim: o código que você escreveu para o 3.13 continua rodando no 3.14 quase sempre, e as mudanças que quebram coisas são avisadas versões antes (com os DeprecationWarning, "aviso de obsolescência").
| Termo | O que é |
|---|---|
3.14.4 | 3 = a "geração" do Python (desde 2008); 14 = a versão do ano; 4 = a quarta correção dela. As correções (3.14.1, 3.14.2…) só consertam defeitos, não trazem recursos |
| PEP | Python Enhancement Proposal, "proposta de melhoria": o documento numerado que descreve cada mudança grande (veja PEP 8) |
| Ciclo de vida | Cada versão recebe correções por cerca de cinco anos; a situação de cada uma está em devguide.python.org/versions |
Qual é o meu Python?
import sys print(sys.version) print(sys.version_info) print(sys.version_info >= (3, 14))
$ python3 --version Python 3.14.4 $ python3 versao.py 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] sys.version_info(major=3, minor=14, micro=4, releaselevel='final', serial=0) True
O sys.version_info é uma tupla com nome, e compará-la com (3, 14) diz se o Python é o 3.14 ou mais novo. O editor do guia roda o 3.14 também (uma correção diferente da do terminal da Ana, o que não muda nada nesta página). E o Debian 13, por exemplo, traz o 3.13: as novidades abaixo não funcionam nele.
Python 3.14 3.14
1. Mensagens de erro mais espertas
Desde o 3.10, a cada versão o Python explica melhor os erros. No 3.14, ele passou a reconhecer palavras-chave digitadas errado:
whille True:
pass
$ python3 erros_314.py
File "/home/ana/erros_314.py", line 1
whille True:
^^^^^^
SyntaxError: invalid syntax. Did you mean 'while'?
"Sintaxe inválida. Você quis dizer while?" Antes, era só invalid syntax. Outros casos novos, todos colhidos no 3.14:
nota = 7
if nota >= 9:
print("Ótimo")
else:
print("Continue estudando")
elif nota >= 6:
print("Bom")
$ python3 erro_elif.py
File "/home/ana/erro_elif.py", line 6
elif nota >= 6:
^^^^
SyntaxError: 'elif' block follows an 'else' block
"Um bloco elif depois de um bloco else." O else é sempre o último (veja elif).
estoque = {}
produto = ["arroz", "5 kg"]
estoque[produto] = 12
$ python3 erro_chave.py
Traceback (most recent call last):
File "/home/ana/erro_chave.py", line 3, in <module>
estoque[produto] = 12
~~~~~~~^^^^^^^^^
TypeError: cannot use 'list' as a dict key (unhashable type: 'list')
"Não dá para usar uma list como chave de dicionário (tipo não hashable)." Antes vinha só unhashable type: 'list'; agora a mensagem diz o que você tentou fazer. Listas podem mudar, por isso não servem de chave; uma tupla serve: ("arroz", "5 kg"). O mesmo vale para os conjuntos:
$ python3 erro_conjunto.py
Traceback (most recent call last):
File "/home/ana/erro_conjunto.py", line 2, in <module>
vistos.add({"nome": "Ana"})
~~~~~~~~~~^^^^^^^^^^^^^^^^^
TypeError: cannot use 'dict' as a set element (unhashable type: 'dict')
$ python3 erro_prefixo.py
File "/home/ana/erro_prefixo.py", line 1
dados = ub"abc"
^^
SyntaxError: 'u' and 'b' prefixes are incompatible
"Não dá para usar um dict como elemento de conjunto", e, no segundo, "os prefixos u e b são incompatíveis" (um texto não pode ser ao mesmo tempo texto Unicode e bytes).
2. O modo interativo colorido
No terminal, o >>> do modo interativo agora colore o código enquanto você digita: o prompt em roxo, os textos em verde, os números, as palavras-chave e as funções embutidas cada um com sua cor. E o Tab completa nomes de módulos no import: digite import co e aperte Tab para ver os módulos que começam com "co". As cores também chegaram a outras ferramentas: o relatório do unittest (veja Testes), o código que o pdb mostra (veja Depuração), a ajuda do argparse, os tracebacks.
$ python3
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> nome = "Ana"
>>> t"Olá, {nome}!"
Template(strings=('Olá, ', '!'), interpolations=(Interpolation('Ana', 'nome', None, ''),))
>>> exit()
(Aqui, sem as cores. Esse t"…" é a próxima novidade.) Se as cores atrapalharem, a variável de ambiente NO_COLOR=1 desliga todas.
3. except sem parênteses (PEP 758)
Para tratar dois tipos de erro do mesmo jeito, era obrigatório pôr os tipos entre parênteses: except (ValueError, ZeroDivisionError):. No 3.14, os parênteses podem sair:
texto = "dez"
try:
quantidade = int(texto)
porcao = 100 / quantidade
except ValueError, ZeroDivisionError:
print("Quantidade inválida:", texto)
$ python3 except_sem_parenteses.py Quantidade inválida: dez
Mas só quando não há o as. Com o as (para guardar o erro numa variável), os parênteses continuam obrigatórios, e o 3.14 diz isso com todas as letras:
try:
quantidade = int("dez")
except ValueError, ZeroDivisionError as erro:
print("Deu erro:", erro)
$ python3 except_as.py
File "/home/ana/except_as.py", line 3
except ValueError, ZeroDivisionError as erro:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: multiple exception types must be parenthesized when using 'as'
"Vários tipos de exceção precisam de parênteses quando se usa as." Conserto: except (ValueError, ZeroDivisionError) as erro:. (A aula try e except explica o try.)
Até o 3.13, except ValueError, ZeroDivisionError: é SyntaxError. Se o seu programa precisa rodar em versões mais velhas, continue com os parênteses: eles funcionam em todas.
Missão: tire os parênteses do except, no estilo novo do 3.14. O programa deve continuar mostrando a mensagem de erro.
precos = {"arroz": "27.90", "café": "dezoito"}
try:
preco = float(precos["café"])
except (ValueError, KeyError):
print("Produto ou preço inválido")
precos = {"arroz": "27.90", "café": "dezoito"}
try:
preco = float(precos["café"])
except ValueError, KeyError:
print("Produto ou preço inválido")
4. Template strings: t"…" (PEP 750)
As f-strings montam o texto na hora: f"Olá, {nome}!" vira "Olá, Ana!", e pronto, não dá mais para saber qual parte era fixa e qual veio da variável. A t-string (de template, "modelo") se escreve igual, com t no lugar do f, mas não monta o texto: ela guarda as partes separadas, para uma função decidir o que fazer com cada uma.
nome = "Ana"
fstring = f"Olá, {nome}!"
template = t"Olá, {nome}!"
print(type(fstring), fstring)
print(type(template))
print(list(template))
print(template.strings)
print(template.values)
$ python3 tstring.py
<class 'str'> Olá, Ana!
<class 'string.templatelib.Template'>
['Olá, ', Interpolation('Ana', 'nome', None, ''), '!']
('Olá, ', '!')
('Ana',)
- t"Olá, {nome}!"
- Uma t-string. O resultado não é um
str: é um objetoTemplate, do módulostring.templatelib. - list(template)
- Percorrer o template entrega as partes em ordem: os pedaços fixos (textos comuns) e as interpolações (as partes entre chaves).
- Interpolation('Ana', 'nome', None, '')
- Uma interpolação guarda o valor (
'Ana'), o código que estava entre as chaves ('nome') e a formatação, se houver. - template.strings / template.values
- Só os pedaços fixos / só os valores.
Para que serve? Para tratar de um jeito o que você escreveu e de outro o que veio de fora. O exemplo clássico é uma página de internet: se um visitante escreve um comentário com código HTML dentro, e o site cola o comentário direto na página, o código do visitante roda no navegador de todo mundo (é o "primo" do SQL injection). Com uma t-string, a função pode "desarmar" só os valores:
from html import escape
from string.templatelib import Interpolation
def html(template):
partes = []
for parte in template:
if isinstance(parte, Interpolation):
partes.append(escape(str(parte.value)))
else:
partes.append(parte)
return "".join(partes)
comentario = "<script>roubar()</script> Adorei o bolo!"
print(f"<p>{comentario}</p>")
print(html(t"<p>{comentario}</p>"))
$ python3 tstring_html.py <p><script>roubar()</script> Adorei o bolo!</p> <p><script>roubar()</script> Adorei o bolo!</p>
- A função
html()percorre as partes do template. As partes fixas (<p>e</p>, que você escreveu) passam do jeito que estão. - As interpolações (o comentário, que veio do visitante) passam pelo
escape()do módulohtml, que troca<por<e>por>. O navegador mostra esses códigos como os sinais, mas não executa nada. - Com a f-string, o
<script>foi colado inteiro. Com a t-string, saiu desarmado, e o<p>que você escreveu continuou funcionando.
Uma t-string não é um texto: para mostrar, alguma função tem de transformá-la. Tentar usá-la como texto dá erro:
nome = "Ana"
template = t"Olá, {nome}!"
print(template)
print("Bem-vinda: " + template)
$ python3 tstring_str.py
Template(strings=('Olá, ', '!'), interpolations=(Interpolation('Ana', 'nome', None, ''),))
Traceback (most recent call last):
File "/home/ana/tstring_str.py", line 4, in <module>
print("Bem-vinda: " + template)
~~~~~~~~~~~~~~^~~~~~~~~~
TypeError: can only concatenate str (not "string.templatelib.Template") to str
O print mostrou a "ficha técnica" do template, e não "Olá, Ana!". E o + recusou: "só dá para juntar str com str (não com Template)". No dia a dia, para montar texto, continue com as f-strings. As t-strings são para quem escreve bibliotecas que precisam tratar os valores com cuidado (HTML, SQL, comandos, logs); você vai usá-las através dessas bibliotecas.
Missão: o nome do cliente veio com um código HTML (<b>). A função html() já sabe desarmar os valores, mas só funciona com uma t-string. Troque o f por t na linha do print e rode: o <b> do nome tem de sair como <b>.
from html import escape
from string.templatelib import Interpolation
def html(template):
partes = []
for parte in template:
if isinstance(parte, Interpolation):
partes.append(escape(str(parte.value)))
else:
partes.append(parte)
return "".join(partes)
cliente = "<b>Ana</b>"
print(html(f"<p>Pedido de {cliente} saiu para entrega</p>"))
from html import escape
from string.templatelib import Interpolation
def html(template):
partes = []
for parte in template:
if isinstance(parte, Interpolation):
partes.append(escape(str(parte.value)))
else:
partes.append(parte)
return "".join(partes)
cliente = "<b>Ana</b>"
print(html(t"<p>Pedido de {cliente} saiu para entrega</p>"))
Por que a versão com f não deu erro? Porque um texto comum também pode ser percorrido (letra por letra), e nenhuma letra é uma Interpolation: a função devolveu o texto sem desarmar nada. É exatamente o perigo que a t-string evita.
5. Anotações adiadas (PEP 649)
As dicas de tipo (anotações) dizem que tipo cada parâmetro espera. Até o 3.13, o Python calculava as anotações no momento do def; se uma anotação citava uma classe definida mais abaixo no arquivo, dava NameError, e o truque era escrevê-la entre aspas (-> "Cliente"). No 3.14, as anotações só são calculadas quando alguém pede por elas:
def cadastrar(nome: str) -> Cliente:
return Cliente(nome)
class Cliente:
def __init__(self, nome: str) -> None:
self.nome = nome
ana = cadastrar("Ana")
print(ana.nome)
print(cadastrar.__annotations__)
$ python3 anotacoes.py
Ana
{'nome': <class 'str'>, 'return': <class '__main__.Cliente'>}
A função cadastrar foi criada antes de existir a classe Cliente, e não deu erro: quando o print pediu as anotações (__annotations__), a classe já existia. Para quem lê as anotações por programa, o módulo novo annotationlib pode entregá-las de três jeitos, inclusive quando um nome não existe:
from annotationlib import Format, get_annotations
def entregar(pedido: Pedido, endereco: str) -> None:
pass
print(get_annotations(entregar, format=Format.STRING))
print(get_annotations(entregar, format=Format.FORWARDREF))
print(get_annotations(entregar))
$ python3 anotacoes_lib.py
{'pedido': 'Pedido', 'endereco': 'str', 'return': 'None'}
{'pedido': ForwardRef('Pedido', owner=<function entregar at 0x7fd70d37f320>), 'endereco': <class 'str'>, 'return': None}
Traceback (most recent call last):
File "/home/ana/anotacoes_lib.py", line 10, in <module>
print(get_annotations(entregar))
~~~~~~~~~~~~~~~^^^^^^^^^^
File "/usr/lib/python3.14/annotationlib.py", line 966, in get_annotations
ann = _get_dunder_annotations(obj)
File "/usr/lib/python3.14/annotationlib.py", line 1159, in _get_dunder_annotations
ann = getattr(obj, "__annotations__", None)
File "/home/ana/anotacoes_lib.py", line 4, in __annotate__
def entregar(pedido: Pedido, endereco: str) -> None:
^^^^^^
NameError: name 'Pedido' is not defined
- Format.STRING
- As anotações como textos, exatamente como foram escritas. Nunca dá erro.
- Format.FORWARDREF
- Os valores reais quando existem (
str,None) e uma "referência adiantada" (ForwardRef('Pedido')) para o que ainda não existe. - sem formato (VALUE)
- Os valores reais. Como
Pedidonunca foi definido, o cálculo atrasado deuNameError, e o traceback mostra a linha dodef(dentro de uma função escondida chamada__annotate__).
Repare: o erro aconteceu na linha 10, quando as anotações foram pedidas, e não na linha 4, onde o def foi escrito. Esse é o "adiado". Para quem só escreve dicas de tipo, a mudança é simples: as aspas em volta de nomes definidos mais abaixo não são mais necessárias.
__annotations__ do módulo sumiu
Uma consequência que pega quem vem de versões antigas: anotações de variáveis soltas no arquivo também são adiadas, e o nome __annotations__ não existe mais "solto" no módulo:
preco: float = 27.90 print(__annotations__)
$ python3 modulo_anot.py
Traceback (most recent call last):
File "/home/ana/modulo_anot.py", line 2, in <module>
print(__annotations__)
^^^^^^^^^^^^^^^
NameError: name '__annotations__' is not defined. Did you mean: '__annotate__'?
No 3.13, isso mostrava {'preco': <class 'float'>}. No 3.14, a dica aponta o __annotate__, a função escondida que calcula as anotações. Para lê-las, peça ao módulo: sys.modules[__name__].__annotations__ (com import sys) ou annotationlib.get_annotations() passando o módulo.
6. return dentro do finally agora dá aviso (PEP 765)
O bloco finally roda sempre, com erro ou sem erro (veja else e finally). Um return lá dentro "engole" qualquer erro, e o programa segue como se nada tivesse acontecido. O 3.14 passou a avisar:
def dividir(a, b):
try:
return a / b
finally:
return "acabou"
print(dividir(10, 0))
$ python3 finally_return.py /home/ana/finally_return.py:5: SyntaxWarning: 'return' in a 'finally' block return "acabou" acabou
Dividir por zero devia dar ZeroDivisionError, mas o return do finally jogou o erro fora e a função devolveu "acabou". O SyntaxWarning ("aviso de sintaxe": não para o programa) aponta o problema. O mesmo aviso vale para break e continue que saem de um finally. Conserto: tire o return do finally; ele serve para "arrumar a casa" (fechar arquivos, por exemplo), não para devolver valores.
7. Pequenas melhorias úteis
from pathlib import Path
lista = Path("compras.txt")
lista.write_text("arroz\nfeijão\n", encoding="utf-8")
copia = lista.copy("compras-backup.txt")
print(copia, copia.read_text(encoding="utf-8").split())
pasta = Path("antigas")
pasta.mkdir(exist_ok=True)
movida = copia.move_into(pasta)
print(movida, movida.exists(), copia.exists())
$ python3 pathlib_copia.py compras-backup.txt ['arroz', 'feijão'] antigas/compras-backup.txt True False
O pathlib ganhou copy() (copiar), copy_into() (copiar para dentro de uma pasta), move() (mover) e move_into() (mover para dentro de uma pasta). Antes, era preciso o módulo shutil. Repare na última linha: depois de mover, o arquivo existe na pasta nova (True) e não mais no lugar antigo (False).
precos = [27.90, 8.49, 4.99] quantidades = [2, 3] print(list(map(lambda p, q: p * q, precos, quantidades))) print(list(map(lambda p, q: p * q, precos, quantidades, strict=True)))
$ python3 map_strict.py
[55.8, 25.47]
Traceback (most recent call last):
File "/home/ana/map_strict.py", line 5, in <module>
print(list(map(lambda p, q: p * q, precos, quantidades, strict=True)))
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: map() argument 2 is shorter than argument 1
Três preços e só duas quantidades: o map() comum para calado no menor (o açúcar sumiu da conta). Com strict=True ("estrito"), novo no 3.14, ele avisa: "o argumento 2 é mais curto que o argumento 1". O zip() já tinha essa opção desde o 3.10.
x = 1234.567891
print(f"{x:,.6f}")
print(f"{x:,.6_f}")
print(f"{x:_._f}")
$ python3 formatar.py 1,234.567891 1,234.567_891 1_234.567_891
Na formatação, o separador de milhares (, ou _) agora também pode agrupar as casas decimais, de três em três: basta repeti-lo depois do ponto.
| Novidade do 3.14 | Em uma frase |
|---|---|
uuid.uuid7() | Identificadores únicos que já vêm em ordem de criação (bons para números de pedido); também uuid6() e uuid8() |
compression.zstd | Um módulo novo para o formato de compressão Zstandard (PEP 784) |
concurrent.interpreters | Vários interpretadores Python no mesmo programa, rodando em paralelo (PEP 734) |
| Python sem GIL (free-threaded) | A versão do Python que roda threads realmente em paralelo passou a ser oficialmente suportada, mas continua opcional (PEP 779) |
python3 -m pdb -p PID | Conectar o depurador a um programa que já está rodando (PEP 768); veja Depuração |
unittest | Saída colorida e conferências novas, como assertStartsWith; veja Testes |
sqlite3 | Marcadores com nome (:nome) com uma tupla viraram erro; veja sqlite3 |
python3 -c | O código passado ao -c agora pode vir indentado: o Python tira o recuo comum |
Python 3.15 3.15
O Python deste guia (no terminal da Ana e no editor) é o 3.14, que não entende o que vem abaixo. Os exemplos com >>> desta seção foram copiados da página oficial What's New in Python 3.15 (docs.python.org/3.15/whatsnew/3.15.html) e não foram rodados aqui. As saídas que aparecem com $ python3 são do 3.14 de verdade, mostrando o que acontece quando se tenta usar a novidade numa versão que ainda não a tem.
1. lazy import: importar só quando usar (PEP 810)
Um programa grande pode demorar para abrir só por causa dos imports: cada módulo é lido e executado no começo, mesmo que o programa nunca o use naquela vez. No 3.15, a palavra lazy ("preguiçoso") adia o carregamento até o primeiro uso:
lazy import json
lazy from pathlib import Path
print("Abrindo...") # json e pathlib ainda não foram carregados
dados = json.loads('{"a": 1}') # o json é carregado aqui
Os imports continuam no topo do arquivo, como pede a PEP 8, mas o custo só é pago quando o nome é usado. O lazy só vale no "corpo" do módulo (dentro de uma função ou de um try, é SyntaxError). No 3.14, a palavra nem existe:
$ python3 so315c.py
File "/home/ana/so315c.py", line 1
lazy import json
^^^^^^
SyntaxError: invalid syntax
2. frozendict: o dicionário que não muda (PEP 814)
Assim como o frozenset é o conjunto que não muda (veja Conjuntos), o frozendict é o dicionário congelado: depois de criado, não aceita chaves novas nem mudanças. Em troca, pode ser chave de outro dicionário ou item de um conjunto. Da documentação:
>>> a = frozendict(x=1, y=2)
>>> a
frozendict({'x': 1, 'y': 2})
>>> a['z'] = 3
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
a['z'] = 3
~^^^^^
TypeError: 'frozendict' object does not support item assignment
>>> b = frozendict(y=2, x=1)
>>> hash(a) == hash(b)
True
>>> a == b
True
E no 3.14, o nome não existe (repare na dica do Python, que sugere o parente mais próximo):
$ python3 so315b.py
Traceback (most recent call last):
File "/home/ana/so315b.py", line 1, in <module>
config = frozendict(tema="escuro", fonte=14)
^^^^^^^^^^
NameError: name 'frozendict' is not defined. Did you mean: 'frozenset'?
3. * e ** dentro das comprehensions (PEP 798)
Para "achatar" uma lista de listas numa lista só, era preciso uma comprehension com dois for. No 3.15, o * de desempacotar pode entrar na comprehension:
>>> lists = [[1, 2], [3, 4], [5]]
>>> [*L for L in lists] # equivalent to [x for L in lists for x in L]
[1, 2, 3, 4, 5]
>>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
>>> {**d for d in dicts} # equivalent to {k: v for d in dicts for k,v in d.items()}
{'a': 3, 'b': 2}
No 3.14, isso é um erro com mensagem própria:
$ python3 so315.py
File "/home/ana/so315.py", line 2
print([*l for l in listas])
^^
SyntaxError: iterable unpacking cannot be used in comprehension
"Desempacotamento não pode ser usado numa comprehension." No 3.14, use a forma com dois for: [x for l in listas for x in l].
4. UTF-8 por padrão (PEP 686)
Quando você abre um arquivo de texto sem dizer o encoding (a "tabela" que transforma letras em bytes), o Python usava a do sistema. No Linux e no macOS quase sempre é UTF-8, mas no Windows podia ser outra, e um arquivo com "ç" e "ã" gravado num computador saía embaralhado no outro. No 3.15, open("compras.txt") usa UTF-8 em qualquer sistema. Mesmo assim, a recomendação continua: escreva encoding="utf-8", como nas aulas de arquivos, e o programa funciona igual em todas as versões.
5. Mais dicas nas mensagens de erro
Quem vem de outra linguagem costuma usar o nome de método de lá. No 3.14, a mensagem só diz que o método não existe:
$ python3 so315d.py
Traceback (most recent call last):
File "/home/ana/so315d.py", line 2, in <module>
compras.push("feijão")
^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'push'
No 3.15, o Python reconhece nomes comuns do JavaScript, do Java, do Ruby e do C#, e sugere o equivalente. Da documentação:
>>> [1, 2, 3].push(4)
AttributeError: 'list' object has no attribute 'push'. Did you mean '.append'?
>>> 'hello'.toUpperCase()
AttributeError: 'str' object has no attribute 'toUpperCase'. Did you mean '.upper'?
>>> {}.put("a", 1)
AttributeError: 'dict' object has no attribute 'put'. Use d[k] = v.
>>> (1, 2, 3).append(4)
AttributeError: 'tuple' object has no attribute 'append'. Did you mean to use a 'list' object?
6. O resto, em uma frase
| Novidade do 3.15 | Em uma frase |
|---|---|
sentinel (PEP 661) | Um tipo embutido para criar "valores marcadores" únicos, como um None próprio que quer dizer "não informado" |
profiling e o Tachyon (PEP 799) | Um pacote novo para medir onde o programa gasta tempo, com um medidor por amostragem rápido |
math.integer | Um módulo novo com as funções matemáticas para números inteiros (PEP 791) |
| Mais cores | A ajuda do python3 --help, o argparse, o calendar, o timeit, a linha de comando do sqlite3 (que também completa SQL com Tab) e outras |
| Modo interativo | O Tab colore as sugestões pelo tipo de objeto e sugere os nomes de dentro de um módulo no from … import |
pdb | O (Pdb) usa o mesmo editor de linha do modo interativo novo |
| JIT | O compilador experimental "na hora" (just-in-time), que acelera o Python, foi bastante melhorado |
sqlite3.connect() | Todos os parâmetros, menos o nome do banco, passam a ser só nomeados (timeout=5, e não um 5 solto) |
Formas de lidar com versões diferentes
| Situação | O que fazer |
|---|---|
| Você está aprendendo | Use a versão que o seu sistema traz (no Ubuntu 26.04, o 3.14) e não se preocupe |
| O programa vai rodar em computadores com Pythons diferentes | Escreva no estilo da versão mais velha que precisa funcionar (por exemplo, except (A, B): com parênteses) |
| Quer usar um recurso novo e avisar quem tiver Python velho | if sys.version_info < (3, 14): sys.exit("Este programa precisa do Python 3.14") |
| Quer experimentar o 3.15 sem trocar o do sistema | Instale-o à parte, sem mexer no python3 do sistema (veja Instalar o Python), e use um ambiente virtual com ele |
| Quer saber o que mudou numa versão | Leia a página What's New dela em docs.python.org/3/whatsnew/ |
Quando dá errado
O erro mais comum com novidades é rodar o código numa versão que não as tem. Os sinais: SyntaxError: invalid syntax numa linha que parece certa (lazy import, except A, B: no 3.13), ou NameError para um nome que a documentação garante que existe (frozendict no 3.14). Antes de procurar o erro no código, confira a versão: python3 --version.
as sem parênteses no except
A novidade do 3.14 tem um limite: except ValueError, ZeroDivisionError as erro: dá SyntaxError: multiple exception types must be parenthesized when using 'as', como você viu na seção 3. Com as, parênteses: except (ValueError, ZeroDivisionError) as erro:.
print(t"…") mostra Template(strings=…), e "texto" + t"…" dá TypeError: can only concatenate str (not "string.templatelib.Template") to str (seção 4). Uma t-string precisa de uma função que a transforme. Se você só quer montar um texto, a ferramenta é a f-string.
Missão: este programa tem três erros, e as mensagens do Python 3.14 apontam cada um. Rode, leia a mensagem, conserte e rode de novo, até o fim. (Dica: palavra-chave digitada errado, a ordem do elif e uma lista que não pode ser chave de dicionário.)
contador = 0
whille contador < 3:
contador += 1
nota = 7
if nota >= 9:
print("Ótimo")
else:
print("Continue estudando")
elif nota >= 6:
print("Bom")
estoque = {}
produto = ["arroz", "5 kg"]
estoque[produto] = 12
print("Fim:", contador, estoque)
contador = 0
while contador < 3:
contador += 1
nota = 7
if nota >= 9:
print("Ótimo")
elif nota >= 6:
print("Bom")
else:
print("Continue estudando")
estoque = {}
produto = ("arroz", "5 kg")
estoque[produto] = 12
print("Fim:", contador, estoque)
Referência rápida
| Recurso | Versão | Exemplo |
|---|---|---|
except sem parênteses | 3.14 | except ValueError, KeyError: |
| Template strings | 3.14 | t"Olá, {nome}!" → Template |
| Anotações adiadas | 3.14 | def f() -> Cliente: antes de class Cliente; annotationlib.get_annotations() |
Aviso de return/break/continue no finally | 3.14 | SyntaxWarning: 'return' in a 'finally' block |
Copiar e mover com pathlib | 3.14 | Path("a.txt").copy("b.txt"), .move_into(pasta) |
map(..., strict=True) | 3.14 | Erro se as sequências tiverem tamanhos diferentes |
Modo interativo colorido, Tab no import | 3.14 | python3 |
lazy import | 3.15 | lazy import json |
frozendict | 3.15 | frozendict(x=1, y=2) |
*/** em comprehensions | 3.15 | [*l for l in listas] |
| UTF-8 por padrão | 3.15 | open("a.txt") lê e grava em UTF-8 |
| Versão em uso | todas | python3 --version, sys.version_info >= (3, 14) |
Exercícios
1. A letra da t-string
Uma f-string começa com f. Com que letra começa uma template string?
2. Qual Python?
Complete o comando que mostra a versão do Python no terminal:
3. No Python 3.14, qual destas linhas é SyntaxError?
4. O que t"Olá, {nome}!" produz?
5. No Python 3.14, uma função anotada com -> Cliente, escrita antes da class Cliente:
6. Você roda config = frozendict(tema="escuro") e recebe NameError: name 'frozendict' is not defined. A causa mais provável:
Resumo
- Sai um Python novo todo outubro. O deste guia é o 3.14 (outubro de 2025); o 3.15 saiu em 9 de outubro de 2026. Confira a sua com
python3 --version. - 3.14: erros mais claros (
Did you mean 'while'?,'elif' block follows an 'else' block,cannot use 'list' as a dict key) e modo interativo colorido. - 3.14:
except A, B:sem parênteses, mas comasos parênteses continuam. - 3.14:
t"…"cria umTemplate, que guarda os valores separados para uma função tratá-los com cuidado; para montar texto, continue com f-strings. - 3.14: anotações adiadas (nada de aspas para nomes definidos depois), aviso de
returnnofinally,Path.copy()/move(),map(strict=True). - 3.15:
lazy import,frozendict,[*l for l in listas], UTF-8 por padrão e dicas comoDid you mean '.append'?. Num Python mais velho, eles dãoSyntaxErrorouNameError.