Arquivo da tag: python

SWX Labs 06 – Python

capa01

No SWX Labs 06 Mike, Vinicius e Tássio conversam com Rodrigo Amaral sobre Python.

Como surgiu a linguagem, qual sua evolução, diferenciais, onde ela é aplicada e como funciona a comunidade que divulga e dá suporte a uma das linguagens de programação que mais cresce e se credencia a ser o Java do futuro.

Ouça o podcast clicando no play, se preferir faça o download

Temas abordados

  • História do Python
  • Particularidades da Sintaxe
  • Ferramentas e aplicações
  • Mercado de trabalho
  • Comunidade e eventos sobre Python

Links

2º GDG Aracaju: Aplicações web com Python e Google App Engine

gdg-aju-python

Assine o feed do nosso podcast e não perca nenhum episódio: http://feeds.feedburner.com/SWXLabs

Se preferir, também estamos no Itunes Store

Gostou? Não gostou? Erramos algo? Sua opinião é muito importante para nós, por isso deixe seu comentário ou envie email para mike@swx.com.br

Introdução aos “decorators” do Python

Fonte: IMasters

Texto original disponível em: http://www.artima.com/weblogs/viewpost.jsp?thread=240808

Este recurso incrível apareceu na linguagem quase se desculpando, e com preocupações de que poderia não ser tão útil. Eu, por minha vez, acredito que em tempo ele será visto como um dos recursos mais poderosos na linguagem. O problema é que todas as introduções à decorators que eu já vi foram bastante confusas, então vou tentar consertar isso neste artigo.

Decorators vs. decorators pattern

Primeiro, você precisa entender que a palavra “decorator” foi usada com certo receio, porque existia uma preocupação em que confundissem o decorator pattern do livro Design Patterns. Outros termos foram considerados para substituí-lo, mas “decorator” parece ser o escolhido.

Na verdade, você pode utilizar os decorators do Python para implementar um decorator pattern, mas esse é um uso muito limitado dele. Os decorators do Python, acredito, se equivalem mais aos macros.

História dos macros

O macro tem uma longa história, mas a maioria das pessoas provavelmente tiveram experiências com os macro processadores C. Os problemas com os macros C eram os seguintes: eles estavam em uma linguagem diferente da C, e o comportamento deles, às vezes, era bizarro e inconsistente com o comportamento do resto do C.

Tanto o Java, quanto o C# adicionaram anotações, que permitem que você faça algumas coisas para os elementos da linguagem. Ambos têm problemas para fazer o que você quer. Às vezes você tem que pular através de um círculo grande e complexo. Há também o fato de que esse recurso de anotações tem suas mãos atadas pela escravidão e disciplina (ou como Martin Fowler gentilmente coloca: “Direcionamento”) natural dessas linguagens.

Muitos programadores C++ (inclusive eu) notaram as habilidades geradoras de templates C++ e utilizaram esse recurso de uma maneira macro.

Muitas outras linguagens incorporaram os macros. Eu, ainda sem saber muito sobre eles, ouso a dizer que os decoradores do Python são parecidos com os macros do Lips em poder e em possibilidades.

O objetivos dos macros

Acredito que seja certo dizer que o objetivo dos marcos em uma linguagem é fornecer uma maneira de modificar os elementos da mesma. É isso que os decorators fazem no Python: eles modificam funções. É por isso que eles normalmente fornecem uma alternativa mais simples para metaclasses.

As maiores falhas da maioria das abordagens de modificações próprias das linguagens são que elas são muito restritivas e que precisam de uma linguagem diferente (posso dizer que as anotações Java compreendem uma “linguagem diferente”, ainda que com todos os problemas pelos quais você deve passar para produzir uma anotação interessante).

O Python cai na categoria de Fowler de “habilitar” linguagens, então se você quiser fazer modificações, por que criar uma linguagem diferente, ou restrita? Por que simplesmente não usar o Python? E é isso que os decorators de Python fazem.

O que você pode fazer com decorators?

Decorators permitem que você insira, ou modifique o código em funções, ou classes. Parece um pouco como Aspect-Oriented Programming (AOP) em Java, não? Exceto que é muito mais simples e poderoso. Por exemplo, suponha que você gostaria de fazer algo nos pontos de entrada e saída de uma função (como executar algum tipo de segurança, rota, bloqueio, etc – todos os argumentos padrões para AOP). Com decorators, fica assim:

@entryExit
def func1():
print "inside func1()"
 
@entryExit
def func2():
print "inside func2()"
O @ indica a aplicação do decorator.

Decorators de funções

O decorator de uma função é aplicado a uma definição de função ao ser colocado na linha antes da que começa a definição da função. Por exemplo:

@myDecorator
def aFunction():
print "inside aFunction"

Quando o compilador passa por este código, a aFunction() é compilada e o objeto da função resultante é passado para o código myDecorator, que faz algo para produzir um objeto do tipo função, que é, então, substituído pelo original aFunction().

Com o que o código myDecorator se parece? Bom, a maior parte dos exemplos introdutórios o mostra como uma função, mas eu achei mais fácil começar a compreender os decorators usando classes como mecanismos de decoração, ao invés de funções. Além disso, é mais poderoso.

O único lado ruim de um objeto retornado por um decorator é que ele pode ser usado como uma função – o que basicamente significa que ele deve ser chamável. Assim, quaisquer classes que usarmos como descoradores devem implementar __call__.

O que um decorator faz? Bem, ele pode fazer qualquer coisa, mas normalmente você espera que o código da função original seja usado em algum ponto. Isso não é necessário, no entanto:

class myDecorator(object):
 
def __init__(self, f):
print "inside myDecorator.__init__()"
f() # Prove that function definition has completed
 
def __call__(self):
print "inside myDecorator.__call__()"
 
@myDecorator
def aFunction():
print "inside aFunction()"
 
print "Finished decorating aFunction()"
 
aFunction()

Quando você rodar esse código, o verá assim:

inside myDecorator.__init__()
inside aFunction()
Finished decorating aFunction()
inside myDecorator.__call__()

Note que o construtor para myDecorator é executado no ponto da decoração da função. Como podemos chamar f() dento de __init__(), isso mostra que a criação de f() está completa antes do decorator ser chamado. Note, também, que o construtor do decorator recebe o objeto da função sendo decorado. Normalmente, você irá capturar o objeto da função no construtor e depois utilizá-lo no método __call__() (o fato de que decoração e chamado são duas fases claras quando se utiliza classes, é o motivo pelo qual eu argumento que esse é o modo mais fácil e mais poderoso).

Quando aFunction() é chamada depois de ter sido decorada, temos um comportamento completamente diferente; o método myDecorator.__call__() é chamado, ao invés do código original. Isso acontece porque o ato da decoração substitui o objeto da função original com o resutlado da decoração – no nosso caso, o objeto myDecorator substitui aFunction. De fato, antes dos decorators serem adicionados, você tinha que fazer algo muito menos elegante para alcançar a mesma coisa:

def foo(): pass
foo = staticmethod(foo)

Com a adição do operador de decoração @, agora você tem o mesmo resultado dizendo:

@staticmethod
def foo(): pass

Esse é o motivo pelo qual as pessoas argumentam contra os decorators, porque o @ é apenas uma sintaxe simplificada, que significa “passar um objeto de função, através de outra função, e atribuir o resultado à função original”.

Acredito que a razão pela qual os decorators sentem tanto o impacto é porque essa maneira mais fácil, também conhecida como “syntactic sugar“, muda o modo como você pensa programação. Certamente, ele traz a ideia de “aplicar código a outro código”(por exemplo, macros) no pensamento dominante ao formalizá-lo como um construtor de linguagem.

Levemente mais útil

Agora, vamos voltar e implementar o primeiro exemplo. Aqui, vamos fazer a coisa mais comum e de fato utilizar o código nas funções decoradoras:

class entryExit(object):
 
def __init__(self, f):
self.f = f
 
def __call__(self):
print "Entering", self.f.__name__
self.f()
print "Exited", self.f.__name__
 
@entryExit
def func1():
print "inside func1()"
 
@entryExit
def func2():
print "inside func2()"
 
func1()
func2()
A saída é:
 
Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2

Você pode ver que as funções decoradoras agora tem as declarações das linha “Entering” e “Exited” em volta do chamado.

O construtor armazena o argumento, que é o objeto da função. No chamado, usamos o atributo da função __name__ para exibir o nome da função, e então chamá-la.

Usando funções como decorators

A única restrição no resultado de um decorator é que ele é chamável, então ele pode substituir propriamente a função decoradora. Nos exemplos acima, eu substitui a função original com um objeto de classe que tem um método __call__(). Mas um objeto de função também é chamável, então podemos reescrever o exemplo anterior usando uma função, ao invés de uma classe, assim:

def entryExit(f):
def new_f():
print "Entering", f.__name__
f()
print "Exited", f.__name__
return new_f
 
@entryExit
def func1():
print "inside func1()"
 
@entryExit
def func2():
print "inside func2()"
 
func1()
func2()
print func1.__name__

A new_f() é definida dentro do corpo de entryExit(), então ela é criada e retornada quando a entryExit() é chamada. Note que new_f() é um encerramento, porque ela captura o valor real de f.

Uma vez que a new_f() tenha sido definida, ela é retornada a partir de entryExit(), de modo que o mecanismo do decorator possa determinar o resultado como uma função decoradora.

O output da linha print func1.__name__ é new_f, porque a função new_f foi substituída pela função original durante a decoração. Se isso for um problema, você pode mudar o nome da função antes de retorná-la:

def entryExit(f):
def new_f():
print "Entering", f.__name__
f()
print "Exited", f.__name__
new_f.__name__ = f.__name__
return new_f

A informação que você consegue obter dinamicamente sobre as funções, e as modificações que você consegue fazer nelas são bastante poderosas no Python.

Mais exemplos

Agora que você sabe o básico, você pode dar uma olhada em mais exemplos de decorators aqui. Observe o número de exemplos que usam classes, ao invés de funções como decorators.

Neste artigo eu intencionalmente evitei lidar com os argumentos da função decoradora, mas farei isso em um próximo. Arguardem!

Threads em Python

Fonte: IMasters

artigo publicado originalmente no developerWorks Brasil, por Breno Leitão

Breno Leitão é engenheiro de software pela IBM onde atua como kernel hacker.


Python é uma linguagem bem genérica e fácil de ser utilizada. Qualquer usuário pode aprender a programar em Python de uma maneira bem fácil, principalmente porque a linguagem encapsula conceitos difíceis em implementações fáceis.

Neste artigo vamos tratar da utilização de threads em Python. Threads são fluxos de programas que executam em paralelo dentro de uma aplicação, isto é, uma ramificação de uma parte da aplicação que é executada de forma independente e escalonada independentemente do fluxo inicial da aplicação.

Imaginemos, por exemplo, uma aplicação que mede, de tempos em tempos, a condição de determinados sensores. Supondo que cada sensor precisa ser medido com uma frequência diferente, isto é, um a cada 30 segundos, outro a cada 45 segundos e, por fim, um terceiro a cada 75 segundos.

Implementar isto de maneira sequencial é trabalhoso. Um jeito fácil, porém, é a implementação de uma thread independente para a leitura em cada um dos sensores. Desta forma a thread espera o tempo determinado para a leitura do sensor a que ela está ligada, sem se preocupar, ou mesmo saber, sobre os outros sensores.

Assim, neste caso, bastaria fazer uma classe por tipo de sensor, sendo que cada classe seria uma thread. Para transformar uma classe em thread, são necessárias duas modificações na classe:

  • A classe em questão estender à classe Thread do pacote threading
  • Implementar o método run(), que será chamado quando a thread iniciar

Em Python, o pacote que providencia as funcionalidades de thread é chamado threading, e deve ser importado no começo do seu programa: from threading import Thread.

Segue um exemplo básico, de uma classe chamada Th que implementa Thread e o método run(). O conteúdo do método run será executado em uma thread separada sempre que o método start, definido na classe Thread e herdado pela classe Th no nosso exemplo, for chamado:

from threading import Thread

class Th(Thread):

def __init__ (self, num):
Thread.__init__(self)
self.num = num

def run(self):

print "Hello "
print self.num

a = Th(1)
a.start()

Apesar de, no exemplo acima, o conteúdo do método run ser executado em uma thread separada, não é possível comprovar isto apenas pela saída do programa.

Afim de comprovarmos que cada thread é executada de forma independente e escalonada independentemente do fluxo inicial da aplicação, vamos analisar o próximo exemplo. Nele criamos várias threads simples Th, como as do exemplo acima, porém ao invés de simplesmente imprimirmos uma mensagem na thread ela vai executar um número definido de vezes COUNTDOWN antes de finalizar sua execução:

from threading import Thread
import sys

COUNTDOWN = 5

class Th(Thread):

def __init__ (self, num):
sys.stdout.write("Making thread number " + str(num) + "n")
sys.stdout.flush()
Thread.__init__(self)
self.num = num
self.countdown = COUNTDOWN

def run(self):

while (self.countdown):
sys.stdout.write("Thread " + str(self.num) +
" (" + str(self.countdown) + ")n")
sys.stdout.flush()
self.countdown -= 1

for thread_number in range (5):

                    thread = Th(thread_number)
                    thread.start()


Uma das possíveis saídas para o programa acima é a seguinte:

Making thread number 0
Thread 0 (5)
Thread 0 (4)
Thread 0 (3)
Thread 0 (2)
Thread 0 (1)
Making thread number 1
Thread 1 (5)
Making thread number 2
Making thread number 3
Thread 2 (5)
Thread 1 (4)
Thread 1 (3)
Thread 2 (4)
Thread 1 (2)
Thread 2 (3)
Thread 1 (1)
Thread 2 (2)
Making thread number 4
Thread 2 (1)
Thread 3 (5)
Thread 4 (5)
Thread 4 (4)
Thread 3 (4)
Thread 4 (3)
Thread 3 (3)
Thread 4 (2)
Thread 3 (2)
Thread 4 (1)
Thread 3 (1)

Caso você rode o programa acima, a saída não necessariamente será igual a esta, já que a alocação das threads para execução no processador não é um processo determinado. Mesmo rodando múltiplas vezes, o mesmo programa em um mesmo computador as saídas irão variar de uma execução para outra.

Um ponto interessante de se notar no exemplo acima é que, em vez de usarmos print para imprimir na saída padrão, utilizamos sys.stdout.write seguido de uma chamada a sys.stdout.flush.

Isto foi feito para garantir que as mensagems fossem impressas em ordem, já que chamadas a print por diversas threads simultaneamente não garantem a ordem de impressão dos caracteres.

Sincronização de threads

Nos exemplos citados anteriormente, usou-se threads para efetuar processamento paralelos distintos e sem ligação entre si. No entanto, no mundo real muitas vezes as diversas linhas de execução representada pelas threads de um programa precisam, eventualmente, comunicar-se entre si.

Uma forma simples de comunicação é aquela que precisa ocorrer no final do processamento das threads. Exemplos típicos deste tipo de necessidade são programas que processam dados em vetores ou matrizes.

Se estes vetores ou matrizes forem muito grandes e os cálculos efetuados em cada elemento relativamente demorados e independentes até certo ponto, a utilização de threads pode acelerar bastante este tipo de cálculo, já que o trabalho é de alguma forma dividido entre as diversas threads.

Ao final do processo, basta realizarmos um cálculo mais simples que agrega os sub-totais calculados pelas threads. Este tipo de sincronização no final da execução de uma thread pode ser feito através do método join da classe Thread.

Por exemplo, imaginemos um programa que soma os valores de um vetor de inteiros com 1000 elementos cujos valores variam de 0 a 100. Para fins deste exemplo, este vetor será criado com valores randômicos.

Serão criadas quatro threads que calcularão a soma de 250 elementos cada uma. Ao fim do processamento, os sub-totais gerados pelas quatro threads serão somados para gerar um único valor total referente à soma de todos os elementos do vetor.

from threading import Thread
import random
import sys

NUM_VALUES = 1000
values = []
sequential_total = 0
threaded_total = 0
threads = []
NUM_THREADS = 4

class Th(Thread):
subtotal = 0

def __init__ (self, num):
sys.stdout.write("Making thread number " + str(num) + "n")
sys.stdout.flush()
Thread.__init__(self)
self.num = num

def run(self):

range_start = self.num * NUM_VALUES / NUM_THREADS
range_end = ((self.num + 1) * NUM_VALUES / NUM_THREADS) - 1

for i in range(range_start, range_end):
self.subtotal += values[i]
sys.stdout.write("Subtotal for thread " + str(self.num) +
": " + str(self.subtotal)
+ " (from " + str(range_start)

+ " to " + str(range_end) + ")n");

sys.stdout.flush()

def get_subtotal(self):
return self.subtotal

#### O programa comeca aqui #####

for i in range(NUM_VALUES):
values.append(random.randint(0,100))

for i in range(NUM_VALUES):
sequential_total += values[i]

print("Sequential total: " + str(sequential_total))

for thread_number in range(NUM_THREADS):
threads.insert(thread_number, Th(thread_number))
threads[thread_number].start()

for thread_number in range(NUM_THREADS):
threads[thread_number].join()
threaded_total += threads[thread_number].get_subtotal()

print("Threaded total: " + str(threaded_total))

Um exemplo de saída para o programa acima seria o seguinte:

Sequential total: 49313
Making thread number 0
Making thread number 1
Subtotal for thread 0: 12365 (from 0 to 249)
Making thread number 2
Subtotal for thread 1: 12568 (from 250 to 499)
Making thread number 3
Subtotal for thread 2: 11742 (from 500 to 749)
Subtotal for thread 3: 12638 (from 750 to 999)
Threaded total: 4931

Note que o valor total calculado pela versão sequencial da soma dos elementos do vetor é igual à soma calculada através das quatro threads criadas no programa para fazer o mesmo trabalho de forma dividida.

Uma outra forma de sincronização pode ser necessária quando há necessidade de se acessar variáveis cujos valores são compartilhados por várias threads rodando simultaneamente. Para isso, é necessário lançar mão da utilização de locks (threading.Lock) ou semáforos (threading.Semaphore). Um artigo a parte descreverá os locks e semáforos, é só aguardar pelo próximo post.

Conclusão

Este artigo fez uma introdução a programação com Thread em python, mostrando o que é uma thread, com deve ser construida classes que tornam-se thread e como sincronizar o fim das threads.

Recursos

Django 1.4 é disponibilizado

Fonte: IMasters


Após meses de trabalho, o Django 1.4 foi liberado. O anúncio foi feito no blog do framework pelo desenvolvedor James Bennet.

Segundo ele, a versão é a última oficial do Django com suporte para o Python 2.5. Quando o Django 1.5 for lançado, a versão mínima do Python requerida será a 2.6, embora será possível a utilização do Django 1.4, durante seu suporte de ciclo de segurança, caso alguém precise de suporte para o Python 2.5.

Detalhes e novidades sobre o Django 1.4 podem ser encontrados nas notas de lançamento, e ele pode ser baixado neste link.

Otimizando o Django Views com C++

Fonte: IMasters

Texto original disponível em: http://www.jeffknupp.com/blog/2012/02/15/optimizing-django-views-with-c-plus-plus/


No meu artigo anterior, esbocei o método que vai sobre o perfil de um aplicativo Django. Utilizei uma view do linkrdr como um exemplo. Ela é responsável por agregar, classificar e ordenar todos os links de feeds de um usuário (RSS, Atom, Twitter, etc). O código a partir do envio da mensagem foi uma implementação simplista e inicial do panorama. Tenho, no entanto, um algoritmo de pontuação muito mais robusto, escrito em Python, que eu planejava utilizar no site.

Você pode ter percebido a palavra “planejado” ali, né? Pois é, o algoritmo se revelou muito lento. Mais do que eu consideraria aceitável. Depois de pensar em várias mudanças arquitetônicas que poderiam ser feitas para resolver o problema, cheguei em uma solução um tanto radical para um desenvolvedor Django: eu implementei a visão em C++.

Sei que nem todo desenvolvedor Django sabe C++ – e não precisa -, mas aqueles que sabem precisam perceber que é uma ferramenta viável quando Python está muito lento. Mas, eventualmente, você pode chegar a um ponto onde não é possível realmente otimizar o seu código Python mais. Neste caso, o perfil mostra que a maioria de seu tempo é gasto em chamadas de bibliotecas Python. Depois de bater nesse ponto, ou você escreve um algoritmo ineficiente ou você tem um problema não adequado para Python.

Quando percebi que tinha atingido esse ponto com o meu código de visão, entrei em pânico. “O que mais há para fazer?”, me perguntava. Então me lembrei de um projeto de trabalho onde havia escrito alguns códigos C++ que fazem interface com o Python. De uma perspectiva técnica, não havia nada me impedindo de implementar alguns aspectos do meu app Django em C++ (além do fato de que ele é torturante para escrever quando se trata do Python). Uma vez que linkrdr é um projeto de uma só pessoa, não existem companheiros que precisam aprender o código. Sendo assim, eu sou livre para implementá-lo como eu desejar.

Configurando

Tendo escrito um código “puro” C++/Python de interoperabilidade Python antes, e não querendo ver Py_XDecRef novamente, decidi usar boost::Python. Para começar, eu me certifiquei de que tinha as bibliotecas mais recentes do Boost e uma versão atualizada de gcc para que eu pudesse usar as características C++ 11, que são de fato muito boas. Depois de construir a versão mais recente da biclioteca boost::python, eu realemnte aprendi a lidar com isso. E ela acabou sendo extremamente fácil.

O boost::python envolve uma série de tipos de dados em Python para você: “object” representa um objeto Python genérico, “lista” é uma lista, e assim por diante. Como o Python é tipado dinamicamente, não há realmente muitos lugares inteiramente dele. “Tudo é um objeto” significa que tudo é um boost::python::object e pode ser acessado desta forma.

Além de wrappers primitivo, o boost fornece um mecanismo claro e conciso para fazer classes e funções C++ visíveis para Python. Eu tinha uma classe simples no código de entrada do nome anterior do meu LinkScore. Era basicamente uma estrutura C com uma lista de objetos e um interger. O código C++ é:

using namespace boost::python;

class LinkScore
{
public:
LinkScore() {}
LinkScore(const object& link, int score) : score_(score)
{
links_.append(link);
}
list links_;
int score_;
};

Se você está pensando que meus data members deveriam ser privados, adivinhem: eu não me importo. Essa é alegria de trabalhar em código que só você vai usar. Você pede escrevê-lo e usá-lo como quiser.

Os detalhes

Enfim, o código com o qual o boost:python pode chamar o Python é:

class_<LinkScore>("LinkScore", init<object, int>())
.def_readwrite("links", &LinkScore::links_)
.def_readwrite("score", &LinkScore::score_);

Realmente, não poderia ser mais simples. A maneira de conseguir isso <Python.h> envolve a definição de uma estrutura com quarenta valores para declarar cada classe. Fiquei feliz em não ter que me preocupar com isso.

O atual código para a minha view é uma função gratuita chamada get_scores. Aqui está um breve trecho:

using namespace boost::python;
using namspace std;

class CompareObject {
public:
bool  operator()(const LinkScore& l, const LinkScore& r) { return l.score_ > r.score_; }
};

list get_scores(object links)
{
object utility = import("links.utility");
set<LinkScore, CompareObject> seen_links;
list python_seen_links;
for (int i = 0; i < len(links); ++i)
{
const object& link = links[i];
LinkScore score = LinkScore(link, score_link (link, links));
auto iter = seen_links.find(score);

if (iter != seen_links.end())
{
// Do stuff
}
else
{
// Do other stuff
}
}
// TODO: Optimize this
for (auto i = seen_links.begin(); i != seen_links.end(); ++i)
{
python_seen_links.append(*i);
}
return python_seen_links;

Se você conhece C++ e Python, é quase como ler um mix dos dois. A descrição acima, no entanto, é válida para o código C++ e é a interface que o Python usa para chamar minha biblioteca de pontuação. Para expor essa função para o Python, tudo que é necessário é def (“get_score”, get_score); dentro de um bloco BOOST_PYTHON_MODULE, que nomeia o módulo a ser importado.

Quando terminei de escrever o código C++, eu o compilei usando o gcc com a ferramenta de biuld bjam da biblicota boots; defini o meu LD_LIBRARY_PATH para captar o libboost_Python.so e liguei uma shell do manage.py (na verdade, um “shell_plus”). Usei o módulo cProfile para comparar a versão do C++ da view com a versão do Python da view. Os resultados foram satisfatórios: um aumento de oito vezes na velocidade com a versão C++.

Para acionar o código C++, eu só precisava ter certeza que o .so gerado estiva em minha PYTHON_PATH. Assim, poderia importá-lo como uma biblioteca normal do Python. Acrescentei-o ao meu views.py e meus testes unitários rodaram. Depois disso, comitei tudo e coloquei o novo código através dos seus passos no servidor de desenvolvimento web. O tempo de resposta melhorou visivelmente, com a view funcionando instantaneamente.

Wrap Up

Sei que esta não é uma opção de otimização disponível para todos, mas é uma opção interessante. O Python é uma linguagem fantástica e o Django é um framework muito bom. No geral, estou bastante contente com os resultados e como foi fácil de implementar. Me absterei de escrever mais código C++ para linkrdr, a menos que seja absolutamente necessário. É bom saber, no entanto, que a opção está lá.

Django divulga planos para migrar para Python 3

Fonte: IMasters

Com informações de The H

Os desenvolvedores do Django publicaram planos sobre como eles migrarão seu framework baseado em Python para o Python 3. Vários usuários apontaram a falta de suporte para o Python 3 no Django como a razão para não migrarem para a nova versão da linguagem. Trabalhando com a equipe do Python, eles optaram por uma migração organizada, usando o Python 2.6 como ponto de partida.

Primeiramente, os desenvolvedores pretendem diminuir o uso de versões antigas 2.x do Python, até que a versão mínima do Python pelo Django seja a 2.6. Essa versão é a base da transição, já que foi desenvolvida para ser uma ponte para o Python 3, uma vez que muitas funcionalidades do mais novo Python foram portadas novamente para ela, que inclui ferramentas para dar suporte para a migração de código para o Python 3.

O ainda não lançado Django 1.4 não terá mais suporte para Python 2.4, e o Django 1.5, por sua vez, deixará de suportar o Python 2.5 mais para frente. Além disso, o Django 1.5 vai adicionar suporte experimental para o Python 3.x, principalmente a versão 3.3. Logo, o Django 1.5 será o início do processo de portar o código base do Django para o Python 3.

Detalhes sobre essa transição ainda não estão disponíveis, mas, segundo os desenvolvedores do Django, o Python 3 é o futuro da linguagem Python e, em apoio a isso, o Django continuará comprometido em alcançar a compatibilidade com o Python.

Alfa do Python 3.3.0 traz primeiras mudanças sintáticas em dois anos

Fonte: IMasters

Com informações de The H

A versão 3.3.0 da linguagem de programação Python entrou na fase de testes com a liberação do seu primeiro alfa. Ela marca o fim de dois anos sem mudanças na sintática na linguagem. Propostas por Guido van Rossum como Python Enhancement Proposal (PEP) 3003, as mudanças foram feitas para habilitar implementações não-CPython da linguagem para atualizar a implementação do core depois do lançamento do Pyhton 3.0.

Com as mudanças na sintaxe permitidas novamente, o alfa inclui uma nova maneira de habilitar generators a delegar trabalho para sub-generators, o que abre novas possibilidades para otimizar iterações no código do Python. Outra mudança na sintaxe adiciona o atributo __qualname__ a funções e classes. Isso possibilita dizer se o objeto está no topo da hierarquia ou se ele é aninhado dentro de outro objeto.

O PEP 393 faz uma representação de string mais flexível ao mudar o tipo de string Unicode para permitir várias representações internas ao mesmo tempo. Com isso, os programadores podem otimizar espaço ou maximizar a disponibilidade de caracteres e abandonar a distinção entre builds estreitos e amplos do Unicode.

Além disso, a sintaxe lateral do Unicode a partir do Python 2 foi reintegrada ao Python 3.3.0 para tornar a migração dos aplicativos do Pyhton 2 mais fácil. Outras mudanças na nova versão incluem melhorias em lidar com exceção, um novo módulo de “empacotamento” e suporte para compressão LZMA/XZ.

Mais detalhes sobre as modificações podem ser encontrados nas notas de lançamento e neste link. O Python 3.3.0 alfa 1 está disponível para download para Windows e Mac OS X.

Como Trabalhar com Threads em Python

Fonte: Rafael Cirolini/NerdHead

Precisei criar um programa (futuramente vou colocar ele aqui) que precisava testar 290 links de uma pagina para saber se eles estavam ok. O teste era simples, tentar conectar e esperar um 200 OK da resposta do servidor para verificar se não havia problema.

O problema consistia que o teste deveria ser razoavelmente rápido, e fazendo os testes de forma sequenciais demorava em torno de 16 minutos, o que não era aceitável. Uma solução foi a criação de threads para paralelizar o trabalho. Foi difícil achar alguma documentação que explique de forma simples o que eu precisava fazer, que era disparar o maior numero de processos simultâneos, aguardar eles terminarem e fazer diversas verificações.

Bom, aqui pretendo demonstrar de maneira bem simples como criar uma fila (queue), e criar threads para consumi-la.

#imports necessários
import random
from time import sleep
from Queue import *
from threading import Thread, Lock
 
#função para consumir a fila
def consumir():
    job = queue.get() #pega o primeiro job livre
    sleep(random.randint(1,3)) #espera
    print "Estou consumindo o job: %s"%(job)
    queue.task_done() #finaliza o job
 
#gera a fila e coloca todos os links na fila
queue = Queue()
 
jobs = 0
while jobs < 10:
    print "Colocando o job %s na fila"%(jobs)
    queue.put(jobs)
    jobs = jobs + 1
 
print "A fila tem %s jobs"%(queue.qsize())
 
#enquanto tiver fila cria uma tread
i = 0
while i < queue.qsize():
    th = Thread(target=consumir)
    th.setDaemon(True)
    th.start()
 
#espera a fila ser consumida para saber se esta com algum erro
queue.join()
print "Finalizou"

A saída deve ser algo mais ou menos assim:

Colocando o job 0 na fila

Colocando o job 1 na fila

Colocando o job 2 na fila

Colocando o job 3 na fila

Colocando o job 4 na fila

Colocando o job 5 na fila

Colocando o job 6 na fila

Colocando o job 7 na fila

Colocando o job 8 na fila

Colocando o job 9 na fila

A fila tem 10 jobs

Estou consumindo o job: 9

Estou consumindo o job: 1

Estou consumindo o job: 4

Estou consumindo o job: 6

Estou consumindo o job: 0

Estou consumindo o job: 2

Estou consumindo o job: 3

Estou consumindo o job: 5

Estou consumindo o job: 7

Estou consumindo o job: 8

Finalizou

Usei o random e o sleep somente para mostrar que os jobs são consumidos de maneira assíncrona e que não esperam um pelo outro para serem consumidos.

Web Service em Python

Fonte: Rafael Cirolini/NerdHead

Tive uma necessidade estes dias de criar um webservice em um servidor linux que retornasse os logs de emails do postfix, fazendo um grep (find) pelo usuário, tipo de protocolo e data.

Pesquisei um pouco, e achei uma solução muito boa, fazer o desenvolvimento do webservice em Python, o que é muito simples e de muito rápida execução.

O servidor que eu estava trabalhando usa CentOS e vinha com as bibliotecas padrões do python instalado, caso o seu sistema não venha, um apt-get install python ou um yum install python deve resolver o problema. Mas eu ainda precisava de mais duas bibliotecas que não vinham com a minha distro: fpconst e SOAPpy. Procurei as duas aqui: http://rpm.pbone.net/, achei a que se enquadrava para o meu sistema operacional i586.

Segue as versões de como eu usei:

mkdir /home/pacotes
cd /home/pacotes/
wget http://pypi.python.org/packages/source/f/fpconst/fpconst-0.7.2.tar.gz#md5=10ba9e04129af23108d24c22c3a698b1
wget http://downloads.sourceforge.net/project/pywebsvcs/SOAP.py/0.12.0_rc1/SOAPpy-0.12.0.tar.gz?use_mirror=ufpr
tar -cvf fpconst-0.7.2.tar.gz
tar -cvf SOAPpy-0.12.0.tar.gz
cd fpconst-0.7.2
python setup.py install
cd ../home/SOAPpy-0.12.0
python setup.py install

Pronto, minhas duas bibliotecas já estavam funcionando.

Agora vamos ao webservice:

#!/usr/bin/python
#import das bibliotecas necessarias
from SOAPpy import SOAPServer
import os
import commands
 
#caminho dos arquivos de logs
caminho = '/root/cirolini/'
 
#identifica se o protocolo for pop ou imap e direciona para a pasta solicitada
def protocolo(protocolo):
        if protocolo == 'popper':
                return 'popper/popper.log'
        if protocolo == 'imap':
                return 'imap/imap.log'
 
#literalmente da um grep nos logs que estao no formato popper.log.2010-03-16T08:00-03:00
def buscaLogs(usuario, proto, data):
        proto = protocolo(proto)
        busca = "zgrep " + usuario + " " + proto + "." + data +"*"
        var = commands.getoutput(busca)
        return var
 
#instancia o webservice para rodar na porta 8081 e responder para pesquisas como localhost
server = SOAPServer(('localhost',8081))
#registra a funcao que vamos chamar no nosso cliente
server.registerFunction(buscaLogs,'ns-buscalogs','buscaLogs')
#indica para o webservice nao parar de executar
server.serve_forever()

Acredito que já deixei tudo bem comentado de como funciona.

E segue o nosso cliente:

#!/usr/bin/python
#importa a biblioteca para fazer o webservice via SOAP
from SOAPpy import SOAPProxy
 
#parametro do webservice para ele saber a porta e o namespace (funcao) que vamos chamar
url = 'http://localhost:8081'
namespace = 'ns-buscalogs'
 
#conecta no webservice
server = SOAPProxy(url,namespace)
#isto para dar um dump das informacoes de entrada e saida
server.config.dumpSOAPOut = 1
server.config.dumpSOAPIn = 1
 
#escreve na tela o retorno da funcao do webservice buscaLogs
print server.buscaLogs('rafael','popper', '2010-03-16')

Os retornos ficaram mais ou menos desta forma:

[root@dsv cirolini]$ python cliente.py
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:buscaLogs xmlns:ns1="ns-buscalogs" SOAP-ENC:root="1">
<v1 xsi:type="xsd:string">rafael</v1>
<v2 xsi:type="xsd:string">popper</v2>
<v3 xsi:type="xsd:string">2010-03-16</v3>
</ns1:buscaLogs>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
*** Incoming SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<buscaLogsResponse SOAP-ENC:root="1">
<Result xsi:type="xsd:string">Mar 16 08:46:19: end session - user rafael from 127.0.0.1: time=1 inbox=0/0 quit=1/4/138 stat=1/19/9 auth=1/150099/111 </Result>
</buscaLogsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
Mar 16 08:46:19: end session - user rafael from 127.0.0.1: time=1 inbox=0/0 quit=1/4/138 stat=1/19/9 auth=1/150099/111

Threads em Python

Python é uma linguagem bem genérica e fácil de ser utilizada. Qualquer usuário pode aprender a programar em Python de uma maneira bem fácil, principalmente porque a linguagem encapsula conceitos difíceis em implementações fáceis.

Neste artigo vamos tratar da utilização de threads em Python. Threads são fluxos de programas que executam em paralelo dentro de uma aplicação, isto é, uma ramificação de uma parte da aplicação que é executada de forma independente e escalonada independentemente do fluxo inicial da aplicação.

Imaginemos, por exemplo, uma aplicação que mede, de tempos em tempos, a condição de determinados sensores. Supondo que cada sensor precisa ser medido com uma frequência diferente, isto é, um a cada 30 segundos, outro a cada 45 segundos e, por fim, um terceiro a cada 75 segundos.

Implementar isto de maneira sequencial é trabalhoso. Um jeito fácil, porém, é a implementação de uma thread independente para a leitura em cada um dos sensores. Desta forma a thread espera o tempo determinado para a leitura do sensor a que ela está ligada, sem se preocupar, ou mesmo saber, sobre os outros sensores.

Assim, neste caso, bastaria fazer uma classe por tipo de sensor, sendo que cada classe seria uma thread. Para transformar uma classe em thread, são necessárias duas modificações na classe:

  • A classe em questão estender à classe Thread do pacote threading
  • Implementar o método run(), que será chamado quando a thread iniciar

Em Python, o pacote que providencia as funcionalidades de thread é chamado threading, e deve ser importado no começo do seu programa: from threading import Thread.

Segue um exemplo básico, de uma classe chamada Th que implementa Thread e o método run(). O conteúdo do método run será executado em uma thread separada sempre que o método start, definido na classe Thread e herdado pela classe Th no nosso exemplo, for chamado:

from threading import Thread
 
class Th(Thread):
 
def __init__ (self, num):
Thread.__init__(self)
self.num = num
 
def run(self):
 
print "Hello "
print self.num
 
 
a = Th(1)
a.start()
 

Apesar de, no exemplo acima, o conteúdo do método run ser executado em uma thread separada, não é possível comprovar isto apenas pela saída do programa.

Afim de comprovarmos que cada thread é executada de forma independente e escalonada independentemente do fluxo inicial da aplicação, vamos analisar o próximo exemplo. Nele criamos várias threads simples Th, como as do exemplo acima, porém ao invés de simplesmente imprimirmos uma mensagem na thread ela vai executar um número definido de vezes COUNTDOWN antes de finalizar sua execução:

from threading import Thread
import sys
 
COUNTDOWN = 5
 
class Th(Thread):
 
def __init__ (self, num):
sys.stdout.write("Making thread number " + str(num) + "n")
sys.stdout.flush()
Thread.__init__(self)
self.num = num
self.countdown = COUNTDOWN
 
def run(self):
 
while (self.countdown):
sys.stdout.write("Thread " + str(self.num) +
" (" + str(self.countdown) + ")n")
sys.stdout.flush()
self.countdown -= 1
 
 
for thread_number in range (5):
thread = Th(thread_number)
thread.start()

Uma das possíveis saídas para o programa acima é a seguinte:

Making thread number 0
Thread 0 (5)
Thread 0 (4)
Thread 0 (3)
Thread 0 (2)
Thread 0 (1)
Making thread number 1
Thread 1 (5)
Making thread number 2
Making thread number 3
Thread 2 (5)
Thread 1 (4)
Thread 1 (3)
Thread 2 (4)
Thread 1 (2)
Thread 2 (3)
Thread 1 (1)
Thread 2 (2)
Making thread number 4
Thread 2 (1)
Thread 3 (5)
Thread 4 (5)
Thread 4 (4)
Thread 3 (4)
Thread 4 (3)
Thread 3 (3)
Thread 4 (2)
Thread 3 (2)
Thread 4 (1)
Thread 3 (1)
 

Caso você rode o programa acima, a saída não necessariamente será igual a esta, já que a alocação das threads para execução no processador não é um processo determinado. Mesmo rodando múltiplas vezes, o mesmo programa em um mesmo computador as saídas irão variar de uma execução para outra.

Um ponto interessante de se notar no exemplo acima é que, em vez de usarmos print para imprimir na saída padrão, utilizamos sys.stdout.write seguido de uma chamada a sys.stdout.flush.

Isto foi feito para garantir que as mensagems fossem impressas em ordem, já que chamadas a print por diversas threads simultaneamente não garantem a ordem de impressão dos caracteres.

Sincronização de threads

Nos exemplos citados anteriormente, usou-se threads para efetuar processamento paralelos distintos e sem ligação entre si. No entanto, no mundo real muitas vezes as diversas linhas de execução representada pelas threads de um programa precisam, eventualmente, comunicar-se entre si.

Uma forma simples de comunicação é aquela que precisa ocorrer no final do processamento das threads. Exemplos típicos deste tipo de necessidade são programas que processam dados em vetores ou matrizes.

Se estes vetores ou matrizes forem muito grandes e os cálculos efetuados em cada elemento relativamente demorados e independentes até certo ponto, a utilização de threads pode acelerar bastante este tipo de cálculo, já que o trabalho é de alguma forma dividido entre as diversas threads.

Ao final do processo, basta realizarmos um cálculo mais simples que agrega os sub-totais calculados pelas threads. Este tipo de sincronização no final da execução de uma thread pode ser feito através do método join da classe Thread.

Por exemplo, imaginemos um programa que soma os valores de um vetor de inteiros com 1000 elementos cujos valores variam de 0 a 100. Para fins deste exemplo, este vetor será criado com valores randômicos.

Serão criadas quatro threads que calcularão a soma de 250 elementos cada uma. Ao fim do processamento, os sub-totais gerados pelas quatro threads serão somados para gerar um único valor total referente à soma de todos os elementos do vetor.

from threading import Thread
import random
import sys
 
NUM_VALUES = 1000
values = []
sequential_total = 0
threaded_total = 0
threads = []
NUM_THREADS = 4
 
class Th(Thread):
subtotal = 0
 
def __init__ (self, num):
sys.stdout.write("Making thread number " + str(num) + "n")
sys.stdout.flush()
Thread.__init__(self)
self.num = num
 
def run(self):
 
range_start = self.num * NUM_VALUES / NUM_THREADS
range_end = ((self.num + 1) * NUM_VALUES / NUM_THREADS) - 1
 
for i in range(range_start, range_end):
self.subtotal += values[i]
sys.stdout.write("Subtotal for thread " + str(self.num) +
": " + str(self.subtotal)
+ " (from " + str(range_start)
 
+ " to " + str(range_end) + ")n");
 
sys.stdout.flush()
 
def get_subtotal(self):
return self.subtotal
 
#### O programa comeca aqui #####
 
for i in range(NUM_VALUES):
values.append(random.randint(0,100))
 
for i in range(NUM_VALUES):
sequential_total += values[i]
 
print("Sequential total: " + str(sequential_total))
 
for thread_number in range(NUM_THREADS):
threads.insert(thread_number, Th(thread_number))
threads[thread_number].start()
 
for thread_number in range(NUM_THREADS):
threads[thread_number].join()
threaded_total += threads[thread_number].get_subtotal()
 
print("Threaded total: " + str(threaded_total))

Um exemplo de saída para o programa acima seria o seguinte:

Sequential total: 49313
Making thread number 0
Making thread number 1
Subtotal for thread 0: 12365 (from 0 to 249)
Making thread number 2
Subtotal for thread 1: 12568 (from 250 to 499)
Making thread number 3
Subtotal for thread 2: 11742 (from 500 to 749)
Subtotal for thread 3: 12638 (from 750 to 999)
Threaded total: 4931

Note que o valor total calculado pela versão sequencial da soma dos elementos do vetor é igual à soma calculada através das quatro threads criadas no programa para fazer o mesmo trabalho de forma dividida.

Uma outra forma de sincronização pode ser necessária quando há necessidade de se acessar variáveis cujos valores são compartilhados por várias threads rodando simultaneamente. Para isso, é necessário lançar mão da utilização de locks (threading.Lock) ou semáforos (threading.Semaphore). Um artigo a parte descreverá os locks e semáforos, é só aguardar pelo próximo post.

Conclusão

Este artigo fez uma introdução a programação com Thread em python, mostrando o que é uma thread, com deve ser construida classes que tornam-se thread e como sincronizar o fim das threads.

Recursos

artigo publicado originalmente no developerWorks Brasil, por Breno Leitão

Fonte: IMasters

Um guia para pacotes Python

O principal para um projeto de software livre de sucesso é o pacote. Um ingrediente chave para um bom pacote é a versão. Como o projeto é de software livre, o ideal é publicar o pacote para aproveitar os muitos benefícios que a comunidade de software livre oferece.

Diferentes plataformas e linguagens têm mecanismos diversos para pacotes, mas este artigo se concentra especificamente em Python e seu ecossistema de pacotes. O artigo discute mecânica de pacotes para oferecer uma base e fornece exemplos práticos suficientes para que o leitor comece imediatamente.

Por que se preocupar com pacotes?

Além de ser a coisa certa a se fazer, há três motivos práticos para empacotar software:

  • Facilidade de uso
  • Estabilidade (com versões)
  • Distribuição

Tornar a instalação do aplicativo o mais simples possível é uma questão de consideração para com os usuários. Pacotes tornam o software mais acessível e mais fácil de instalar. Se for mais fácil de instalar, será mais fácil para que usuários comecem a usar o software.

Ao publicar um pacote no Python Package Index (PyPI), ele poderá ser facilmente acessado por meio de utilitários como pip oueasy_install.

Além disso, ao criar versões de pacotes, o desenvolvedor permite que os usuários “fixem” a dependência que seus projetos têm em relação ao software a uma versão em particular. Por exemplo, fixar Pinax para a versão 0.9a2.dev1017 seria expresso como:

Pinax==0.9a2.dev1017

Isso forçaria o projeto a usar o release 0.9a2.dev1017 do Pinax.

Versões garantem maior estabilidade caso sejam lançadas alterações de releases para seu software mais tarde que possam ter quebra de interfaces. Permitem aos usuários saber exatamente o que estão obtendo e facilitam para eles acompanhar as diferenças em releases.

Além disso, os desenvolvedores de projeto podem saber exatamente para o que estão criando código.

Um método comum para publicar pacotes no PyPI (ou em um servidor de distribuição próprio) é criar uma distribuição de origem para upload. Uma distribuição de origem é uma maneira padrão de empacotar a origem de seu projeto como uma unidade distribuível.

Há maneiras de criar distribuições binárias, mas, para o software livre, faz sentido também distribuir a origem.

Criar distribuições de origem facilita o uso de ferramentas que procuram o software na Internet, fazem download e instalam automaticamente. Esse processo ajuda não só no desenvolvimento local, mas também nas implementações do software.

Portanto, ao tornar mais fácil para usuários integrar e instalar o software, usar boas versões que permitem uma técnica confiável de fixação e publicar o pacote para distribuição mais ampla, você terá uma chance maior de que seu projeto tenha sucesso e obtenha aprovação ampla. Aprovação ampla pode levar a mais contribuidores — algo que certamente todo desenvolvedor de software livre deseja.

Anatomia de um arquivo setup.py

Um dos propósitos do script setup.py é servir como o executável que pode ser executado para empacotar o software e fazer upload para servidores de distribuição. O script setup.py pode variar bastante em conteúdo conforme você navega pelos repositórios Python populares. Este artigo se concentra no básico.

O arquivo setup.py pode ser usado para muitas tarefas diferentes, mas aqui você cria um que permitirá executar os seguintes comandos:

python setup.py register
python setup.py sdist upload

O primeiro comando, register, toma as informações fornecidas na função setup() no script setup.py e cria uma entrada no PyPI para seu pacote. Ele não faz upload; em vez disso, cria os metadados sobre o seu projeto, de modo que posteriormente seja possível fazer upload e hospedar os releases lá.

Os próximos dois comandos estão encadeados: sdist upload desenvolve uma distribuição de origem e faz upload dela para o PyPI. Mas há alguns pré-requisitos, como configurar seu próprio arquivo de configuração .pypirc e escrever efetivamente o conteúdo de setup.py.

Primeiro, configure o arquivo .pypirc. Ele deve estar em seu diretório inicial, que varia dependendo do sistema operacional. No UNIX®, Linux® e Mac OS X, chega-se lá digitando cd ~/. O conteúdo do arquivo deve conter suas credenciais PyPI, como mostrado abaixo:

[distutils]
index-servers =
pypi
 
[pypi]
username:xxxxxxxxxxxxx
password:xxxxxxxxxxxxx

Em seguida, acesse o PyPI e registre uma conta (não se preocupe, é grátis). Coloque o mesmo nome de usuário e senha criados no PyPI em seu arquivo .pypirc e nomeie o arquivo ~/.pypirc.

Agora, ao criar o script setup.py, é preciso decidir o que será exibido na página de índice do PyPI e qual será o nome do projeto. Comece copiando um modelo de setup.py que eu uso para projetos (consulte a listagem abaixo).

Ignorando as importações e funções, olhe para a parte inferior do modelo, para o que precisa ser mudado para se adequar ao seu projeto.

PACKAGE = ""
NAME = ""
DESCRIPTION = ""
AUTHOR = ""
AUTHOR_EMAIL = ""
URL = ""
VERSION = __import__(PACKAGE).__version__
 
setup(
name=NAME,
version=VERSION,
description=DESCRIPTION,
long_description=read("README.rst"),
author=AUTHOR,
author_email=AUTHOR_EMAIL,
license="BSD",
url=URL,
packages=find_packages(exclude=["tests.*", "tests"]),
package_data=find_package_data(
PACKAGE,
only_in_packages=False
),
classifiers=[
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Framework :: Django",
],
zip_safe=False,
)

Primeiro, observe que este modelo espera que o projeto tenha dois arquivos diferentes. O primeiro é usado para long_description: ele lê o conteúdo do arquivo README.rst que está no mesmo diretório que setup.py e passa o conteúdo como uma cadeia de caracteres para o parâmetro long_description.

Esse arquivo preenche a página de entrada no PyPI, portanto é bom descrever brevemente o projeto e mostrar exemplos de uso nesse arquivo. O segundo arquivo é __init__.py . Ele não é mencionado explicitamente aqui, mas a linha que define a variável VERSION importa o pacote; e quando isso acontece, Python precisa de um arquivo __init__.py e espera uma variável definida naquele módulo, chamada __version__.

Por enquanto, basta defini-la como uma cadeia de caractere:

# __init__.py
__version__ = "0.1"
 

Agora vamos ver as demais entradas:

Package é o pacote Python no projeto. É a pasta de nível superior que contém o módulo __init__.py que deve estar no mesmo diretório que o arquivo setup.py — por exemplo:

/-
|- README.rst
|- setup.py
|- dogs
|- __init__.py
|- catcher.py
 
Portanto,
 
dogs

seria o pacote aqui.

  • Name é geralmente o mesmo que Package ou semelhante, mas pode ser qualquer coisa. Name é como as pessoas chamarão o software, o nome pelo qual ele será listado no PyPI e — o mais importante — sob o qual os usuários irão instalá-lo (por exemplo, pip install NAME).
  • Description é apenas uma breve descrição do projeto. Uma frase é o bastante.
  • Author e Author_Email são o que parecem: o nome e endereço de e-mail do autor. Essas informações são opcionais, mas é uma boa prática fornecer um endereço de e-mail caso as pessoas queiram entrar em contato com você devido ao projeto.
  • URL é a URL do projeto. Essa URL pode ser o Web site do projeto, repositório Github ou qualquer URL que você queira. Novamente, essas informações são opcionais.

Pode ser útil também fornecer a licença e classificadores. Para mais informações sobre a criação de um arquivo setup.py, consulte a documentação do Python logo abaixo em Recursos.

Versão

Versões podem facilmente ser um tópico próprio, mas vale a pena mencioná-las no contexto de pacotes, pois um bom empacotamento envolve versões apropriadas. Versões são uma maneira de comunicar-se com o usuário: também permite que os usuários desenvolvam mais estabilidade e confiabilidade em seus aplicativos.

Com versões, o desenvolvedor diz aos usuários que ele mudou algo e dá limites explícitos para onde essas mudanças ocorreram.

Um padrão para versões em pacotes Python pode ser encontrado em Python Enhancement Proposal (PEP) 386. Essa proposta declara regras pragmáticas.

Mesmo que você não tenha lido e entendido a PEP, ou mesmo que não concorde com ela, seria sábio segui-la, pois mais e mais desenvolvedores Python estão acostumados a vê-la.

Além disso, versões não são apenas para releases estáveis transferidos por upload para PyPI, mas também são úteis para releases de desenvolvimento usando o sufixo devNN.

Geralmente não é bom fazer upload dessas versões de desenvolvedor para o PyPI, mas você ainda pode configurar seu próprio servidor de distribuição público (ou privado) para disponibilizá-las; dessa forma, usuários que queiram usar a versão mais recente podem citar isso em seu arquivo requirements.txt do pip. Aqui estão alguns exemplos de versões:

1.0.1        # 1.0.1 final release
1.0.2a       # 1.0.2 Alpha (for Alpha, after Dev releases)
1.0.2a.dev5  # 1.0.2 Alpha, Dev release #5

Publicação

As pessoas geralmente não irão localizar e instalar software que não tenha sido publicado. Na maioria das vezes, você deve publicar seus pacotes no PyPI.

Após configurar o arquivo de configuração .pypirc, o comando upload passado para setup.py transmite seu pacote para o PyPI. Geralmente isso é feito em conjunto com o desenvolvimento de uma distribuição de origem:

python setup.py sdist upload
 

Se você estiver usando seu próprio servidor de distribuição, inclua uma seção para autorização em seu arquivo .pypirc para esse novo local, e indique-o por nome ao fazer o upload:

python setup.py sdist upload -r mydist

Configurar seu próprio servidor de distribuição

A principal razão para usar um servidor de distribuição próprio em software livre é oferecer um lugar para publicar releases de desenvolvedor, pois o PyPI deve consistir apenas de releases estáveis. Por exemplo, você provavelmente quer que instale o release estável mais recente localizado no PyPI:

pip install MyPackage

No entanto, se posteriormente você instalar releases de desenvolvedor, esse comando acabará instalando o release mais recente, o que significa o de desenvolvedor.

É geralmente bom fixar um release, mas nem todos os usuários fazem isso. Portanto, garanta que o release estável mais recente seja sempre retornado se o usuário não especificar um número de versão.

Uma maneira de ter as vantagens tanto de um método (expor apenas releases estáveis para padrão do pip) como do outro (permitir que os usuários instalem pacotes de releases de desenvolvedor) é hospedar um servidor de distribuição próprio. O projeto Pinax faz isso para todos os seus releases de desenvolvedor.

O servidor de distribuição é apenas um índice, servido em Protocolo de Transporte de Hipertexto (HTTP), de arquivos no seu servidor. Deve ter a seguinte estrutura de arquivos:

 
/index-name/package-name/package-name-version.tar.gz

Dessa forma, é possível tornar o servidor privado configurando Basic-Auth no servidor da Web. É uma boa ideia incluir alguns recursos para upload de distribuições de origem também.

Para isso, é preciso incluir código para lidar com o upload, analisar o nome do arquivo e criar os caminhos de diretório para corresponder ao esquema acima. Essa estrutura existe para o projeto Pinax, que hospeda diversos repositórios.

pip e virtualenv

Embora este artigo tenha se concentrado primariamente na criação de pacotes, esta seção descreve o consumo de pacotes, oferecendo um pouco de apreciação para o que bons pacotes e versões fazem para os usuários.

pip é uma ferramenta que pode ser instalada diretamente, mas eu recomendo usá-la como parte de virtualenv. Recomendo usar virtualenv para tudo relacionado a Python, pois mantém os ambientes Python limpos.

Assim como uma máquina virtual permite executar diversos sistemas operacionais lado a lado, virtualenvs permitem executar diversos ambientes Python lado a lado. Eu não instalo nada no Python do meu sistema; em vez disso, crio um novo virtualenv para cada novo projeto ou utilitário em que trabalho.

Agora que você instalou virtualenv, pode brincar um pouco:

$ mkvirtualenv —no-site-packages testing
$ pip install Pinax
$ pip freeze|grep Pinax
$ pip uninstall Pinax
$ pip install —extra-index-url=http://dist.pinaxproject.com/fresh-start/
Pinax==0.9a2.dev1017
$ pip freeze|grep Pinax

Observe que a primeira instalação do pip foi transferida por download e instalada a partir do PyPI. pip freeze mostra todas as versões de pacotes instalados no virtualenv atual. pip uninstall faz exatamente o que você imagina: remove-se do virtualenv.

Em seguida, você instala uma versão de desenvolvedor do repositório novo para obter a versão de desenvolvimento do Pinax versão 0.9a2.dev1017.

Não é preciso ir para Web sites, fazer download de tarballs e criar links simbólicos para um pacote no site. (Era assim que eu costumava fazer, e causava muitos problemas.) Seus usuários obtêm tudo isso como resultado de bons pacotes, publicação e versões de seu projeto.

Conclusão

Em suma, vale muito a pena aprender a arte e ciência dos pacotes. Você obterá uma adoção maior dos usuários devido à facilidade de instalação e estabilidade que a divisão dos pacotes em versão oferece a eles.

Usando o modelo de setup.py fornecido abaixo em Recursos e discutido neste artigo, deve ser possível incluir pacotes em seu projeto rápido e facilmente. Comunicar-se com seus usuários por meio de versões apropriadas é uma questão de consideração com eles, pois facilita o rastreamento de mudanças entre releases.

Por fim, à medida que pip e virtualenv aumentam sua adoção, a confiança nos pacotes publicados — seja no PyPI ou em um servidor de distribuição próprio — aumenta. Portanto, não deixe de publicar os projetos que você quer compartilhar com o mundo.

Fonte: developerWorks Brasil/IMasters

Python volta a ganhar o premio de melhor linguagem de programação

O Python novamente ganhou o prêmio de melhor linguagem de programação oferecido pela Linux Journal, uma das revistas de referência dedicada a sistemas operacionais, e uma das mais populares entre os programadores amadores. E essa já é a terceira vez. O Python voltar a se impor ante seu mais ardente rival, o clássico C++, que ficou 6% atrás nas pesquisas.

Para aqueles que não estão familiarizados com o assunto, o Python é uma linguagem de programação de alto nível e muito jovem, já que sua primeira versão foi lançada há 20 anos em 1991. Sua vantagem sobre os demais é que é muito fácil de usar, com uma sintaxe que se caracteriza pela sua simplicidade e limpeza. Para se ter uma idéia, o clássico “Hello World”, exemplo comum em linguagens de programação para mostrar como se imprime uma linha na tela, você pode conseguir com esta simples sentença: print “Hello World”.

Fácil, não? Atualmente se encontra em sua versão 3.2 e já tem se consolidado o suficiente para influenciar outras línguas no mundo da programação, a qual tem crescido ainda mais.

Estas foram algumas das características que deram ao Python o posto de melhor linguagem de programação, mas destacamos principalmente, a facilidade com que se pode iniciá-lo e começar a trabalhar nele. Python é sinônimo de simplicidade e potência, duas palavras que devem ir juntas e que fazem com que algo esteja em mudança no mundo da linguagem de programação graças a linguagens como está.

Fonte: Auricelio Barbosa/forumpc