Armadilhas comuns e o estilo de questão da Python Institute
TL;DR
As notas 02 e 03 deste galho mapearam os blocos oficiais do syllabus às notas-fonte dos Galhos 1-6. Esta nota faz outra coisa: isola o padrão de pegadinha que se repete de questão em questão na Python Institute, independente de qual bloco ela está testando. Toda prova PCEP/PCAP é dominada por uma pergunta: “o que este código imprime?” — e a Python Institute tem um catálogo relativamente pequeno de armadilhas que reaparecem disfarçadas em sintaxes diferentes: mutação por referência disfarçada de “só li a variável”, escopo LEGB armado pra explodir com
UnboundLocalError, precedência de operador que separabooldeintno resultado, slicing com passo negativo, o cache de inteiros pequenos do CPython fazendois“funcionar por acidente”, o argumento default mutável,+=custando O(n²) sem avisar, comparação encadeada, etype()vsisinstance()sob herança. Cada armadilha aqui é nova em relação às notas 02/03 (que já cobriramelsede loop,finally/return,find/index, comparação de strings) — o objetivo é fechar o catálogo antes do simulado final da nota 08.
Por que a Python Institute pergunta assim
Questões de múltipla escolha que testam “o que aparece na tela” são baratas de corrigir automaticamente e caras de acertar no chute — exigem simular o interpretador na cabeça, sem rodar nada. É o formato dominante nas provas PCEP-30-02 e PCAP-31-03 (confirmado nas notas 02 e 03 deste galho, syllabus oficial pythoninstitute.org). O padrão se repete porque as armadilhas exploram um número pequeno de comportamentos “não óbvios mas documentados” do Python — a mesma dezena de armadilhas reaparece vestida com nomes de variável diferentes, tipos diferentes, valores numéricos diferentes. Decorar a lista de armadilhas vale mais, ponto a ponto, do que decorar sintaxe: quem já fez os Galhos 1-6 sabe a sintaxe; o que falta é o reflexo de “opa, isso é uma das armadilhas conhecidas”.
flowchart TD A["Pegadinha Python Institute"] --> B["Referência e mutação"] A --> C["Escopo e nomes"] A --> D["Avaliação de expressão"] A --> E["Sequências e slicing"] A --> F["Identidade vs igualdade"] A --> G["Tipos e checagem"] B --> B1["mutar lista/dict dentro de função"] B --> B2["argumento default mutável"] C --> C1["UnboundLocalError sem global"] C --> C2["closure tardia em loop"] D --> D1["precedência aritmética/lógica/bitwise"] D --> D2["+= em string dentro de loop"] D --> D3["comparação encadeada 1 < x < 10"] E --> E1["lista[::-1] — passo negativo"] E --> E2["lista[-3:-1] — dois negativos"] F --> F1["is vs == e o cache -5..256"] G --> G1["type() vs isinstance() com herança"] style A fill:#4a5568,color:#fff
Mutação por referência disfarçada de leitura
O erro mental mais caro em prova: olhar def f(lista): e assumir que, como Python “passa tudo por valor” (mito comum de quem vem de C), a função não pode afetar o chamador. Python passa referências a objetos — se o objeto é mutável (lista, dict, set) e a função chama um método que muta in-place (.append(), .pop(), [chave] = valor), o objeto original muda, porque não existe cópia nenhuma no meio do caminho. Isso já foi explicado em profundidade em Core 02 (mutabilidade) — o ângulo novo aqui é o formato exato como a prova testa isso: uma função que parece “só processar” a lista, sem return, e a pergunta é sobre o estado da variável depois da chamada.
def processa(dados):
dados.append(99)
dados = dados + [100] # reatribuição LOCAL — não afeta o chamador
dados.append(101)
numeros = [1, 2, 3]
processa(numeros)
print(numeros)O que este código imprime?
[1, 2, 3, 99]. A primeira linha (dados.append(99)) muta o objeto original —dadosenumerosapontam pra mesma lista na memória, então.append()afeta ambos os nomes. A segunda linha (dados = dados + [100]) não muta nada:dados + [100]cria uma lista nova, edados = ...só reaponta o nome localdadospra essa lista nova, sem tocar no objeto quenumerosainda referencia. A terceira linha (.append(101)) muta essa lista nova, que só existe dentro da função e é descartada quandoprocessaretorna. Essa mistura de mutação in-place com reatribuição no mesmo bloco de código é o formato exato que a Python Institute usa pra testar se você entende a diferença entre “mutar o objeto” e “reatribuir o nome” — ver Core 02, seção de mutabilidade e identidade.
O mesmo padrão aparece com dicionários — e a prova gosta de combinar com .get() pra criar uma armadilha dupla:
def atualiza(cache, chave):
valor = cache.get(chave, 0)
valor += 1
cache[chave] = valor
contagem = {"a": 1}
atualiza(contagem, "a")
atualiza(contagem, "b")
print(contagem)O que este código imprime?
{'a': 2, 'b': 1}. Repare quevalor += 1opera numa variável local de tipoint(imutável) — isso não muta nada por referência, é reatribuição pura. A mutação real acontece só na linhacache[chave] = valor, que grava de volta no dicionário compartilhado. A pegadinha é achar que, como a função “trabalha com”cache, qualquer coisa dentro dela é automaticamente uma mutação — quando na verdade o que muta é só o que passa por atribuição de item (cache[chave] = ...) ou método mutante (.append(),.update(),.pop()etc.), nunca reatribuição de variável local.
Argumento default mutável — a pegadinha clássica, com uma volta a mais
Core 06 já documenta a regra: um valor default é avaliado uma única vez, no momento em que a def é executada (não a cada chamada), e fica gravado no objeto função — se esse default é mutável, toda chamada que não passa o argumento explicitamente compartilha o mesmo objeto. A versão que a prova mais gosta de testar não é o exemplo isolado — é o efeito acumulado ao longo de várias chamadas em sequência, porque é isso que separa quem decorou a regra de quem entende o mecanismo por trás dela:
def historico(item, log=[]):
log.append(item)
return log
a = historico("x")
b = historico("y")
c = historico("z", log=[])
d = historico("w")
print(a, b, c, d)O que este código imprime?
['x', 'y', 'w'] ['x', 'y', 'w'] ['z'] ['x', 'y', 'w'].a,bedsão o mesmo objeto lista — cada chamada que não passalogexplicitamente reaproveita a lista default criada uma única vez quandodef historico(...)foi executada, então os.append()dea,bedse acumulam todos na mesma lista, e por isso os três nomes imprimem o conteúdo final idêntico (a lista mudou de baixo dos seus pés depois queaebjá tinham sido atribuídos — o valor “congelado” que você esperava nunca existiu, porque nomes de lista sempre apontam pro objeto vivo).cé diferente porque a chamada passoulog=[]explicitamente, criando uma lista nova só pra essa chamada. A correção padrão — usarNonecomo sentinela e criar a lista dentro do corpo da função (if log is None: log = []) — está detalhada no[!warning]de Core 06, seção “Valores default”. A mesma regra vale paradict()eset()como default.
Escopo LEGB armado pra explodir
Core 06 já explica a regra LEGB e o UnboundLocalError por reatribuição sem global. O ângulo novo desta nota é o formato de closure tardia dentro de loop — uma armadilha de escopo diferente, que não aparece na nota-fonte porque pertence mais à interseção entre loops e funções do que a escopo básico isolado:
funcoes = []
for i in range(3):
funcoes.append(lambda: i)
resultados = [f() for f in funcoes]
print(resultados)O que este código imprime?
[2, 2, 2], não[0, 1, 2]como a intuição sugere. Cadalambda: inão captura o valor deino momento em que foi criada — captura o nomei, que é resolvido no escopo envolvente (enclosing, oEdo LEGB) só na hora em que a lambda é chamada, não na hora em que é definida. Quando o loop termina,ivale2(o último valor atribuído), e como as três lambdas compartilham a mesma variávelido escopo da função/módulo que as contém, todas devolvem2. O fix clássico é forçar a captura por valor via um argumento default (lambda i=i: i), porque valores default são avaliados no momento da definição — a mesma regra que vira pegadinha com listas mutáveis, aqui usada a favor. Essa armadilha combina escopo (LEGB) com o momento de avaliação de expressão, os dois eixos mais testados da prova.
Precedência de operadores além da tabela decorada
Core 03 já tem a tabela completa de precedência e cobre a mistura de bitwise com comparação. O que a prova gosta de fazer — e que vale destacar isolado — é misturar aritmética com exponenciação e criar a ilusão de associatividade errada, porque ** é o único operador aritmético binário em Python que associa à direita:
print(2 + 3 * 2 ** 2)
print(2 ** 3 ** 2)O que estas duas linhas imprimem?
14e512. Na primeira,**tem precedência mais alta que*, que por sua vez tem precedência mais alta que+: primeiro2 ** 2 = 4, depois3 * 4 = 12, depois2 + 12 = 14. Na segunda, a pegadinha é a associatividade:**associa à direita, então2 ** 3 ** 2é2 ** (3 ** 2)=2 ** 9=512, não(2 ** 3) ** 2=64(que seria o resultado se você (erradamente) assumisse associatividade à esquerda, como a maioria dos outros operadores binários de Python). Nenhum outro operador aritmético comum se comporta assim — é o único caso de associatividade à direita fora dos operadores de atribuição, e a Python Institute testa exatamente essa exceção.
A segunda armadilha de precedência mistura operador lógico (and/or, que trabalha com truthiness e devolve um dos operandos) com operador bitwise (&/|, que trabalha bit a bit em inteiros e sempre devolve int ou bool conforme o tipo dos operandos):
a = 6 # 0b110
b = 3 # 0b011
print(a and b)
print(a & b)
print(bool(a) and bool(b))O que estas três linhas imprimem?
3,2,True.a and bé lógico: comoa(6) já é truthy, oandavalia e devolve o segundo operando (b, valor3) — não um booleano, o valor debem si (comportamento já coberto em Core 03, “Assumir queand/orsempre retornambool”).a & bé bitwise:0b110 & 0b011 = 0b010 = 2, uma operação bit a bit que não tem nada a ver com truthiness.bool(a) and bool(b)converte ambos praboolantes doand, então devolveTruede fato. A prova adora trocarand/orpor&/|(ou vice-versa) num trecho de código e perguntar o resultado — os símbolos parecem intercambiáveis pra quem vem de linguagens onde só existe uma família de operador lógico, mas em Python são dois mundos com semânticas completamente diferentes.
+= em string dentro de loop
Strings são imutáveis — isso já está em Core 07. O que a prova testa aqui não é o valor final (que costuma ser óbvio), mas o custo e o mecanismo: cada += numa string dentro de um loop não modifica nada in-place, porque não existe “in-place” possível para um str — cria uma string totalmente nova a cada iteração e reatribui o nome pra ela.
resultado = ""
for c in "abc":
resultado += c.upper()
print(resultado)O que este código imprime, e por que a prova destaca esse padrão?
Imprime
"ABC"— o valor não surpreende ninguém. O que a Python Institute testa com essa construção é o entendimento do mecanismo, geralmente numa questão teórica separada: cadaresultado += c.upper()descarta a string antiga e aloca uma nova, copiando todo o conteúdo anterior mais o caractere novo. Para um loop deniterações, isso é O(n²) no total (cada concatenação copia uma string cada vez maior), enquanto o idiomático"".join(c.upper() for c in "abc")é O(n) porque o.join()sabe o tamanho final antecipadamente e aloca o buffer uma vez só. A prova não costuma pedir a notação Big-O explicitamente (isso é PCAP-adjacente, não exigido no syllabus), mas testa se você sabe apontar"".join(...)como a alternativa correta quando a pergunta é “qual destas opções constrói a string de forma mais eficiente”.
Comparação encadeada além do básico
Core 03 já menciona 1 < x < 10 na seção “Em entrevista” como equivalente a 1 < x and x < 10. A armadilha nova aqui é o que acontece quando a cadeia mistura tipos ou quando um dos operandos tem efeito colateral — porque x só é avaliado uma vez, mesmo aparecendo logicamente duas vezes na comparação:
def registra(n):
print(f"avaliando {n}")
return n
if 1 < registra(5) < 10:
print("dentro do intervalo")O que este código imprime?
avaliando 5seguido dedentro do intervalo— a funçãoregistraé chamada uma única vez, não duas. Diferente de1 < registra(5) and registra(5) < 10(que chamaria a função duas vezes), a comparação encadeada1 < registra(5) < 10avaliaregistra(5)só uma vez e reaproveita o valor pros dois lados da cadeia. Essa diferença — encadeamento nativo vs.andmanual com a expressão repetida — é o ponto exato que separa “sei que1 < x < 10funciona” de “sei por que ele é mais seguro que a versão equivalente comand” quando a expressão do meio tem efeito colateral (I/O, mutação, chamada de função cara).
Slicing com passo negativo em coleções, não só strings
A nota 03 já cobriu s[::-1] e s[-3:-1] para strings. A mesma sintaxe se aplica identicamente a listas e tuplas (todas são sequências no mesmo sentido do data model — ver Collections 01), e a prova gosta de testar o passo negativo combinado com limites explícitos, que é onde a intuição costuma falhar de verdade:
lista = [10, 20, 30, 40, 50]
print(lista[::-1])
print(lista[-3:-1])
print(lista[::-2])
print(lista[4:1:-1])O que estas quatro linhas imprimem?
[50, 40, 30, 20, 10],[30, 40],[50, 30, 10],[50, 40, 30]. A primeira é a reversão total via passo-1sem limites — o idioma mais cobrado de slicing em toda a prova. A segunda pega do índice-3(30) até o índice-1exclusive (50fica de fora) — a mesma regra “[a:b]sempre inclusive-exclusive” vale igual com índices negativos. A terceira reversão-com-salto pega elementos de trás pra frente pulando de 2 em 2, começando no último. A quarta é a mais traiçoeira: quando o passo é negativo, os limitesinício:fimtambém são lidos “de trás pra frente” —lista[4:1:-1]começa no índice4(50) e anda pra trás até o índice1exclusive (20fica de fora), então devolve[50, 40, 30]. Trocar a ordem dos limites (lista[1:4:-1], início menor que fim com passo negativo) não levanta erro — devolve uma lista vazia[], silenciosamente, porque não existe caminho válido “pra trás” de um índice menor pra um maior. Slicing nunca levantaIndexErrormesmo quando o resultado é vazio ou os limites estão fora do range — só indexação simples (lista[10]) levanta.
is vs == — o cache de inteiros pequenos do CPython
Este é o item mais citado em qualquer fórum de preparação pra PCEP/PCAP, e a razão de fundo está em CPython internals, nota 02 (Galho 6) — esta nota não repete a explicação de por que o cache existe (interning de inteiros de -5 a 256, decisão de implementação do CPython, não parte da especificação da linguagem), só o efeito observável que a prova cobra:
a = 100
b = 100
print(a is b)
c = 300
d = 300
print(c is d)
e, f = 300, 300
print(e is f)O que estas três linhas imprimem?
True,False(na maioria dos casos — depende do interpretador e do modo de execução),True. A primeira:100está dentro do intervalo-5..256cacheado pelo CPython, entãoaebapontam pro mesmo objetointna memória, eis(identidade) dáTrue. A segunda:300está fora do cache, então cada literal300— avaliado como expressão separada, em declarações separadas — costuma criar um objetointnovo, eisdáFalsemesmo os valores sendo iguais (==sempre dariaTruenos três casos, porque==compara valor, não identidade). A terceira é a mais traiçoeira: quando os dois literais300aparecem na mesma linha de código, compilados no mesmo bloco (e, f = 300, 300), o compilador do CPython pode aplicar peephole optimization e reaproveitar a mesma constante — nesse caso,isdáTruepor um motivo totalmente diferente do cache de small ints. O ponto que a prova testa, no fim, é sempre o mesmo:isnunca é a ferramenta certa pra comparar valor — o fato de “às vezes funcionar” pra inteiros pequenos é um detalhe de implementação do CPython, não uma garantia da linguagem, e código que depende disso é um bug esperando a versão errada do interpretador (ou o valor errado, fora do intervalo-5..256) pra explodir. Regra de prova:==para valor,issó paraNone/identidade de objeto deliberada.
O intervalo exato não é garantia de linguagem
-5a256é o comportamento do CPython especificamente (a implementação de referência, a que a prova assume) — não está na especificação da linguagem Python e pode variar em outras implementações (PyPy, por exemplo, cacheia de forma diferente). A prova testa o comportamento observável do CPython porque é nele que ela roda, mas a lição de fundo — nunca usarispra comparar valor deint/str/float— vale universalmente, independente do intervalo exato.
type() vs isinstance() sob herança
Território de OO (Galho 3), mas a prova testa como pegadinha de sintaxe isolada, então vale o exemplo aqui: type(obj) == Classe compara o tipo exato, enquanto isinstance(obj, Classe) também aceita subclasses — a diferença só aparece quando existe hierarquia.
class Animal:
pass
class Cachorro(Animal):
pass
rex = Cachorro()
print(type(rex) == Animal)
print(type(rex) == Cachorro)
print(isinstance(rex, Animal))
print(isinstance(rex, Cachorro))O que estas quatro linhas imprimem?
False,True,True,True.type(rex)devolve exatamenteCachorro— nunca uma superclasse, mesmo queCachorroherde deAnimal— então só a comparação comCachorrobate.isinstance(rex, Animal)dáTrueporqueisinstancepercorre toda a cadeia de herança (o MRO), perguntando “rexé umAnimal, considerando toda a árvore de classes?”, não “o tipo exato derexéAnimal?“. Essa diferença é a razão pela qualisinstance()é considerado o idioma correto pra checagem de tipo em Python (inclusive dentro deduck typing/EAFP) — usartype(obj) == Classequebra silenciosamente assim que alguém introduz uma subclasse legítima, um bug de design queisinstance()evita por construção.
Atributo de classe mutável — a mesma armadilha, um nível acima
O default mutável de função tem uma prima próxima em OO (Galho 3): um atributo mutável definido no corpo da classe (não dentro de __init__) é compartilhado por todas as instâncias, pelo mesmo motivo — ele é avaliado uma única vez, quando a classe é definida, e vive como atributo da classe até que alguma instância o sobrescreva explicitamente.
class Carrinho:
itens = [] # atributo de CLASSE, não de instância
def adiciona(self, item):
self.itens.append(item)
c1 = Carrinho()
c2 = Carrinho()
c1.adiciona("maçã")
c2.adiciona("pão")
print(c1.itens)
print(c2.itens)O que este código imprime?
['maçã', 'pão']e['maçã', 'pão']— as duas listas são idênticas, e é o mesmo objeto pros dois carrinhos.itens = []no corpo da classe cria uma lista uma vez, na definição deCarrinho, e essa lista vira um atributo de classe:self.itens.append(item)resolveself.itensvia a regra de busca de atributo (primeiro na instância, sem achar, depois na classe), acha a lista da classe, e.append()muta esse objeto compartilhado — nenhuma instância nunca teve sua própria lista. A correção é a mesma ideia do default mutável de função: inicializarself.itens = []dentro de__init__, criando uma lista nova por instância. A prova testa essa armadilha com menos frequência que o default mutável de função, mas ela aparece especificamente no bloco Object-Oriented Programming (34% da prova PCAP, o de maior peso) — vale ter o reflexo pronto.
Simulado rápido de aquecimento
Seis perguntas curtas, misturando os padrões desta nota, no estilo “single-choice” da prova real — sem consultar as respostas antes de tentar prever o resultado mentalmente:
1. print(True + True + False)
Resposta
2.boolé subclasse deintem Python —Truevale1,Falsevale0em qualquer contexto aritmético, então a soma é tratada como1 + 1 + 0. A prova adora essa combinação porque parece um erro de tipo à primeira vista, mas é aritmética válida.
2. x = [1, 2, 3] y = x y.append(4) print(x)
Resposta
[1, 2, 3, 4].y = xnão copia a lista — só cria um segundo nome apontando pro mesmo objeto..append()emymuta o único objeto que existe, entãox“vê” a mudança. Copiar de verdade exigiriay = x.copy()ouy = list(x)(cópia rasa) oucopy.deepcopy(x)(cópia profunda, necessária quando a lista contém objetos mutáveis aninhados).
3. print(10 // 3 ** 2)
Resposta
1.**tem precedência mais alta que//:3 ** 2 = 9, depois10 // 9 = 1.
4. def f(a, b=[]): b.append(a) return b print(f(1) is f(2))
Resposta
True. Os doisf(1)ef(2)reaproveitam a mesma lista default — não só o valor é igual, é literalmente o mesmo objeto na memória, por issois(identidade) também dáTrue, não só==.
5. print(list(range(10, 0, -3)))
Resposta
[10, 7, 4, 1]. Com passo negativo,rangetambém precisa queinício > fimpra gerar algo — aqui desce de10até (mas sem incluir)0, pulando de 3 em 3:10, 7, 4, 1, parando antes de chegar a-2(que já passou de0).
6. class A: pass class B(A): pass print(issubclass(B, A), issubclass(A, B), isinstance(B(), A))
Resposta
True False True.issubclass(B, A)pergunta seBherda deA— sim.issubclass(A, B)é o inverso — não,Anão herda deB.isinstance(B(), A)cria uma instância deBe pergunta se ela “é um”A— sim, porqueBherda deA, a mesma lógica deisinstancejá vista na seção detype()vsisinstance()acima.
Desempacotamento com número errado de valores
Collections 02 cobre desempacotamento em profundidade — o ângulo de prova que vale isolar é o que acontece quando a contagem de nomes à esquerda não bate com a de valores à direita, incluindo o uso do operador * pra capturar “o resto”:
a, b, *c = [1, 2, 3, 4, 5]
print(a, b, c)
x, *y, z = "abcde"
print(x, y, z)O que estas duas linhas imprimem?
1 2 [3, 4, 5]ea ['b', 'c', 'd'] e. Na primeira,aebpegam os dois primeiros valores, e*cabsorve todo o resto numa lista nova — mesmo que sobrem 0, 1 ou muitos valores,*csempre vira lista (mesmo que vazia). Na segunda, o mesmo princípio vale iterando sobre uma string:xpega o primeiro caractere,zpega o último, e*yabsorve tudo do meio numa lista de caracteres individuais — string não devolve substring nesse tipo de desempacotamento, devolve uma lista de caracteres um a um. Se a contagem de nomes sem*for maior que os valores disponíveis (a, b, c = [1, 2]), a prova espera que você reconheçaValueError: not enough values to unpack— o padrão exato de erro que a Python Institute testa em questões de “qual exceção é levantada”.
Mapa de decisão rápido pra revisão
flowchart LR Q["Vi uma questão 'o que isso imprime'"] --> R1{"Envolve função<br/>mutando algo?"} R1 -->|sim| S1["Checar: mutação in-place<br/>ou reatribuição de nome?"] R1 -->|não| R2{"Envolve is/==<br/>com números?"} R2 -->|sim| S2["Lembrar: is é identidade,<br/>cache só -5..256"] R2 -->|não| R3{"Envolve slicing<br/>com passo?"} R3 -->|sim| S3["a:b sempre inclusive-exclusive,<br/>passo negativo inverte leitura de a/b"] R3 -->|não| R4{"Envolve operador<br/>ambíguo (and/or/&/|)?"} R4 -->|sim| S4["Lógico = truthiness/curto-circuito;<br/>bitwise = bit a bit"] R4 -->|não| R5["Simular linha a linha,<br/>sem assumir atalho"] style Q fill:#4a5568,color:#fff
Vocabulário PT/EN
| Termo PT | Termo EN |
|---|---|
| mutação por referência | mutation by reference |
| argumento default mutável | mutable default argument |
| escopo envolvente | enclosing scope |
| captura tardia (de variável) | late binding (closure) |
| associatividade (de operador) | associativity |
| associa à direita | right-associative |
| operador bitwise | bitwise operator |
| curto-circuito (avaliação) | short-circuit evaluation |
| passo (de slice) | step |
| interning de inteiros | integer interning |
| cache de inteiros pequenos | small integer cache |
| identidade de objeto | object identity |
| checagem de tipo | type checking |
| tipo exato | exact type |
Armadilhas comuns
- Achar que “Python passa por valor” — não passa; passa referência a objeto, e o efeito observável depende só de o objeto ser mutável e de a operação dentro da função ser mutação in-place ou reatribuição de nome local.
- Confiar no intervalo exato do small int cache (
-5a256) como se fosse parte da linguagem — é detalhe de implementação do CPython, não garantia da especificação Python. - Usar
type() ==em vez deisinstance()quando existe (ou pode vir a existir) hierarquia de classes — quebra silenciosamente com subclasses. - Esquecer que
**associa à direita — é o único operador aritmético binário comum com essa propriedade em Python. - Assumir que uma expressão dentro de comparação encadeada (
a < f(x) < b) é avaliada duas vezes — é avaliada uma vez só, e isso importa quandof(x)tem efeito colateral.
Em entrevista
- “Por que
def f(lista=[])é considerado um anti-padrão em Python?” Porque o valor default é avaliado uma única vez, na definição da função, e objetos mutáveis usados como default ficam compartilhados entre todas as chamadas que não passam o argumento — o fix padrão é usarNonecomo sentinela e criar o objeto mutável dentro do corpo da função. - “Quando
ise==podem divergir para dois inteiros com o mesmo valor?” Fora do intervalo cacheado pelo CPython (-5a256), cada literal pode virar um objetointdistinto na memória —==continuaTrue(mesmo valor), masispode darFalse(identidade diferente), a não ser que o compilador funda os literais por otimização dentro do mesmo bloco de código.
How to explain in English
“A classic Python Institute exam pattern is testing whether a function mutates a shared object or just rebinds a local name — the two look identical at a glance but behave completely differently when the object is passed by reference.”
O que vem a seguir
Com o catálogo de armadilhas fechado, a nota 07 vira pra outro problema: não o que estudar, mas como se preparar e atacar a prova sob tempo — gestão de tempo, ordem de ataque das questões, recursos oficiais de prática.
Veja também
- PCAP) — MOC do galho
- 02 — PCEP na prática — cobre
elsede loop,range/zip,.get()vs[], divisão/////% - 03 — PCAP: módulos, exceções e strings — cobre
finally/return,find/index, comparação de strings,math.ceil/floor - Core 02 — Tipos e variáveis — mutabilidade,
isvs== - Core 03 — Operadores e expressões — tabela de precedência completa, operadores lógicos e bitwise
- Core 06 — Funções — LEGB,
UnboundLocalError, valores default - Core 07 — Strings e formatação — imutabilidade, slicing básico
- Collections 01 — Listas — slicing avançado em sequências
- CPython internals 02 — Objetos em CPython — Galho 6, explicação de fundo do cache de inteiros pequenos
- OO e Data Model — Galho 3,
isinstance/MRO em profundidade
Fontes
- Python Institute / OpenEDG. PCEP-30-02 Exam Syllabus. pythoninstitute.org. https://pythoninstitute.org/pcep-exam-syllabus (acessado em 2026-07-12, pesquisa registrada no roadmap deste galho — status “Live & Active”)
- Python Institute / OpenEDG. PCAP-31-03 Exam Syllabus. pythoninstitute.org. https://pythoninstitute.org/pcap-exam-syllabus (acessado em 2026-07-12, pesquisa registrada no roadmap deste galho — status “Live & Active”)
- Python Software Foundation. Expressions — Operator precedence. docs.python.org, versão 3.14. https://docs.python.org/3/reference/expressions.html#operator-precedence (acessado em 2026-07-12)
- Python Software Foundation. Data Model —
object.__eq__, identity vs equality. docs.python.org, versão 3.14. https://docs.python.org/3/reference/datamodel.html (acessado em 2026-07-12) - Python Software Foundation. Built-in Functions —
isinstance(),type(). docs.python.org, versão 3.14. https://docs.python.org/3/library/functions.html (acessado em 2026-07-12) - CPython source (referenciado indiretamente via CPython internals 02).
Objects/longobject.c— small integer cache. github.com/python/cpython (acessado em 2026-07-10, já citado na nota-fonte do Galho 6)