You are on page 1of 49

Hello Python!

Guia Essencial

Bruno Cesar Shiguemichi


Lucas Moreira Laperuta
Conteúdo
1. Motivação.......................................................................................................... 7

2. Conceitos Básicos ............................................................................................ 8

2.1. Sintaxe e Convenções Léxicas ................................................................... 8

2.1.1. Identação e Instruções ........................................................................... 8

2.1.2. Blocos ..................................................................................................... 9

2.1.3. Instruções ............................................................................................... 9

2.1.4. Comentários ........................................................................................... 9

2.1.5. Identificadores e Palavras Reservadas. ................................................. 9

2.1.6. Operadores ............................................................................................10

2.2. Controle de Fluxo ...................................................................................... 11

2.2.1. IF ...........................................................................................................11

2.2.2. WHILE ...................................................................................................12

2.2.3. FOR .......................................................................................................13

2.2.4. RANGE ..................................................................................................15

2.3. Estrutura de Dados ................................................................................... 16

2.3.1. STRINGS ...............................................................................................16

2.3.2. String: Slice ...........................................................................................17

2.3.3. Listas .....................................................................................................19

2.3.4. Funções em listas. .................................................................................19

2.3.5. Pilhas .....................................................................................................22

2.3.6. Filas .......................................................................................................22

2.3.7. Ferramentas de Programação Funcional com Filas ..............................23

2.3.8. Outras ferramentas com Listas. (list comprehensions) ..........................25

2.3.9. Tuplas ....................................................................................................26

2.3.10. Sets .....................................................................................................27

2.3.11. Dicionários ...........................................................................................28

2
2.3.12. Técnicas de Laço em estruturas de dados ..........................................29

2.4. Módulos e Funções ................................................................................... 31

2.4.1. Criando novas Funções .........................................................................32

2.5. Avançando em Funções ............................................................................ 32

2.5.1. Recursão ...............................................................................................32

2.5.2. Argumentos Padrão ...............................................................................33

3. Python e C .......................................................................................................34

3.1. Módulos de Extensão ................................................................................ 34

3.2. Embarcando Python em C ........................................................................ 39

3.2.1. Embedding Alto Nível ............................................................................39

3.2.2. Técnicas avançadas de Embeedding ....................................................41

4. Extras ...............................................................................................................44

4.1. Desempenho ............................................................................................. 44

4.2. Compressão de Dados .............................................................................. 45

5. Apêndice ..........................................................................................................46

5.1. Conversão de dados de Python para C..................................................... 46

5.2. Conversão de dados de C para Python..................................................... 47

5.3. Configurações adicionais distutils ............................................................. 48

6. Bibliografia .......................................................................................................49

3
Índice de Tabelas
Tabela 1: Descrição dos operadores em Python ......................................................10
Tabela 2: Especificadores de formato e tipos em C ..................................................47
Tabela 3: Modificadores de formato ..........................................................................47
Tabela 4: Exemplos de chamadas da função Py_BuildValue().................................48

4
Índice de Códigos Fonte

Código 2-1: Identação em Python .............................................................................. 8


Código 2-2: Importação de módulos e chamadas de funções. .................................31
Código 2-3: Função recursiva de Fibonacci. .............................................................33
Código 2-4: Definição de função com um argumento padrão. ..................................33
Código 2-5: Chamadas de funções com argumentos padrão. ..................................34
Código 3-1: Arquivo module.c a ser extendido. ........................................................35
Código 3-2: Arquivo de configuração setup.py. ........................................................37
Código 3-3: Arquivo de teste test.py .........................................................................38
Código 3-4: Embedding alto nível. ............................................................................39
Código 3-5: Execução do arquivo hello.py através de embedding. ..........................40
Código 3-6: Arquivo reverse.py usado como exemplo para embeeding. ..................42
Código 3-7: Arquivo em C com aplicação Python embarcada ..................................44
Código 5-1: Exemplos de uso para o parâmetro format............................................47

5
“para nosso amigo e professor”

6
1. Motivação
Por que Python? A procura de uma nova linguagem eficiente e de fácil
implementação acaba aqui. Python é a resposta para esta procura, pois além de ser uma
linguagem de alto nível, esta é de simples e rápida programação. Por ser uma linguagem
interpretada, o Python não precisa ser compilado e vinculado durante o processo de
desenvolvimento e isto economiza um tempo razoável.

Python pode ser desenvolvido em módulos e consequentemente isto é uma das


suas características, o reuso da linguagem. Esta linguagem tem uma escrita simples,
legível e permite uma programação compacta dos programas, isto devido à definição dos
blocos de acordo com a identação, ao invés de marcadores. Dessa forma um padrão é
formado e a legibilidade é mais rápida e fácil.

Um ponto forte do Python é a extensão com C/C++. A combinação pode ser feita
tanto de C para Python, quanto de Python para C. Essa facilidade permite um grande
aumento do leque de possibilidades para a programação em Python. Como escrever um
programa com a finalidade do uso como uma linguagem de extensão.

A linguagem foi projetada com a filosofia de enfatizar a importância do esforço do


programador sobre o esforço computacional. Prioriza a legibilidade do código sobre a
velocidade ou expressividade. Combina uma sintaxe concisa e clara com os recursos
poderosos de sua biblioteca padrão e por módulos e frameworks desenvolvidos por
terceiros.

7
2. Conceitos Básicos
2.1. Sintaxe e Convenções Léxicas

Este capítulo descreve as regras de sintaxe e as convenções léxicas de um


programa escrito em Python. Serão apresentados os tópicos de identação, instruções, lista
de palavras reservadas e operadores.

2.1.1. Identação e Instruções


Ao contrário da maioria das linguagens de programação de alto nível, que fazem
uso de limitadores de bloco como “{ }” (C e Java) ou begin/end (Pascal e Delphi), Python
utiliza a própria identação do código para delimitar e distinguir diferentes seções de código.
Isto é, o programador deve definir o número de espaços de identação de um bloco ou
comando e seguir este padrão sempre que houver necessidade de um novo bloco ou
comando. Na prática, a criação de scripts avançados em Python é feita através de editores
especiais (e.g. Notepad++/ IDLE) que facilitam a identação do código e sua legibilidade. Os
trechos de código abaixo ilustram a importância do uso de identação em Python:

Código 2-1: Identação em Python

Note que no primeiro exemplo todas as linhas referentes ao bloco IF foram


identadas com o mesmo número de espaços e o programa executou normalmente. Já no
segundo caso, a cláusula “print var1, var2” teve uma identação diferente, impossibilitando o
interpretador Python de computar o bloco IF, gerando um erro de sintaxe. Erros de

8
identação como esse são comuns quando se inicia a programação em Python vindo de
outras linguagens e deve-se ficar atento durante a programação, reforçando ainda mais a
necessidade de um editor especial.

A seção abaixo apresenta as regras gerais de identação e sintaxe para os principais


componentes de um programa Python:

2.1.2. Blocos
Um bloco é delimitado através da identação de todas suas instruções pela mesma
quantidade de espaços ou tabulações, conforme visto no trecho de código acima.

2.1.3. Instruções
Uma instrução termina no fim de uma linha, mas pode continuar por diversas linhas
se uma linha física terminar com \, ( ) aberto, [ ] ou um par de { }, ou uma string com três
aspas abertas. É possível ter também diversas instruções em uma mesma linha,
separadas por ponto-e-vírgula. Vale lembrar que em Python instruções executam de forma
seqüencial, uma após a outra, a menos que as instruções de fluxo de controle (if, while, for,
etc.) sejam utilizadas.

2.1.4. Comentários
Comentários em Python começam com “#” e continuam válidos pela linha inteira.

2.1.5. Identificadores e Palavras Reservadas.


Assim como em C, Python apresenta uma série de identificadores e palavras
reservadas, úteis para identificar variáveis, funções, classes e módulos internos. A lista a
seguir apresenta todas as palavras reservadas do Python:

and elif global or


assert else if pass
break except import print
class exec in raise
continue finally is return
def for lambda Try
del from not While

9
Identificadores podem incluir letras, números e o caracter underscore, mas devem
sempre começar com um caracter não numérico. Identificadores que começam ou
terminam com underscore apresentam na maioria das vezes significados especiais e não
são o alvo desta apostila. Uma lista completa destes identificadores especiais pode ser
encontrada em [2]

2.1.6. Operadores
A Tabela 1 abaixo apresenta uma lista dos operadores de expressão mais comuns
do Python. Assim como em C, os operadores possuem diferentes ordens de precedência,
estando abaixo organizados de acordo com tais ordens (operadores em células inferiores
possuem precedência mais alta). A lista completa de operadores pode ser obtida em [3].

Operador Descrição
X or Y Ou lógico. Y é avaliado somente se X for falso
X and Y E lógico. Y é avaliado apenas se X for verdadeiro
not X Negação lógica
X < Y , X > Y , X >= Y, X <= Y Operadores de comparação. Podem ser encadeados
X < Y < Z.
X == Y, X <> Y, X != Y Operadores de igualdade
X is Y, X is not Y Testes de identidade de objeto
X in S, X not in S Verifica se X está presente em uma sequência S
X|Y Ou Bitwise
X^V Ou exclusivo Bitwise
X&V E Bitwise
X << Y, X >> Y Deslocamento de X a esquerda e a direita por Y bits.
X + Y, X - Y Adição/concatenação, subtração.
X[i], X[i:j], X.atrr, X(...) Indexação, slicing*, ref. De atributos, chamada de função.
( ... ) , [ ... ] , { ... } Tupla, lista, dicionário
Tabela 1: Descrição dos operadores em Python

A sintaxe e função dos operadores específicos dos tipos de dados do Python


(strings, listas, tuplas, dicionários) serão abordados juntos com suas respectivas seções.

10
2.2. Controle de Fluxo

2.2.1. IF
A construção “IF” em Python é similar à utilizada em C. As instruções “IF”, “ELSE” e
“ELIF” são utilizadas de acordo com a estrutura abaixo:

IF teste:

Comandos

Elif:

Comandos

Else:

Comandos

A seção “elif” pode aparecer zero ou mais vezes e a seção “else” é opcional, assim
como em C. A principal diferença está na delimitação do bloco de comando que em Python
é feita pelo uso de “:” e pela própria identação.

HINT 1: A instrução “elif” é uma abreviação de “else IF” e é útil para evitar identação
excessiva e melhorar a legibilidade do código. A construção “IF...elif...elif...” substitui as
construções “switch e case” utilizadas em outras linguagens.

HINT 2: Instruções “IF/else” alinhadas são mais rápidas de serem testadas do que
instruções “IF/IF”.

11
2.2.2. WHILE
A instrução “while” é semelhante à mesma instrução em C. O laço é executado
enquanto a condição for verdadeira.

while condição :

Comandos

else:

Comandos

A instrução “else” é opcional e ela será executada ou quando o loop inteiro ocorrer
ou se o loop não for executado nenhuma vez. Como no exemplo:

-loop inteiro:

-sem loop

12
2.2.3. FOR
A construção “for” em Python se difere um pouco das construções de outras
linguagens de programação. Na linguagem Pascal a instrução itera sobre progressões
aritméticas, em C é possível definir tanto o passo da iteração, quanto a condição de
parada. Já em Python a iteração é dada sobre uma sequência (lista ou string), na mesma
ordem desta.

For target in sequence:

Comandos

[Else:
Comandos]

A instrução “else” é opcional e como no “while”, o “else” ou é executado depois de


ocorrer o loop inteiro ou caso ele não aconteça. Caso o loop termine antes com a instrução
break (similar em C), o else não é executado. Como no exemplo a seguir:

-sem loop:

13
-break:

HINT 1: Para modificar uma lista em execução, por exemplo, para duplicar os itens,
deve-se gerar uma cópia da lista e modificar sobre esta cópia. Como função “slice” serve
também para fazer uma cópia em alto nível (superficial) do objeto da sequencia, utiliza-se
ela:

CUIDADO: Dentro do loop “for”, as comparações são feitas com elementos da lista
e não com os índices (como em C). Como no exemplo acima (na condição do “if”), x é
comparado com o elemento da lista ‘c’ e não com seu índice.

HINT 2: Para fazer comparações com o índice. Deve-se combinar as instruções


“range” com “len(lista)” . Neste exemplo modificamos a lista também e para isto, utilizou-se
novamente o “slice”:

14
2.2.4. RANGE
A instrução “range” tem o intuito de gerar listas com progressões aritméticas.

range( start, end, step)

O parâmetro “step” é opcional. Os parâmetros devem ser números inteiros.

O valor default do “step” é igual a +1. Observa-se, no exemplo “range(10,5)”, que a


resposta gerado foi nula, pois por default o “step” é igual à +1. Entretanto no exemplo
abaixo “range(10,5,-1)”, o “step” foi alterado para -1 e obteve-se uma lista com regressão.

HINT: A progressão em listas por ser utilizada combinando as instruções


“range+len”, como no exemplo abaixo:

15
2.3. Estrutura de Dados

2.3.1. STRINGS
O Python manipula strings de diversas formas. A delimitação pode ser feita ou com
aspas simples (‘texto’), ou com aspas duplas (“texto”), ou com triplas simples ou triples
duplas (‘’’texto’’’, ou “””texto”””)

A quebra de linha é feita somente com o “\n”, e ao inserir uma string, o símbolo “\”
gera uma quebra de linha na inserção da string, entretanto a quebra de linha não é salva
na string. Exemplo:

O uso do “\n” faz a inserção em uma linha somente, entretanto se combinarmos o


“\n” com o “\” conseguimos tanto inserir com a quebra de linha, quanto gerar uma string
com a quebra de linha também. Como no exemplo:

- Exemplo \n:

-Exemplo \n\:

16
A utilização de triplas aspas (duplas ou simples) gera a quebra de linha automática
tanto na inserção quanto na própria String, como no exemplo:

Da mesma forma para o uso de triplas aspas duplas.

As strings podem ser concatenadas (+) e repetidas (*) com o uso dos respectivos
operadores.

-repetidas

2.3.2. String: Slice


As Strings são listas indexadas assim como em C e o índice começa em “0”.
Podemos combinar a função “slice” e obtermos resultados interessantes. Vale lembrar que
na notação do “Slice [a:b]” o valor respectivo de “a” é incluído até um antes do valor de “b”
respectivo. Como no exemplo:

Pode-se utilizar também índices negativos.

17
Para compreender melhor, segue-se um esquema com os índices:

A B C D E F

0 1 2 3 4 5

-6 -5 -4 -3 -2 -1

O termo “-0 == 0”, ou seja, a referencia estará para o índice “0”.

Diferente de C, as strings em Python não podem alteradas com combinação de


índice.

Entretanto é possível concatenar e formar uma nova combinação.

Os operadores “str(objeto”), “repr(objeto)” e ‘objeto’ são utilizados para transformar o


objeto em uma string.

18
2.3.3. Listas
Listas são sequências de objetos arbitrários. Os valores dentro de uma lista não
precisam ser do mesmo tipo. Os objetos dentro da lista são separados por vírgulas e entre
colchetes. Sua indexação é iniciada em “0” da esquerda para direita e em “-1” da direita
para esquerda. Diferente de “Strings” as listas podem ser modificadas.

2.3.4. Funções em listas.


-append(x) e extend(x)

Adiciona um objeto (x) no final da lista. Este objeto pode ser uma lista.

19
-insert( i , x)

Adiciona um objeto ou lista (x) no índice (i).

-remove(x)

Remove o elemento de valor igual a (x). Caso seja desejado remover com o
valor do índice, combina-se “remove(lista[x])”.

-pop(i)

Remove o elemento da lista com o índice (i) e retorna o índice removido.

20
-index(x)

Retorna o índice do primeiro valor encontrado igual à (x). É gerado um erro


caso o valor não exista.

-count(x)

Retorna a quantidade de elementos na lista com o valor (x)

-sort()

Ordena a própria lista sem gerar uma nova.

-reverse()

Inverte a ordem dos elementos da lista, sem criar uma nova lista.

21
-del

Remove o item da lista e retorna a lista sem o item, ao invés de retornar o


item retirado como no comando “pop()”. Pode-se combinar o comando “Del” com o slice.

2.3.5. Pilhas
A utilização de pilhas em Python é bem simples. Vale lembrar que em pilhas
(“o último a entrar, é o primeiro a sair”). Utilizaremos uma lista com a combinação dos
comandos “append(x)” e “pop()”. A utilização do “pop()” sem argumentos, remove o último
elemento da lista e retorna o mesmo.

2.3.6. Filas
A utilização de filas também é possível com listas. Vale lembrar que em filas
(“o primeiro a entrar, será o primeiro a sair”). De maneira semelhante a pilhas, utilizaremos
a combinação de listas com os comandos “append(x)” e “pop(0)”. O comando “pop()”
dessa vez terá argumento “0”, para dessa forma retornar o primeiro elemento que foi
inserido.

22
2.3.7. Ferramentas de Programação Funcional com Filas
O Python possui 3 ferramentas para programação funcional com filas:

-filter(função, sequencia)

A ferramenta “filter” retorna os elementos da sequencia, com a restrição da


função definida.

-map(função, sequencia)

A ferramenta “map” aplica a função na sequencia e devolve o retorno em uma


lista.

A chamada pode ser feita com mais de uma sequencia.

-reduce(função(x,y), sequencia,z)

23
A ferramenta “reduce” aplica a “função” de dois em dois (os parâmetro da
função devem ser dois) e o resultado é substituído no lugar das duas entradas e a
função dá continuidade com o objeto resultante e o próximo objeto da lista, até o fim
da mesma. A variável “z” é opcional e ela dá inicio da operação reduce.

Observa-se a chamada “reduce(addA, lista2).

Na primeira iteração (x = 111), (y=222)

x+y+’a’+x = 111222a111

A lista fica [111222a111, 333]

Na segunda iteração (x= 111222a111), (y=333)

x+y+’a’+x = 111222a111333a111222a111

A lista no final fica [111222a111333a111222a111]

24
Caso a operação seja chama com uma sequencia vazia e sem valor “z”, o
retorno será um erro. Caso a operação tenha somente um objeto na sequencia e
sem valor “z”, o retorno será este objeto. Caso seja utilizado o “z” e a sequencia
vazia, o retorno será o “z”.

2.3.8. Outras ferramentas com Listas. (list comprehensions)


Nem sempre a utilização das ferramentas “filter()”, “map()”, etc. suprem as
necessidades desejadas. Para isso, pode-se utilizar o operador “for” seguido de zero
ou mais vezes os comandos “if” e/ou “for”, tudo entre chaves.

25
2.3.9. Tuplas
Python também possui Tuplas. Esse tipo de sequencia é imutável e tem
diversas utilidades como base de dados. A sintaxe é dada ou entre parênteses ou
simplesmente sem parênteses, colchetes e chaves. A criação de Tuplas possui o
nome de “tuple packing” , ou seja, quando se empacota os valores em uma tupla. A
operação reversa (sequence unpacking) também é possível.

26
2.3.10. Sets
Sets são seqüências com dados não duplicados e não necessariamente ordenados.
O comando set() pode ser atribuído a uma lista ou apenas à uma palavra. Caso seja a uma
lista, o retorno será uma lista sem itens duplicados. Já no caso de uma palavra, o retorno
será uma lista com todas as letras separadas em objetos distintos. O comando set permite
algumas manipulações com os dados, como união, concatenação, etc. Como no exemplo:

27
2.3.11. Dicionários
Outra estrutura de dados presente em Python são os dicionários, também
chamados de “memória associativa” ou “vetor associativo”. Diferentemente de sequencia,
dicionários não são indexados por valores inteiros, mas sim por chaves “Keys”. Essas
chaves podem ser qualquer tipo imutável de sequencia, como strings e inteiros. Tupla
também pode ser usada se possuir somente valores imutáveis. Listas não podem ser
utilizadas, pois são mutáveis.

Dicionários são delimitados por colchetes {}. A definição interna chave:valor


separada por vírgula define a formatação de dicionário.

As principais operações são resgatar e armazenar valores através das chaves.


Pode-se utilizar o comando “Del” para remover o par chave:valor.

-keys()

Retorna o valor das chaves presente no dicionário (ordem de inserção).

-has_key()

Verifica se a chave está presente no dicionário. Pode-se utilizar também o


comando “in”.

28
-dict()

Cria dicionários com valores chaves a partir de tuplas. Quando existe um


padrão nas chaves, pode-se utilizar “list comprehensions”. Quando as chaves são apenas
strings, pode-se utilizar a forma strings=valor.

2.3.12. Técnicas de Laço em estruturas de dados


-iteritems()

Percorre um dicionário e obter as chaves e os valores

-enumerate()

Percorre uma sequencia qualquer enumerando os valores.

29
-zip()

Percorre duas listas simultaneamente.

-reversed()

Percorre uma lista na ordem reversa

-sorted

Percorre uma lista em ordem aleatória

30
2.4. Módulos e Funções

Ao contrário dos exemplos mostrados até agora, a maioria dos programas


computacionais reais possuem milhares de linhas de código, o que acaba muitas vezes
dificultando sua legibilidade. É neste contexto que a técnica Dividir e Conquistar se faz
necessária, dividindo o programa inicial em pequenas partes ou componentes, facilitando
seu uso e manutenção. Assim como em C e Java, Python possibilita o desenvolvimento de
funções, classes e módulos, componentes essenciais para o design, a implementação e a
manutenção de programas grandes. A seção abaixo introduz o uso de módulos e funções
pré-definidas na linguagem Python e a sintaxe usada para criá-las.

Módulo é o nome que se dá para o conjunto de definições de funções e elementos


que se relacionam entre si. Um módulo muito conhecido na área de física e engenharia é o
math. Tal módulo define uma série de funções e constantes matemáticas que facilitam a
manipulação algébrica, tratamento de sinais e a construção de programas. Assim como em
C e Java, a utilização de módulos é realizada primeiramente com a importação deste e
posteriormente com o uso de seus elementos (chamadas de funções, atribuições de
constantes definidas, etc.). O trecho de código abaixa exemplifica o uso de algumas
funções definidas no módulo math.(na IDE de Python basta escrever “math.”, apertar Ctrl +
space e a lista de funções definidas para o módulo aparece, conforme ilustrado abaixo.)

Código 2-2: Importação de módulos e chamadas de funções.

31
Adicionalmente, é possível importar apenas determinadas funções de um módulo,
utilizando a sintaxe abaixo:

from módulo import função1, função2

2.4.1. Criando novas Funções


Python permite a criação de funções de forma bem simples, de acordo com a
sintaxe abaixo:

def nome-função (lista-parâmetros) :


“””Informação opcional – docstrings”””
corpo-função

O nome da função deve ser um identificador válido, conforme visto na seção 3.1.5.
A lista de parâmetros é separada por vírgula e assim como qualquer outro bloco em
Python, é a identação que delimita o corpo da função. Opcionalmente pode-se ter na linha
anterior ao corpo da função um string literal com informações sobre a função, podendo ser
posteriormente usado em documentação externa, analogamente a ferramenta JavaDoc
presente em Java.

Note que, ao contrário de C, não há necessidade de se definir o tipo da função nem


de seus parâmetros (e.g. void, int, float), tornando a criação de funções e sua utilização em
um programa Python muito mais rápida e flexível.

2.5. Avançando em Funções

2.5.1. Recursão
Assim como outras linguagens, Python permite o uso de recursão em
funções, isto é, uma função que chama a si própria em seu corpo. O exemplo abaixo
mostra a criação de uma função recursiva para o clássico “Números de Fibonacci”:

32
Código 2-3: Função recursiva de Fibonacci.

2.5.2. Argumentos Padrão


Na grande maioria das linguagens de programação, quando se efetuam chamadas
de funções, é de responsabilidade do programador fornecer os valores para os argumentos
da função. Em Python, durante a definição de uma função, é possível especificar
argumentos como default arguments, informando um valor padrão para ele. Desta forma, a
passagem de parâmetros se torna opcional, permitindo ao programador especificar menos
argumentos durante uma chamada de função. Os exemplos abaixo ilustram o uso de
argumentos padrão em funções:

Código 2-4: Definição de função com um argumento padrão.

Argumentos padrão devem parecer à direita de qualquer outro argumento não


padrão na lista de parâmetros de uma função. Desrespeitar tal convenção leva a erros de
sintaxe. O exemplo abaixo ilustra o uso de vários argumentos padrão. Note que se algum
argumento padrão foi omitido, este será sempre o mais a direita:

33
Código 2-5: Chamadas de funções com argumentos padrão.

3. Python e C
Uma das grandes vantagens de Python é a possibilidade de se trabalhar em
conjunto com outras linguagens de programação, em especial C e C++. Em vias gerais,
existem dois modos de se utilizar Python em conjunto com C em um mesmo processo:
Chamadas de código em C por Python ou; chamadas de código em Python por C. No
primeiro caso, módulos de Python são implementados em linguagem C/C++, permitindo
realizar chamadas de funções (da linguagem e de system calls) e criar novos tipos de
objetos, ações essas que o Python não conseguiria realizar diretamente. No segundo caso,
desenvolvem-se aplicações escritas em C/C++ capazes de carregar e executar scripts de
Python.

3.1. Módulos de Extensão

O uso de módulos de extensão é útil quando se deseja migrar um projeto existente


de uma linguagem para outra ou realizar testes de profiling, geralmente realizados com
protótipos escritos em Python e posteriormente estendidos para C/C++.

O suporte a extensões em Python é gerido pela Python API (Application


Programmers Interface), que define um conjunto de funções, macros e variáveis para o
acesso as características do Python em outras linguagens. O acesso de C ou C++ via uma
extensão é feito através da escrita de um wrapper (envoltório), responsável por converter
argumentos de uma função de Python para C e retornar resultados em C de volta para
Python, de modo que esta linguagem possa tratá-la.

34
Os exemplos abaixo foram desenvolvidos em ambiente Linux utilizando a
distribuição Python 2.6, o compilador gcc nativo e a biblioteca de Python distutils.
Instruções para desenvolvimento em ambiente Windows podem ser obtidas em [4].

Vamos criar um módulo de extensão para a função fatorial. Primeiramente deve-se


escrever em C um arquivo contendo a função fatorial a ser extendida, o wrapper e sua
inicialização.

Código 3-1: Arquivo module.c a ser extendido.

Após inclusão da API Python ao código em C feito através da cláusula


#include “Python.h” e a escrita da função _fact, deve-se criar o wrapper para esta função,
neste exemplo denominada fact, responsável por receber os argumentos de Python,
realizar manipulações em C e retornar dados ao Python (vale lembrar que cada função
definida deve possuir um wrapper próprio). Independente da função a ser extendida, o
wrapper sempre apresenta dois argumentos, convencionalmente chamados de self e args.

35
O argumento self só é usado quando funções em C implementam métodos
built-in e não propriamente uma função. O argumento args é um ponteiro para uma tupla
em Python contendo os argumentos. Tais argumentos são objetos Python e precisam ser
convertidos para tipos de dados aceitos por C antes de poder realizar as devidas
manipulações. A conversão é feita pela função PyArg_ParseTuple(), cujos argumentos são
a tupla contendo os argumentos do Python (args), o tipo(s) para conversão (“i” para inteiro,
“s” para string, etc.) e a variável(is) que armazenará(ão) o resultado da conversão (arg0).
Exemplos de chamadas da função PyArg_ParseTuple() são descritas na seção 5.1.

A cláusula acima retorna TRUE se todos os elementos da tupla args foram


devidamente convertidos e FALSE caso ocorra algum erro. Além disso, a variável que
receberá o resultado da conversão (arg0) deve sempre ser definida com o classificador
const de modo a evitar erros durante a compilação

Com os argumentos devidamente convertidos e armazenados, pode-se agora


realizar as manipulações desejáveis utilizando manipulações em C, neste caso a chamada
da funcção fatorial do número passado pelo Python. Feito isso, é preciso retornar o
resultado para o Python e como este só “entende” objetos, a função Py_BuildValue()
realiza a conversão, recebendo o tipo de dados a ser convertido e a variável que será
convertida.

A definição do wrapper sozinha não é suficiente para realizar chamadas de


código em C pelo Python. Antes, é preciso criar uma lista de métodos e adicionar o
wrapper nela. A criação da lista e adição do wrapper são feitas simultaneamente através
da construção do objeto Methods[], inicializado passando-se as tuplas correspondentes a
cada wrapper onde cada elemento corresponde ao nome a ser usado para o wrapper, sua
implementação, seus argumentos e uma string com uma breve descrição de sua função.
Após a inclusão de todos os wrappers é preciso adicionar uma tupla nula para auxiliar o
interpretador Python.

36
Finalmente, com todos os wrappers definidos e listados, é necessário inicializar o
módulo, feito através da função Py_ InitModule(), que recebe como argumentos o nome a
ser usado para o método e a lista de wrappers recém criada. A função de inicialização
deve sempre se chamar initnome(), onde nome corresponde ao nome do módulo a ser
inicializado pela Py_InitModule(), neste caso, module.

Apenas a escrita do arquivo module.c não é suficiente para realizar a extensão de C


em Python. O passo seguinte consiste em, utilizando a biblioteca distutils presente na
linguagem Python, criar um arquivo de configuração responsável pela compilação do
módulo em Python e por possíveis operações de pré processamento, tais como inclusões
de bibliotecas e diretórios de pesquisa. O código abaixo corresponde ao arquivo setup.py
necessário para a extensão do módulo criado neste exemplo (module.c). Abordagens mais
complexas para o arquivo de configuração podem sem encontradas na seção 5.3.

Código 3-2: Arquivo de configuração setup.py.

O arquivo de configuração inicia-se com a importação das funções setup e


Extension presentes na biblioteca distutils. Feito isso, deve-se inicializar os possíveis
módulos através da função Extension(), cujos argumentos são: o nome a ser usado para o
módulo (‘module’);e os arquivos fontes em C a serem extendidos (module.c). Argumentos
opcionais para a função Extension() serão abordados na seção 5.3. Note que estamos
associando nosso módulo a um objeto (neste caso, associado ao objeto module1), ação
que facilita o controle e adição de novos módulos.

37
Por fim, todos os módulos inicializados são passados para a função setup() para
criação de um pacote de módulos, cujos atributos são nome do pacote, versão atual
(usada para controle de versões), descrição do pacote e conjunto de módulos pertencentes
a ele.

De posse, no mesmo diretório, do módulo em C a ser extendido (module.c) e do


arquivo de configuração em Python (setup.py), é necessário executar o seguinte comando
no terminal do Linux:

# python setup.py build

O comando acima compila o arquivo module.c com as definições existentes


no arquivo setup.py, gerando uma shared library, criada na pasta build. Este arquivo,
usualmente de nome module.so ou module.pyd é o arquivo necessário para realizar as
chamadas de C em um arquivo Python.

Para testar a funcionalidade do módulo vamos criar um arquivo simples em


Python, denominado test.py, e importar nosso módulo recém compilado (module.so), de
acordo com o seguinte código:

Código 3-3: Arquivo de teste test.py

Vale lembrar que para importar o módulo, o arquivo com a extensão


module.so deve estar no mesmo diretório de trabalho do arquivo test.py ou em algum
diretório de busca da variável de ambiente PATH. Com o módulo importado, basta chamar
a função fact passando o número desejado como parâmetro. Lembre-se que a função fact
funciona como interface entre C e Python, convertendo o objeto passado como parâmetro
para um valor inteiro em C, realizando a operação do fatorial e retornando o resultado de
modo que Python possa fazer uso dele.

O exemplo acima mostrou a criação e utilização de um módulo de extensão


bastante simples para a função fatorial, porém, os conceitos aqui envolvidos são os
mesmos, podendo ser aplicados também para a criação de módulos mais complexos.

38
3.2. Embarcando Python em C

A seção anterior discutiu e exemplificou o uso de módulos de extensão


escritos em C na linguagem Python, ampliando seu leque de funcionalidades. Conforme
dito anteriormente, é possível fazer o caminho inverso, embarcando a API Python em uma
aplicação escrita em C/C++. A incorporação da API Python em aplicações é útil pois
algumas funcionalidades podem ser escritas mais rapidamente em Python, além de
permitir personalizar aplicações escritas em C com scripts em Python.

Existem diferentes formas de embarcar a linguagem Python em uma


aplicação. As seções abaixo discutem e exemplificam os principais modos existentes.

3.2.1. Embedding Alto Nível


A forma mais simples de se embarcar Python é através do uso de interfaces
alto nível, que executam scripts em Python, mas não interagem diretamente com a
aplicação. As funções utilizadas para este tipo de embedding são Py_Initialize(),
Py_Finalize(), Py_SimpleStrig() e Py_SimpleFile, todas presentes na biblioteca Python.h.
O exemplo abaixo ilustra a utilização destas funções em uma aplicação simples em C.

Código 3-4: Embedding alto nível.

A função Py_Initialize() é responsável por iniciar o interpretador Python, alocando os


recursos necessários e deve sempre ser chamada antes de qualquer outra função em
Python. PyRun_SimpleString(), como o próprio nome diz, possibilita a execução de códigos
arbitrários em Python, cuja interpretação se dá de forma imediata. O parâmetro desta
função deve ser uma linha inteira de código Python, isto é, chamadas parciais da função
PyRun_SimpleString(), exemplo do código abaixo, não irão funcionar corretamente.

39
PyRun_SimpleString("import ");
PyRun_SimpleString("math\n");

Note ainda o uso obrigatório no final de cada linha de comando do identificador “\n”,
necessário para o interpretador reconhecer o término de um comando. Por fim, a função
Py_Finalize() é a ultima função a ser chamada quando do embedding de Python, pois esta
desliga o interpretador e libera todos os recursos alocados durante o processo de
embedding.

Com o código pronto, basta executar os seguintes comandos no terminal do Linux,


lembrando que estamos usando a distribuição Python 2.6 (para versões mais antigas basta
mudar o número da versão durante a inclusão das bibliotecas).

#gcc embed.c -o embed -I/usr/include/python2.6 -lutil /usr/lib/libpython2.6.so


#./embed

Ainda sobre embedding alto nível, a função PyRun_SimplesString() pode ser


substituída pela função PyRun_SimpleFile(), com a única diferença de esta ter como
parâmetros um ponteiro para o arquivo escrito em Python e o nome deste arquivo. Por
exemplo, a chamada da função abaixo irá executar os comandos presentes no arquivo
hello.py.

Código 3-5: Execução do arquivo hello.py através de embedding.

Outra funcionalidade permitida para o embedding de Python é a integração com


módulos de extensão. Por exemplo, é possível, utilizando a função PyRun_SimpleFile(),
chamar o arquivo test.py apresentado na seção 3.1. Como este arquivo faz referência ao
módulo de extensão module.so é necessário que este seja instalado no conjunto de
bibliotecas do Python. Para isso, usamos o mesmo arquivo de configuração setup.py,
executando o seguinte comando no terminal:

40
#python setup.py install

A execução deste comando seguida dos comandos de compilação descritos


anteriormente permitem que nosso módulo para a função fatorial será corretamente
executado.

3.2.2. Técnicas avançadas de Embeedding


A seção anterior apresentou a execução de strings e arquivos através do
interpretador Python embarcado. Neste tipo de abordagem não há interação direta entre o
código em Python e a aplicação em C. No entanto, na maioria das aplicações é necessário
uma constante interação entre o código Python, o interpretador embarcado e a aplicação
host e este tipo de abordagem alto nível não é o mais adequado.

Conforme dito anteriormente, Python trata praticamente tudo como objeto de


determinado tipo, e é através deles que o verdadeiro embeedding acontece, permitindo a
extração de atributos e uso de formatos de referência para acesso a módulos e funções.
Para começar o embeedding, criaremos primeiramente um módulo contendo funções
simples de inversão dos principais tipos de dados em Python: números, strings, listas e
dicionários. O arquivo reverse.py abaixo contém a implementação destas funções.

41
Código 3-6: Arquivo reverse.py usado como exemplo para embeeding.

Lembre-se que para utilizar este módulo, deve-se ser criado um arquivo de
configuração semelhante ao criado na seção 3.1 e executar o comando para instalação do
módulo descrito na seção 3.2.1.

As funções acima descritas só podem ser acessadas em conjunto com uma


aplicação embarcada através do acesso à referencias de seus objetos. A função
PyObject_GetAttrString() captura um atributo de um objeto, através do acesso do mesmo
na lista de atributos. Tal função recebe como parâmetro um objeto e o atributo do objeto
que se deseja ter acesso.

Suponha que desejamos acessar a função rstring, que no caso acima é um atributo
do objeto reverse, passar como parâmetro uma string a ser revertida e por fim imprimir na
tela a string invertida (estas duas ultimas ações executadas na aplicação host em C). Para
permitir a troca de informações entre o módulo Python embarcado e a aplicação host em C
primeiramente pode ser descrita com a seguinte sequência de passos:

1. Importar o módulo que contém a função desejada.


2. Capturar a referência da função através do acesso ao atributo do módulo

42
3. Chamar a função desejada
4. Converter o objeto Python de retorno em uma variável C.

A importação do módulo é feita através da chamada da função


PyImport_ImportModule(), cujo parâmetro é o nome do módulo a ser importado e retorna
um objeto Python, que neste caso é um objeto módulo. Este objeto de retorno é importante
para o acesso da função através de PyObject_GetAttrString(). O trecho abaixo exemplifica
a importação do módulo.

PyObject *mod = NULL;


mod = PyImport_ImportModule("reverse");

O objeto de retorno da função (mod) é usado então para captura da função rstring,
atrvés do acesso de seu correspondente atributo pela função PyObject_GetAttrString().
Novamente o retorno é um objeto e o código abaixo ilustra a captura da função no módulo.

PyObject *strfunc = NULL;


strfunc = PyObject_GetAttrString(mod,"rstring");

O objeto resultante é uma referencia a função, podendo ser usado para chamadas
da função através de um wrapper em C. Com a função devidamente referenciada em um
objeto (strfunc), deve-se construir a lista de argumentos a ser passada a ela. Neste caso,
como há apenas um argumento para a função, pode-se usar a já vista Py_BuildValue()
para converter a string a ser passada como parâmetro em um objeto para rstring, seguindo
o código abaixo..

PyObject *strargs = NULL;


strargs = PyBuildValue("(s)","HelloWorld");

Estando apto a realizar a chamada da função, utiliza-se a PyEval_CallObject(), que


recebe como parâmetro um objeto (strfunc) e sua lista de parâmetros (strargs).

PyObject *strret = NULL;


strret = PyEval_CallObject(strfunc,strargs);

Finalmente, com a chamada da função sendo executada corretamente e seu retorno


armazenado no objeto strret, basta convertê-lo em uma variável C através da função
PyArg_Parse() e imprimir o resultado na tela.

43
Char *string = NULL;
PyArg_Parse(strret,"s",&string);
printf("String Invertida:%s\n",string);

O arquivo completo em C é descrito abaixo:

Código 3-7: Arquivo em C com aplicação Python embarcada

4. Extras
4.1. Desempenho

Assim como outras linguagens, Python fornece uma ferramenta para medição de
profiling e desempenho de código, úteis para comparar diferentes abordagens de um
problema e identificar pontos críticos e programas escritos na linguagem. Os módulos
utilizados para medidas de desempenho são: timeit, profile e pstats. O trecho de código
abaixo exemplifica o uso do módulo timeit para comparação de desempenho entre duas
abordagens de declaração e instanciação de variáveis.

44
>>> Timer('a,b=1,2;').timeit()
0.05402044160980779
>>> Timer('a=1;b=2;').timeit()
0.050916166610463165

O módulo timeit, apesar de útil para pequenas comparações, apresenta uma


granularidade de resultado elevada, tornando-o inadequado para testes de profiling em
programas maiores. Nestes casos, usa-se os módulos profile e pstats. Outro módulo
disponível para profiling é o módulo cProfile, desenvolvido em C cujo exemplo de uso
encontra-se abaixo.Documentação adicional pode ser obtida em [4].

>>> def ex():


x=1;
n=0;
while x < 20:
x = x + (x/3);
n = n +1;
return n
>>> import cProfile
>>> cProfile.run('ex()')
3 function calls in 41.482 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 41.482 41.482 41.482 41.482 <pyshell#39>:1(ex)
1 0.000 0.000 41.482 41.482 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}

4.2. Compressão de Dados

Python disponibiliza alguns módulos para arquivamento e compressão de dados,


sendo os principais: zlib, gzip, bz2, zipfile e tarfile. O exemplo abaixo ilustra a utilização do
módulo zlib Documentação adicional sobre os módulos pode ser obtida em [4].

>>> import zlib


>>> string = 'Esta frase sera comprimida com o comando zlib.compress()'
>>> len(string)
56
>>> string2 = zlib.compress(string)
>>> len(string2)
51

45
>>> zlib.decompress(string2)
'Esta frase sera comprimida com o comando zlib.compress()'
>>> print string
Esta frase sera comprimida com o comando zlib.compress()
>>> print string2
xœs-.ITH+J,NU(N-JTHÎÏ-(ÊÌÍL3òAdb^J¾BUNf’-XC

5. Apêndice
5.1. Conversão de dados de Python para C

As seguintes funções presentes na biblioteca Python.h são responsáveis pela


conversão de dados passados por Python em C.

int PyArg_ParseTuple (PyObject *args, char *format, ... );

A função acima, utilizada no exemplo da seção 3.1, converte uma tupla de objetos
de args para uma série de variáveis em C. O parâmetro format corresponde aos possíveis
tipos das variáveis para conversão.

int PyArg_ParseTupleAndKeywords (PyObject *args, PyObject *kwdict, char


*format, char **kwlist, ... );

Além da tupla contendo os objetos, esta função recebe como parâmetro um


dicionário contendo argumentos chaves em kwdict. O parâmetro format apresenta o
mesmo significado da função PYArg_ParseTuple(), a única diferença é a presença do
parâmetro kwlist, uma lista de strings contendo os nomes de todos os argumentos. A
tabela abaixo descreve os possíveis uso para o parâmetro format nas chamadas das
funções de conversão.

format Tipo em Python Tipo em C


“s” String ou Unicode char **r
“s#” String ou Unicode char **r, int *len
“z” String, Unicode ou Vazio char **r
“z#” String, Unicode ou Vazio char **r, int *len
“b” Inteiro char *r
“h” Inteiro short *r
“i” Inteiro int *r
“l” Inteiro long int *r
“c” String unitária char **r

46
“f” Float float *r
“d” Float double *r
“O” Qualquer PyObject **r
“O!” Qualquer PyTypeObject *type, PyObject **r
Tabela 2: Especificadores de formato e tipos em C

Além das possibilidades citadas acima, existem quatro modificadores que


podem ser aplicados ao parâmetro format. São eles:

String de format Descrição


“(items)” Tupla de objetos
“|” Início de argumentos opcionais
“:” Término de argumentos (o texto seguinte é o nome da função)
“;” Término de argumentos (o texto seguinte é a mensagem de erro)
Tabela 3: Modificadores de formato

Os exemplos abaixo ilustram alguns possíveis usos e modificadores para o


parâmetro format.

Código 5-1: Exemplos de uso para o parâmetro format.

5.2. Conversão de dados de C para Python

A biblioteca Python.h define também uma função para conversão de dados


originários de C para Python:

PyObject *Py_BuildValue (char *format, ...)

47
A chamada desta função constrói um objeto em Python através de variáveis em C.
O parâmetro format é análogo ao utilizado nas funções PyArg_Parse* e os outros
parâmetros da função são as variáveis a serem convertidas. A tabela a seguir ilustra
chamadas para a função Py_BuildValue().

Chamada da função Resultado conversão


Py_BuildValue(“i”, 37) 37
Py_BuildValue(“[ii]” , 1 , 2) [1, 2]
Py_BuildValue(“ids”, 37, 3.4, “hello”) (37, 3.4, “hello”)
Tabela 4: Exemplos de chamadas da função Py_BuildValue()

5.3. Configurações adicionais distutils

Na criação do arquivo de configuração steup.py é possível adicionar opções extrads


de pré compilação e linkagem tais como as que seguem abaixo:

Módulo de extensão com mais de um arquivo fonte:

Extension('test', ['src/test1.c', 'src/test2.c'])

Opção de pré compilação com adição de diretórios include:

Extension(‘test’, ['test.c'], include_dirs=['include'])

Ainda sobre diretórios, pode se trabalhar com referências absolutas:

Extension('test', ['test.c'], include_dirs=['/usr/include/X11'])

É possível também adicionar diretórios de pesquisa de bibliotecas padrão,


semelhante a adição de diretórios include:

#bibliotecas presentes no diretório de busca padrão


Extension(...,
libraries=['gdbm', 'readline'])
#bibliotecas presentes em outros diretórios

Extension(...,
library_dirs=['/usr/X11R6/lib'],
libraries ['X11', 'Xt'])

48
6. Bibliografia
[1] BEAZLEY, D. M. Python - Essential Reference. Indianapolis: New Riders Publishing, 2001.

[2] DEITEL, H. M. et al. Python - How to Program. New Jersey: Deitel, 2002.

[3] LUTZ, M. Python - Pocket Reference. [S.l.]: O'Reilly Media, 2006.

[4] PYTHON SOFTWARE FOUNDATION. The Python Standard Library, 2010. Disponivel em:
<http://docs.python.org/library/>.

[5]RAGESTORM. Tutorial - Embedded Python, 2003. Disponivel em:


<http://www.ragestorm.net/tutorial?id=21>.

[6] VAN ROSSUM, G. Tutorial Python. [S.l.]: Python Software Foundation, 2005.

[7] WIKIBOOKS. Python Programming/Extending with C, 2009. Disponivel em:


<http://en.wikibooks.org/wiki/Python_Programming/Extending_with_C>.

49

You might also like