49
Hello Python! Guia Essencial Bruno Cesar Shiguemichi Lucas Moreira Laperuta

Hello Python

Embed Size (px)

Citation preview

Page 1: Hello Python

Hello Python! Guia Essencial

Bruno Cesar Shiguemichi

Lucas Moreira Laperuta

Page 2: Hello Python

2

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

Page 3: Hello Python

3

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

Page 4: Hello Python

4

Í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

Page 5: Hello Python

5

Í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

Page 6: Hello Python

6

“para nosso amigo e professor”

Page 7: Hello Python

7

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.

Page 8: Hello Python

8

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

Page 9: Hello Python

9

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

Page 10: Hello Python

10

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

X < Y < Z.

Operadores de comparação. Podem ser encadeados

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.

Page 11: Hello Python

11

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”.

Page 12: Hello Python

12

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

Page 13: Hello Python

13

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:

Page 14: Hello Python

14

-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”:

Page 15: Hello Python

15

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:

Page 16: Hello Python

16

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\:

Page 17: Hello Python

17

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.

Page 18: Hello Python

18

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.

Page 19: Hello Python

19

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.

Page 20: Hello Python

20

-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.

Page 21: Hello Python

21

-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.

Page 22: Hello Python

22

-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.

Page 23: Hello Python

23

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)

Page 24: Hello Python

24

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]

Page 25: Hello Python

25

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.

Page 26: Hello Python

26

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.

Page 27: Hello Python

27

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:

Page 28: Hello Python

28

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”.

Page 29: Hello Python

29

-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.

Page 30: Hello Python

30

-zip()

Percorre duas listas simultaneamente.

-reversed()

Percorre uma lista na ordem reversa

-sorted

Percorre uma lista em ordem aleatória

Page 31: Hello Python

31

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.

Page 32: Hello Python

32

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”:

Page 33: Hello Python

33

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:

Page 34: Hello Python

34

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.

Page 35: Hello Python

35

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.

Page 36: Hello Python

36

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.

Page 37: Hello Python

37

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.

Page 38: Hello Python

38

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.

Page 39: Hello Python

39

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.

Page 40: Hello Python

40

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:

Page 41: Hello Python

41

#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.

Page 42: Hello Python

42

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

Page 43: Hello Python

43

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.

Page 44: Hello Python

44

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.

Page 45: Hello Python

45

>>> 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

Page 46: Hello Python

46

>>> 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

Page 47: Hello Python

47

“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, ...)

Page 48: Hello Python

48

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'])

Page 49: Hello Python

49

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>.