{
  "assessmentTests": {
    "python_test": {
      "name": "Teste Python",
      "desc": "30 questões de cenários sobre sintaxe, funções, estruturas de dados e comportamento de objetos — descubra se seu Python corresponde ao que uma oferta de emprego significa por proficiência em Python.",
      "recommendation": "Seu perfil de habilidades em Python",
      "results": {
        "beginner": {
          "name": "Iniciante",
          "desc": "Você consegue acompanhar um script curto e alterar valores dentro dele, mas as questões que você errou tendem a girar em torno do comportamento específico da própria linguagem, e não de lógica geral — um argumento padrão que é construído uma vez e reutilizado, is versus == em duas listas com aparência igual, uma variável que se torna local no momento em que você atribui a ela em qualquer lugar de uma função. Nada disso é sobre ser ruim em programação; estas são regras específicas do Python que tropeçam tanto em pessoas vindas de outras linguagens quanto em iniciantes. Elas importam no trabalho porque cada uma é um lugar onde um bug se esconde em código que parece correto à primeira vista.",
          "recommendation": "Comece com três coisas, nesta ordem: argumentos padrão mutáveis (por que basket=[] é perigoso), a diferença entre is e ==, e como o escopo de variáveis funciona dentro de uma função. O tutorial oficial do Python em docs.python.org cobre todos os três diretamente, e o termo \"Python gotchas\" traz exemplos funcionais de cada um."
        },
        "intermediate": {
          "name": "Intermediário",
          "desc": "Você lida confortavelmente com scripts do dia a dia — estruturas de dados, fluxo de controle, funções diretas — e não seria desacelerado por trabalho de manutenção rotineira ou uma pequena funcionalidade em um código já existente. A diferença entre aqui e Avançado está principalmente no que acontece quando os recursos de conveniência do Python interagem um com o outro: uma cópia superficial deixando dados aninhados compartilhados quando você esperava que fossem duplicados, um valor de retorno de um gerador silenciosamente não se tornando parte de sua saída, decoradores sendo empilhados em uma ordem que é fácil de inverter. Esses são o tipo de bugs que um revisor sênior identifica em dez segundos e todo o resto passa uma hora perseguindo.",
          "recommendation": "Concentre-se nos internos de objetos e iteração: cópia superficial versus profunda, o que um gerador realmente faz com return, e como a ordem de empilhamento de decoradores funciona. Depois, noções básicas de classe que a maioria dos tutoriais pula — igualdade padrão sem __eq__, e por que um atributo de classe mutável é compartilhado por cada instância."
        },
        "advanced": {
          "name": "Avançado",
          "desc": "Este é o nível que a maioria das ofertas de emprego significa por \"Python forte\". Você busca a ferramenta certa sem procurá-la, você sabe por que um pedaço de estado compartilhado mudou em vez de apenas que mudou, e você pode ler a função de outra pessoa e prever corretamente sua saída. O que separa essa faixa do topo é o lado defensivo do trabalho: saber qual de duas abordagens que parecem corretas se comportará mal uma vez que um atributo de classe, um argumento somente nomeado, ou uma hierarquia de exceção estejam envolvidos.",
          "recommendation": "Aprofunde-se nas partes que protegem um código que outras pessoas também tocam: argumentos somente nomeados como uma escolha de design de API em vez de uma curiosidade de sintaxe, a hierarquia de exceção (para que as cláusulas except capturem a família certa de erro, não apenas uma classe), e gerenciadores de contexto como a forma padrão de garantir limpeza. Os artigos de mergulho profundo do Real Python são um bom próximo passo para todos os três."
        },
        "expert": {
          "name": "Especialista",
          "desc": "Você pontuou no topo de cada seção — sintaxe central, funções e escopo, estruturas de dados e expressões orientadas a objetos. Praticamente, isso significa que você pode receber um arquivo de um estranho e explicar por que ele produz a saída que produz, não apenas o que a sintaxe diz que deveria fazer, o que é a habilidade mais difícil e mais valiosa. Neste nível, a linguagem bruta é raramente o fator limitante em seu trabalho; o limite geralmente é o tamanho ou forma do sistema ao redor do código.",
          "recommendation": "Os retornos agora estão em ferramentas e revisão: verificação de tipo estático com mypy ou pyright, criação de perfil antes de otimizar em vez de adivinhar, e leitura de solicitações de pull de outras pessoas exatamente por essa categoria de bug — aquelas que passam em cada teste e ainda fazem a coisa errada sob uma entrada específica. Se você está sendo avaliado para um cargo, descreva um bug como este que você encontrou em vez de nomear recursos da linguagem — isso demonstra o raciocínio, não apenas o vocabulário."
        }
      },
      "questions": [
        {
          "question": "Você escreve def add_item(item, basket=[]): basket.append(item); return basket, depois chama add_item('a') e add_item('b'), deixando basket de fora ambas as vezes. O que a segunda chamada retorna?",
          "options": [
            {
              "icon": "",
              "label": "['b'] — cada chamada recebe uma lista vazia nova por padrão"
            },
            {
              "icon": "",
              "label": "TypeError — você deve fornecer um argumento basket"
            },
            {
              "icon": "",
              "label": "['a', 'b'] — a lista padrão é criada uma vez e reutilizada entre chamadas"
            },
            {
              "icon": "",
              "label": "['a'] depois ['b'] como duas listas independentes de um item cada"
            }
          ]
        },
        {
          "question": "a = [1, 2, 3] e b = [1, 2, 3]. O que a == b retorna e o que a is b retorna?",
          "options": [
            {
              "icon": "",
              "label": "True para ambas — listas idênticas são sempre o mesmo objeto"
            },
            {
              "icon": "",
              "label": "True para ==, False para is — conteúdo igual mas objetos diferentes na memória"
            },
            {
              "icon": "",
              "label": "False para ambas — literais separados nunca são iguais em Python"
            },
            {
              "icon": "",
              "label": "True para is, False para == — is verifica igualdade de valor para listas"
            }
          ]
        },
        {
          "question": "Em Python 3, o que 7 / 2 avalia e o que 7 // 2 avalia?",
          "options": [
            {
              "icon": "",
              "label": "3.5, depois 3 — / sempre retorna um float, // arredonda o resultado para baixo"
            },
            {
              "icon": "",
              "label": "3, depois 3.5 — / trunca e // retorna um float"
            },
            {
              "icon": "",
              "label": "3.5, depois 3.5 — ambos os operadores retornam um float em Python 3"
            },
            {
              "icon": "",
              "label": "3, depois 3 — ambos os operadores arredondam para baixo em Python 3"
            }
          ]
        },
        {
          "question": "s = 'hello', depois você executa s[0] = 'H'. O que acontece?",
          "options": [
            {
              "icon": "",
              "label": "s se torna 'Hello'"
            },
            {
              "icon": "",
              "label": "s se torna 'Hhello' porque o caractere é inserido, não substituído"
            },
            {
              "icon": "",
              "label": "TypeError — strings são imutáveis e não suportam atribuição de item"
            },
            {
              "icon": "",
              "label": "Nada — a atribuição é silenciosamente ignorada e s permanece 'hello'"
            }
          ]
        },
        {
          "question": "x = [10, 20, 30, 40, 50]. O que x[1:4] retorna?",
          "options": [
            {
              "icon": "",
              "label": "[20, 30, 40, 50]"
            },
            {
              "icon": "",
              "label": "[10, 20, 30, 40]"
            },
            {
              "icon": "",
              "label": "[20, 30, 40]"
            },
            {
              "icon": "",
              "label": "[30, 40]"
            }
          ]
        },
        {
          "question": "name = 'Ana' e age = 30. O que f'{name} is {age}' produz?",
          "options": [
            {
              "icon": "",
              "label": "{name} is {age}"
            },
            {
              "icon": "",
              "label": "Ana is 30"
            },
            {
              "icon": "",
              "label": "name is age"
            },
            {
              "icon": "",
              "label": "Um TypeError, porque f-strings exigem o método format()"
            }
          ]
        },
        {
          "question": "O que 1 < 2 < 3 avalia?",
          "options": [
            {
              "icon": "",
              "label": "True — Python encadeia as comparações como (1 < 2) and (2 < 3)"
            },
            {
              "icon": "",
              "label": "False — comparações encadeadas são avaliadas da esquerda para a direita sem curto-circuito, dando 1 < 2 < 3 -> 1 < True -> False"
            },
            {
              "icon": "",
              "label": "Um SyntaxError — comparações não podem ser encadeadas"
            },
            {
              "icon": "",
              "label": "3 — Python retorna o último valor no encadeamento"
            }
          ]
        },
        {
          "question": "O que bool([]) retorna e o que bool([0]) retorna?",
          "options": [
            {
              "icon": "",
              "label": "False, depois False — qualquer lista contendo apenas valores falsos é falsa"
            },
            {
              "icon": "",
              "label": "False, depois True — uma lista vazia é falsa, uma lista contendo um elemento (até 0) é verdadeira"
            },
            {
              "icon": "",
              "label": "True, depois True — objetos não-None são sempre verdadeiros"
            },
            {
              "icon": "",
              "label": "True, depois False — uma lista é verdadeira apenas quando vazia"
            }
          ]
        },
        {
          "question": "Um count = 0 no nível do módulo existe. Dentro de def increment(): count += 1; return count, você chama increment(). O que acontece?",
          "options": [
            {
              "icon": "",
              "label": "UnboundLocalError — atribuir a count em qualquer lugar da função a torna local, então count += 1 tenta ler uma variável local antes de ser atribuída"
            },
            {
              "icon": "",
              "label": "Retorna 1 e incrementa o count do nível do módulo para 1"
            },
            {
              "icon": "",
              "label": "Retorna 1 mas deixa o count do nível do módulo em 0"
            },
            {
              "icon": "",
              "label": "Levanta NameError porque count nunca foi declarado dentro da função"
            }
          ]
        },
        {
          "question": "def f(*args, **kwargs): return args, kwargs. O que f(1, 2, x=3) retorna?",
          "options": [
            {
              "icon": "",
              "label": "([1, 2], {'x': 3})"
            },
            {
              "icon": "",
              "label": "((1, 2), {'x': 3})"
            },
            {
              "icon": "",
              "label": "(1, 2, {'x': 3})"
            },
            {
              "icon": "",
              "label": "TypeError — argumentos posicionais e nomeados não podem ser misturados em uma chamada"
            }
          ]
        },
        {
          "question": "Você constrói funcs = [lambda: i for i in range(3)] em um loop. O que [f() for f in funcs] retorna?",
          "options": [
            {
              "icon": "",
              "label": "[2, 2, 2] — cada lambda busca i quando chamada, e nessa hora o loop terminou com i igual a 2"
            },
            {
              "icon": "",
              "label": "[0, 1, 2] — cada lambda captura o valor de i no momento em que foi criada"
            },
            {
              "icon": "",
              "label": "[0, 0, 0] — lambdas sempre capturam o primeiro valor atribuído a uma variável"
            },
            {
              "icon": "",
              "label": "Um NameError, porque i não existe mais quando o loop termina"
            }
          ]
        },
        {
          "question": "Uma função é definida com @a diretamente acima de @b, que fica diretamente acima de def f(): pass. Em que ordem os decoradores são aplicados a f?",
          "options": [
            {
              "icon": "",
              "label": "b envolve f primeiro, depois a envolve o resultado de b — o decorador mais próximo da função executa primeiro"
            },
            {
              "icon": "",
              "label": "a envolve f primeiro, depois b envolve o resultado — decoradores aplicam de cima para baixo"
            },
            {
              "icon": "",
              "label": "Ambos os decoradores envolvem f independentemente e apenas o último definido tem efeito"
            },
            {
              "icon": "",
              "label": "Depende da ordem em que os decoradores são importados, não sua posição no código"
            }
          ]
        },
        {
          "question": "def f(a, *, b): return a + b. Qual dessas chamadas funciona?",
          "options": [
            {
              "icon": "",
              "label": "f(1, b=2) — b deve ser passado por palavra-chave porque vem após o * na assinatura"
            },
            {
              "icon": "",
              "label": "f(1, 2) — argumentos posicionais preenchem parâmetros da esquerda para a direita independentemente do *"
            },
            {
              "icon": "",
              "label": "f(a=1, 2) — argumentos nomeados devem vir primeiro"
            },
            {
              "icon": "",
              "label": "f(1) — b é opcional porque segue o *"
            }
          ]
        },
        {
          "question": "Uma função geradora faz yield 1, depois yield 2, depois return 99. O que list(the_generator()) contém e o que acontece com o 99?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 99] — return dentro de um gerador se comporta como um yield adicional"
            },
            {
              "icon": "",
              "label": "[99] — return imediatamente sobrescreve qualquer valor já feito yield"
            },
            {
              "icon": "",
              "label": "[1, 2] — o valor de retorno de um gerador se torna o valor anexado ao StopIteration que ele levanta, não é feito yield"
            },
            {
              "icon": "",
              "label": "Um RuntimeError, porque geradores não podem conter uma declaração return"
            }
          ]
        },
        {
          "question": "Em uma função outer(), x = 1 é definido, depois uma inner() aninhada faz nonlocal x; x += 1, e outer() chama inner() antes de retornar x. O que outer() retorna?",
          "options": [
            {
              "icon": "",
              "label": "1 — inner() opera em sua própria cópia local de x, então a mudança não persiste"
            },
            {
              "icon": "",
              "label": "Um UnboundLocalError, porque x não é declarado dentro de inner() antes da declaração nonlocal"
            },
            {
              "icon": "",
              "label": "Um SyntaxError — nonlocal pode ser usado apenas dentro de classes"
            },
            {
              "icon": "",
              "label": "2 — nonlocal permite que inner() modifique o x da função externa em vez de criar uma nova variável local"
            }
          ]
        },
        {
          "question": "d = {'a': 1, 'b': 2}. O que d.get('c', 0) retorna e isso adiciona 'c' ao dicionário?",
          "options": [
            {
              "icon": "",
              "label": "0, e não — get() retorna o padrão sem inserir a chave"
            },
            {
              "icon": "",
              "label": "0, e sim — get() insere a chave com o valor padrão"
            },
            {
              "icon": "",
              "label": "KeyError, porque 'c' não existe"
            },
            {
              "icon": "",
              "label": "None, e sim — get() sempre adiciona chaves ausentes com um valor None"
            }
          ]
        },
        {
          "question": "t = (1, 2, [3, 4]). Você pode executar t[2].append(5) e pode executar t[0] = 10?",
          "options": [
            {
              "icon": "",
              "label": "Ambos funcionam — aninhar uma lista dentro de uma tupla torna toda a tupla mutável"
            },
            {
              "icon": "",
              "label": "Ambos levantam TypeError — nada dentro de uma tupla pode ser mudado"
            },
            {
              "icon": "",
              "label": "t[2].append(5) levanta TypeError, mas t[0] = 10 funciona porque tuplas permitem reatribuição de seu primeiro elemento"
            },
            {
              "icon": "",
              "label": "t[2].append(5) funciona porque a lista dentro é mutável; t[0] = 10 levanta TypeError porque a própria tupla é imutável"
            }
          ]
        },
        {
          "question": "Qual destes retorna um iterador que calcula valores lentamente em vez de construir a sequência inteira na memória de uma vez: [x*x for x in range(1000000)] ou (x*x for x in range(1000000))?",
          "options": [
            {
              "icon": "",
              "label": "O com parênteses, (x*x for x in range(1000000)) — essa é uma expressão geradora"
            },
            {
              "icon": "",
              "label": "O com colchetes — compreensões de lista são sempre preguiçosas em Python 3"
            },
            {
              "icon": "",
              "label": "Ambos são preguiçosos — a única diferença é o tipo retornado no final"
            },
            {
              "icon": "",
              "label": "Nenhum — ambos constroem a sequência completa na memória imediatamente"
            }
          ]
        },
        {
          "question": "Um bloco try divide por zero, a cláusula except ZeroDivisionError imprime 'a', e uma cláusula finally imprime 'b'. O que imprime e em que ordem?",
          "options": [
            {
              "icon": "",
              "label": "b depois a — finally sempre executa antes de qualquer cláusula except"
            },
            {
              "icon": "",
              "label": "a depois b — o except correspondente executa primeiro, e finally sempre executa depois, independentemente"
            },
            {
              "icon": "",
              "label": "Apenas b — a exceção não é realmente capturada, então 'a' nunca imprime"
            },
            {
              "icon": "",
              "label": "Apenas a — finally é ignorado uma vez que uma exceção já foi tratada"
            }
          ]
        },
        {
          "question": "import copy; a = [[1, 2], [3, 4]]; b = copy.copy(a); b[0].append(99). a[0] muda também?",
          "options": [
            {
              "icon": "",
              "label": "Não — copy.copy() sempre duplica objetos aninhados também"
            },
            {
              "icon": "",
              "label": "Não — anexar a b[0] cria uma lista completamente nova apenas para b[0]"
            },
            {
              "icon": "",
              "label": "Sim, mas apenas porque copy.copy() foi chamado sem o argumento deepcopy"
            },
            {
              "icon": "",
              "label": "Sim — copy.copy() faz uma cópia superficial, então as listas aninhadas são ainda compartilhadas entre a e b"
            }
          ]
        },
        {
          "question": "d = {'x': 1, 'y': 2}. O que 'x' in d verifica contra — as chaves, os valores, ou ambos?",
          "options": [
            {
              "icon": "",
              "label": "Os valores — `in` verifica se 1 ou 2 é igual a 'x'"
            },
            {
              "icon": "",
              "label": "Tanto chaves quanto valores são verificados"
            },
            {
              "icon": "",
              "label": "Nenhum — `in` em um dict sempre levanta TypeError"
            },
            {
              "icon": "",
              "label": "As chaves — `in` em um dicionário testa associação entre suas chaves, não seus valores"
            }
          ]
        },
        {
          "question": "names = ['Al', 'Bo'] e scores = [10, 20]. O que list(zip(names, scores)) retorna?",
          "options": [
            {
              "icon": "",
              "label": "[('Al', 'Bo'), (10, 20)]"
            },
            {
              "icon": "",
              "label": "['Al', 10, 'Bo', 20]"
            },
            {
              "icon": "",
              "label": "[('Al', 10), ('Bo', 20)]"
            },
            {
              "icon": "",
              "label": "Um ValueError, porque zip requer três ou mais argumentos"
            }
          ]
        },
        {
          "question": "class Dog: tricks = [] segura uma lista no nível de classe, e add_trick anexa a self.tricks. d1 = Dog() e d2 = Dog() são ambos criados, depois d1.add_trick('sit') executa. O que d2.tricks contém?",
          "options": [
            {
              "icon": "",
              "label": "[] — cada instância recebe sua própria cópia independente de tricks"
            },
            {
              "icon": "",
              "label": "['sit'] — tricks é uma lista no nível de classe compartilhada por cada instância, então a mudança de d1 é visível em d2 também"
            },
            {
              "icon": "",
              "label": "Um TypeError — instâncias não podem anexar a um atributo de classe"
            },
            {
              "icon": "",
              "label": "['sit'] apenas após d2 = Dog() ser re-executado"
            }
          ]
        },
        {
          "question": "class A tem def greet(self): return 'A'. class B(A) tem def greet(self): return 'B' + super().greet(). O que B().greet() retorna?",
          "options": [
            {
              "icon": "",
              "label": "'AB' — super() sempre executa antes do próprio código da subclasse"
            },
            {
              "icon": "",
              "label": "'B' — super().greet() é ignorado porque B já sobrescreve greet"
            },
            {
              "icon": "",
              "label": "'BA' — super().greet() chama o método de A e seu resultado é anexado a 'B'"
            },
            {
              "icon": "",
              "label": "Um AttributeError, porque A não tem método greet visível para B"
            }
          ]
        },
        {
          "question": "class Point armazena self.x em __init__ e não define outros métodos. p1 = Point(1) e p2 = Point(1). O que p1 == p2 retorna por padrão?",
          "options": [
            {
              "icon": "",
              "label": "True — Python compara todos os atributos correspondentes por padrão"
            },
            {
              "icon": "",
              "label": "False — sem um __eq__ personalizado, == volta para comparação de identidade, e p1 e p2 são objetos diferentes"
            },
            {
              "icon": "",
              "label": "True, mas apenas porque ambos os objetos foram criados com o mesmo argumento"
            },
            {
              "icon": "",
              "label": "Um TypeError, porque Point não define __eq__"
            }
          ]
        },
        {
          "question": "Qual cláusula except abaixo também vai capturar um ZeroDivisionError: except ArithmeticError, except ValueError, ou except KeyError?",
          "options": [
            {
              "icon": "",
              "label": "except ValueError — erros de divisão são tratados como valores inválidos"
            },
            {
              "icon": "",
              "label": "except KeyError — qualquer erro de tempo de execução não vinculado a um tipo específico volta para KeyError"
            },
            {
              "icon": "",
              "label": "Nenhum — apenas except ZeroDivisionError em si pode capturá-lo"
            },
            {
              "icon": "",
              "label": "except ArithmeticError — ZeroDivisionError é uma subclasse de ArithmeticError"
            }
          ]
        },
        {
          "question": "Você abre um arquivo com open('data.txt') as f: e uma exceção é levantada ao ler dentro do bloco. O arquivo ainda é fechado?",
          "options": [
            {
              "icon": "",
              "label": "Não — o arquivo permanece aberto porque o bloco não terminou normalmente"
            },
            {
              "icon": "",
              "label": "Apenas se você também adicionar uma cláusula finally ao redor da declaração with"
            },
            {
              "icon": "",
              "label": "Sim — a declaração with chama o método __exit__ do arquivo, que o fecha, mesmo se uma exceção ocorra dentro do bloco"
            },
            {
              "icon": "",
              "label": "Depende do tipo de exceção — apenas exceções capturadas em outro lugar disparam limpeza"
            }
          ]
        },
        {
          "question": "x = [3, 1, 2] e y = x.sort(). O que y contém?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3] — sort() retorna a lista recém-ordenada"
            },
            {
              "icon": "",
              "label": "None — list.sort() ordena no lugar e retorna None; x em si se torna [1, 2, 3]"
            },
            {
              "icon": "",
              "label": "[3, 1, 2] — sort() retorna a lista original não ordenada e apenas muda a ordem interna de x"
            },
            {
              "icon": "",
              "label": "Um TypeError, porque sort() não pode ser atribuído a uma variável"
            }
          ]
        },
        {
          "question": "O que acontece quando você executa 'Score: ' + 42?",
          "options": [
            {
              "icon": "",
              "label": "'Score: 42' — Python converte o número automaticamente em uma expressão +"
            },
            {
              "icon": "",
              "label": "'Score: ' — o número é silenciosamente descartado"
            },
            {
              "icon": "",
              "label": "42 — a string é coagida a um número e adicionada"
            },
            {
              "icon": "",
              "label": "TypeError — você não pode concatenar uma str e um int diretamente, 42 deve ser convertido com str() primeiro"
            }
          ]
        },
        {
          "question": "Você precisa verificar se uma lista chamada results está vazia. Qual é a forma idiomática do Python: if results == []: , if len(results) == 0: , ou if not results: ?",
          "options": [
            {
              "icon": "",
              "label": "if results == []: — esta é a única maneira confiável de detectar uma lista vazia"
            },
            {
              "icon": "",
              "label": "if len(results) == 0: — isto é necessário porque listas vazias são verdadeiras em Python"
            },
            {
              "icon": "",
              "label": "Todos os três nunca são usados na prática; a abordagem padrão é if results is None:"
            },
            {
              "icon": "",
              "label": "if not results: — a expressão idiomática do Python depende de veracidade, e uma lista vazia é falsa"
            }
          ]
        }
      ],
      "optionOrderVersion": "92945565db6c55da"
    }
  }
}
