Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A maioria dos depuradores comuns do Python dá suporte apenas à depuração do código Python, mas é uma prática comum para os desenvolvedores usarem o Python com C ou C++. Alguns cenários que usam código misto são aplicativos que exigem alto desempenho ou a capacidade de invocar diretamente APIs de plataforma geralmente são codificadas em Python e C ou C++.
O Visual Studio fornece depuração integrada e simultânea de modo misto para python e código C/C++ nativo. O suporte estará disponível quando você selecionar a opção de ferramentas de desenvolvimento nativas do Python para a carga de trabalho de Desenvolvimento do Python no instalador do Visual Studio:
Neste artigo, você explorará como trabalhar com os seguintes recursos de depuração de modo misto:
- Pilhas de chamadas combinadas
- Etapa entre o Python e o código nativo
- Pontos de interrupção em ambos os tipos de código
- Exibir representações python de objetos em quadros nativos e vice-versa
- Depuração no contexto do projeto Python ou do projeto C++
Pré-requisitos
Visual Studio 2017 e posterior. A depuração de modo misto não está disponível nas Ferramentas para Python do Visual Studio 1.x no Visual Studio 2015 ou versões anteriores.
Visual Studio instalado com suporte para cargas de trabalho do Python. Para obter mais informações, consulte Instalar o suporte do Python no Visual Studio.
Habilitar a depuração de modo misto em um projeto do Python
As etapas a seguir descrevem como habilitar a depuração de modo misto em um projeto do Python:
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto Python e selecione Propriedades.
No painel Propriedades , selecione a guia Depurar e, em seguida, selecione a opção Habilitar depuração>de código nativo :
Essa opção habilita o modo misto para todas as sessões de depuração.
Dica
Quando você habilita a depuração de código nativo, a janela de saída do Python pode ser fechada imediatamente após a conclusão do programa, sem pausar e mostrar a mensagem Pressione qualquer tecla para continuar. Para forçar a pausa e o prompt depois de habilitar a depuração de código nativo, adicione o argumento
-iao campo Executar>Argumentos do Interpretador na guia Depurar. Esse argumento coloca o interpretador Python no modo interativo após a execução do código. O programa aguarda que você selecione Ctrl+Z+Enter para fechar a janela.Selecione Salvar Arquivo> (ou Ctrl+) para salvar as alterações de propriedade.
Para anexar o depurador de modo misto a um processo existente, selecione Depurar>Anexar ao Processo. Uma caixa de diálogo é aberta.
Na caixa de diálogo Anexar ao Processo , selecione o processo apropriado na lista.
Para o campo Anexar ao campo, use a opção Selecionar para abrir a caixa de diálogo Selecionar Tipo de Código .
Na caixa de diálogo Selecionar Tipo de Código , escolha a opção Depurar esses tipos de código .
Na lista, selecione a caixa de seleção Python (nativo) e selecione OK:
Selecione Anexar para iniciar o depurador.
As configurações de tipo de código são persistentes. Se você quiser desabilitar a depuração de modo misto e anexar a um processo diferente mais tarde, desmarque a caixa de seleção do tipo de código Python (Nativo) e marque a caixa de seleção do tipo de código Nativo.
Você pode selecionar outros tipos de código além ou em vez da opção Native . Por exemplo, se um aplicativo gerenciado hospeda o CPython, que, por sua vez, usa módulos de extensão nativos e deseja depurar todos os três projetos de código, selecione as caixas de seleção Python, Native e Managed . Essa abordagem oferece uma experiência de depuração unificada, incluindo pilhas de chamadas combinadas e uma passagem entre os três ambientes de execução.
Trabalhar com ambientes virtuais
Quando você usa esse método de depuração de modo misto para ambientes virtuais (venvs), o Python para Windows usa um python.exe arquivo stub para venvs que o Visual Studio localiza e carrega como um subprocesso.
Para Python 3.8 e posterior, o modo misto não dá suporte à depuração de vários processos. Quando você inicia a sessão de depuração, o subprocesso stub é depurado em vez do aplicativo. Para cenários de anexação, a solução alternativa é anexar ao arquivo correto
python.exe. Ao iniciar o aplicativo com depuração (como por meio do atalho de teclado F5 ), você pode criar seu venv usando o comandoC:\Python310-64\python.exe -m venv venv --symlinks. No comando, insira sua versão preferida do Python. Por padrão, somente os administradores podem criar symlinks no Windows.Para versões do Python anteriores à 3.8, a depuração de modo misto deve funcionar conforme o esperado com venvs.
A execução em um ambiente global não causa esses problemas para nenhuma versão do Python.
Instalar símbolos do Python
Ao iniciar a depuração no modo misto pela primeira vez, você poderá ver uma janela de diálogo Símbolos Python necessários. Você precisa instalar os símbolos apenas uma vez para qualquer determinado ambiente do Python. Os símbolos serão incluídos automaticamente se você instalar o suporte ao Python por meio do Instalador do Visual Studio (Visual Studio 2017 e posterior). Para obter mais informações, consulte Instalar símbolos de depuração para interpretadors do Python no Visual Studio.
Acessar o código-fonte do Python
Você pode disponibilizar o código-fonte do Python padrão ao depurar.
Baixe o arquivo de código-fonte do Python apropriado para sua versão e extraia o código para uma pasta.
Quando o Visual Studio solicitar o local do código-fonte do Python, aponte para os arquivos específicos na pasta de extração.
Habilitar a depuração de modo misto em um projeto C/C++
O Visual Studio 2017 versão 15.5 e posterior dá suporte à depuração de modo misto de um projeto C/C++. Um exemplo desse uso é quando você deseja inserir o Python em outro aplicativo, conforme descrito em python.org.
As etapas a seguir descrevem como habilitar a depuração de modo misto para um projeto C/C++:
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto C/C++ e selecione Propriedades.
No painel Páginas de Propriedades, selecione a guia Propriedades de Configuração>Depuração.
Expanda o menu suspenso para que o Depurador inicie a opção e selecione Python/Depuração Nativa.
Observação
Se você não vir a opção Python/Depuração Nativa, primeiro instale as ferramentas de desenvolvimento nativas do Python usando o Instalador do Visual Studio. A opção de depuração nativa está disponível na carga de trabalho de desenvolvimento do Python. Para obter mais informações, consulte Instalar o suporte do Python no Visual Studio.
Selecione OK para salvar as alterações.
Depurar o inicializador de programas
Quando você usa esse método, não é possível depurar o py.exe inicializador de programas porque ele gera um subprocesso filho python.exe . O depurador não é anexado ao subprocesso. Para esse cenário, a solução alternativa é iniciar o python.exe programa diretamente com argumentos, da seguinte maneira:
No painel Páginas de Propriedades do projeto C/C++, vá para a aba Propriedades de Configuração>Depuração.
Para a opção Comando , especifique o caminho completo para o arquivo de
python.exeprograma.Especifique os argumentos desejados no campo Argumentos de Comando .
Anexar o depurador de modo misto
Para o Visual Studio 2017 versão 15.4 e anteriores, a depuração direta no modo misto só é habilitada ao iniciar um projeto em Python no Visual Studio. O suporte é limitado porque projetos C/C++ usam apenas o depurador nativo.
Para esse cenário, a solução alternativa é anexar o depurador separadamente:
Inicie o projeto C++ sem depurar selecionando Depurar>Iniciar sem Depuração ou use o atalho de teclado Ctrl+F5.
Para anexar o depurador de modo misto a um processo existente, selecione Depurar>Anexar ao Processo. Uma caixa de diálogo é aberta.
Na caixa de diálogo Anexar ao Processo , selecione o processo apropriado na lista.
Para o campo Anexar ao campo, use a opção Selecionar para abrir a caixa de diálogo Selecionar Tipo de Código .
Na caixa de diálogo Selecionar Tipo de Código , escolha a opção Depurar esses tipos de código .
Na lista, selecione a caixa de seleção do Python e selecione OK.
Selecione Anexar para iniciar o depurador.
Dica
Você pode adicionar uma pausa ou atraso no aplicativo C++ para garantir que ele não chame o código Python que você deseja depurar antes de anexar o depurador.
Explorar recursos específicos do modo misto
O Visual Studio fornece vários recursos de depuração de modo misto para facilitar a depuração do aplicativo:
- Pilha de chamadas combinada
- Etapa entre o Python e o código nativo
- Exibição de valores PyObject no código nativo
- Exibição de valores nativos no código do Python
Usar uma pilha de chamadas combinada
A janela Pilha de Chamadas mostra frames de pilha nativos e de Python intercalados, com transições marcadas entre os dois:
- Para fazer transições aparecerem como [Código Externo] sem especificar a direção da transição, use o painelOpções de >. Expanda a seção Todas as Configurações>Depuração>Geral, selecione a caixa de seleção Habilitar Apenas Meu Código.
- Para fazer transições aparecerem como [Código Externo] sem especificar a direção da transição, use a caixa de diálogoOpções de >. Expanda a seçãoGeral>, selecione a caixa de seleção Habilitar Apenas Meu Código e selecione OK.
- Para tornar qualquer quadro de chamada ativo, clique duas vezes no quadro. Essa ação também abre o código-fonte correspondente, se possível. Se o código-fonte não estiver disponível, o quadro ainda será ativo e as variáveis locais poderão ser inspecionadas.
Etapa entre o Python e o código nativo
O Visual Studio fornece os comandos Step Into (F11) ou Step Out (Shift+F11) para permitir que o depurador de modo misto manipule corretamente as alterações entre tipos de código.
Quando o Python chama um método de um tipo implementado em C, intervir em uma chamada para esse método é interrompido no início da função nativa que implementa o método.
Esse mesmo comportamento ocorre quando o código nativo chama uma função de API do Python que resulta na invocação do código Python. Ao entrar em uma chamada para
PyObject_CallObjectum valor de função definido originalmente em Python, a execução para no início da função Python.A transição do Python para nativo também é suportada para funções nativas invocadas a partir do Python por meio de ctypes.
Usar a exibição de valores PyObject no código nativo
Quando um quadro nativo (C ou C++) está ativo, suas variáveis locais aparecem na janela Locals do depurador. Em módulos de extensão nativos do Python, muitas dessas variáveis são do tipo PyObject (que é um typedef para _object) ou alguns outros tipos fundamentais do Python. Na depuração de modo misto, esses valores apresentam outro nó filho rotulado [visão Python].
Para exibir a representação da variável em Python, expanda o nó. A exibição das variáveis é idêntica ao que você vê se uma variável local que faz referência ao mesmo objeto está presente em um quadro do Python. Os filhos desse nó são editáveis.
Para desabilitar esse recurso, clique com o botão direito do mouse em qualquer lugar na janela
Locais e alterne a opção de menuPython Exibir Nós de Visualização do Python :
Tipos C que mostram nós de exibição do Python
Os seguintes tipos C mostram os nós de [visualização do Python], se habilitados:
PyObjectPyVarObjectPyTypeObjectPyByteArrayObjectPyBytesObjectPyTupleObjectPyListObjectPyDictObjectPySetObjectPyIntObjectPyLongObjectPyFloatObjectPyStringObjectPyUnicodeObject
[Visualização do Python] não se apresenta automaticamente para tipos que você criar. Quando você cria extensões para Python 3.x, essa falta geralmente não é um problema. Qualquer objeto, em última análise, tem um ob_base campo de um dos tipos C listados, o que faz com que [modo de exibição python] apareça.
Exibir valores nativos no código do Python
Você pode habilitar uma exibição [C++] para valores nativos na janela Locals quando um quadro do Python está ativo. Esse recurso não é habilitado por padrão.
Para habilitar o recurso, clique com o botão direito do mouse na janela Locais e defina a opção de menu Python>Exibir Nós do C++.
O nó [exibição C++] fornece uma representação da estrutura C/C++ subjacente para um valor, idêntico ao que você vê em um quadro nativo. Ele mostra uma instância (
_longobjectpara a qualPyLongObjecté um typedef) para um inteiro longo do Python e tenta inferir tipos de classes nativas que você mesmo cria. Os filhos desse nó são editáveis.
Se um campo filho de um objeto for do tipo PyObjectou outro tipo com suporte, ele terá um nó de representação [exibição do Python] (se essas representações estiverem habilitadas). Esse comportamento possibilita navegar por grafos de objetos em que os links não são expostos diretamente ao Python.
Ao contrário dos nós [modo de exibição do Python ], que usam metadados de objeto python para determinar o tipo do objeto, não há mecanismo igualmente confiável para [modo de exibição C++]. De modo geral, dado um valor python (ou seja, uma PyObject referência), não é possível determinar de forma confiável qual estrutura C/C++ está apoiando-a. O depurador de modo misto tenta adivinhar o tipo examinando vários campos do tipo do objeto (como o PyTypeObject referenciado pelo campo ob_type) que possuem tipos de ponteiro para função. Se um desses ponteiros de função fizer referência a uma função que pode ser resolvida, e se essa função tiver um self parâmetro cujo tipo seja mais específico que o de PyObject*, então esse tipo é considerado o tipo subjacente.
Considere o exemplo a seguir, em que o valor ob_type->tp_init de um determinado objeto aponta para a seguinte função:
static int FobObject_init(FobObject* self, PyObject* args, PyObject* kwds) {
return 0;
}
Nesse caso, o depurador pode deduzir corretamente que o tipo C do objeto é FobObject. Se o depurador não puder determinar um tipo mais preciso a partir de tp_init, ele segue para outros campos. Se não for possível deduzir o tipo de qualquer um desses campos, o nó [exibição C++] apresentará o objeto como uma PyObject instância.
Para sempre obter uma representação útil para tipos personalizados, é recomendado registrar pelo menos uma função especial ao registrar o tipo e usar um parâmetro fortemente tipado self. A maioria dos tipos atende a esse requisito naturalmente. Para outros tipos, a tp_init inspeção geralmente é a entrada mais conveniente a ser usada para essa finalidade. Uma implementação fictícia de tp_init de um tipo que está presente apenas para habilitar a inferência do tipo no depurador pode simplesmente retornar zero imediatamente, como no exemplo anterior.
Examinar as diferenças da depuração padrão do Python
O depurador de modo misto é distinto do depurador padrão do Python. Ele apresenta alguns recursos extras, mas não tem alguns recursos relacionados ao Python, da seguinte maneira:
- Os recursos sem suporte incluem pontos de interrupção condicionais, a janela Depuração Interativa e a depuração remota multiplataforma.
- A janela Imediata está disponível, mas com um subconjunto limitado de sua funcionalidade, incluindo todas as limitações listadas nesta seção.
- As versões do Python com suporte incluem apenas o CPython 2.7 e 3.3+.
- Para usar o Python com o Visual Studio Shell (por exemplo, se você instalá-lo com o instalador integrado), o Visual Studio não poderá abrir projetos do C++. Como resultado, a experiência de edição para arquivos C++ é a de apenas um editor de texto básico. No entanto, a depuração de C/C++ e a depuração de modo misto são totalmente suportadas no Shell, incluindo o código-fonte, a navegação no código nativo e a avaliação de expressões C++ nas janelas do depurador.
- Quando você exibe objetos Python nas janelas de ferramentas Locais e Observação do depurador, o depurador em modo misto mostra apenas a estrutura dos objetos. Ele não avalia automaticamente as propriedades nem mostra atributos computados. Para coleções, ele mostra apenas elementos para tipos de coleção internos (
tuple, ,list,dict,set). Os tipos de coleção personalizados não são visualizados como coleções, a menos que sejam herdados de algum tipo de coleção interno. - A avaliação de expressão é realizada conforme mencionado na seção a seguir.
Usar avaliação de expressão
O depurador python padrão permite a avaliação de expressões arbitrárias do Python nas janelas Inspeção e Imediato quando o processo depurado é pausado em qualquer ponto do código, desde que não seja bloqueado em uma operação de E/S ou outra chamada de sistema semelhante. Na depuração de modo misto, expressões arbitrárias só podem ser avaliadas quando paradas no código python, após um ponto de interrupção ou ao entrar no código. As expressões só podem ser avaliadas no thread no qual o ponto de interrupção ou a operação de etapa ocorreu.
Quando o depurador para no código nativo ou no código Python em que as condições descritas não se aplicam, como após uma operação de 'step-out' ou em uma thread diferente. A avaliação de expressão é limitada ao acesso a variáveis locais e globais no escopo do frame atualmente selecionado, acesso aos seus campos e à indexação de tipos de coleção embutidos com literais. Por exemplo, a expressão a seguir pode ser avaliada em qualquer contexto (desde que todos os identificadores se refiram a variáveis e campos existentes de tipos apropriados):
foo.bar[0].baz['key']
O depurador de modo misto também resolve essas expressões de forma diferente. Todas as operações de acesso de membros pesquisam apenas os campos que fazem parte diretamente do objeto (como uma entrada em seu __dict__ ou __slots__, ou um campo de um struct nativo exposto ao Python por meio de tp_members) e ignoram qualquer lógica de descritor. Da mesma forma, todas as operações de indexação ignoram __getitem__e acessam diretamente as estruturas de dados internas das coleções.
Para fins de consistência, esse esquema de resolução de nomes é usado para todas as expressões que correspondem às restrições para avaliação de expressão limitada. Esse esquema é aplicado independentemente de expressões arbitrárias serem permitidas no ponto de parada atual. Para forçar a semântica adequada do Python quando um avaliador completo estiver disponível, coloque a expressão entre parênteses:
(foo.bar[0].baz['key'])