Planeta PythonBrasil

PythonBrasil[10]

June 29, 2015

Kodumaro

MoonScript

MoonScript Há muito pouco tempo atrás um amigo meu me sugeriu dar atenção à MoonScript. Admito que eu via a linguagem com preconceito, mesmo assim resolvi dar uma olhada.

Resultado: todos os meus códigos em Lua acabaram convertidos para MoonScript. :-)

A linguagem é extremamente enxuta, limpa e poderosa. Não vou entrar em detalhes, se estiver curioso, leia o guia da linguagem.

Mas também não puxei assunto por nada, vou dar alguns exemplos.

Paradigma Funcional

Para lidar com o paradigma funcional, a sintaxe de MoonScript é bem mais concisa e que a de Lua. Por exemplo, o combinador Y.

Lua é uma linguagem estrita e não suporta o combinador Y em sua forma lazy. Como MoonScript é compilado para código Lua, sofre do mesmo mal. Assim, é preciso usar o combinador Z, que é versão estrita do combinador Y.

O combinador Z é definido como: λf.(λx.xx)(λx.f(λv.xxv)). Isso é facilmente representado em MoonScript:
Z = (f using nil) -> ((x) -> x x) ((x) -> f (...) -> (x x) ...)

Com isso é possível, por exemplo, implementar facilmente o quick sort:
Z = (f using nil) -> ((x) -> x x) ((x) -> f (...) -> (x x) ...)

tconcat = (...) -> [e for t in *{...} for e in *t]

Z (qsort using tconcat) ->
(xs) ->
if #xs = 1
xs

else
x, xs = xs[1], [e for e in *xs[2,]]
lesser = [e for e in *xs when e = x]
greater = [e for e in *xs when e > x]
tconcat (qsort lesser), {x}, (qsort greater)

Orientação a Objetos

Em Lua é preciso toda uma ginástica com metatabelas para simular eficientemente orientação a objetos. MoonScript tem suporte a classes na linguagem.

Por exemplo, podemos criar uma pilha (stack) facilmente:
import bind_methods from assert require "moon"

class Stack
list: nil

set: (x) =>
@list =
next: @list
value: x

get: =>
v = nil
{value: v, next: @list} = @list if @list
v

bind_methods Stack!

LuaJIT

Como MoonScript compila para código Lua tradicional, você pode gerar código para virtualmente qualquer plataforma que rode Lua, como LuaJIT e LÖVE.

Por exemplo, você pode usar C-structs e metatipos:
ffi = assert require "ffi"
import sqrt from math

ffi.cdef [[
typedef struct { double x, y; } point_t;
]]

local Point = ffi.metatype "point_t",
__add: (o) => Point @x + o.x, @y + o.y
__len: => @\hypot!
__tostring: => "(#{@x}, #{@y})"
__index:
area: => @x * @y
hypot: => sqrt (@x*@x + @y*@y)

Point

bash$ luajit
LuaJIT 2.0.3 -- Copyright (C) 2005-2014 Mike Pall. http://luajit.org/
JIT: ON CMOV SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
> moon = assert(require "moonscript.base")
> Point = (moon.loadfile "point.moon")()
> p = Point(3, 4)
> = tostring(p)
(3, 4)
> = p:area()
12
> = #p
5
>
Bem, acho que já fiz propaganda suficiente da linguagem. ;-)

[]’s

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 29 de June de 2015 às 21:08

Galácia

Capoeira Elements and Movements Translated to English

BRAZILIAN PORTUGUESEENGLISH armadaarmed armada com martelo rodadoarmed with spinning hammer aúaooh (phonetic transliteration) bananeirahandstand bençãoblessing benguelabengala (phonetic transliteration) bento grandebig benedict bento médiomiddle genedict berimbaubaereembaoo (phonetic transliteration) botesnake strike cabeçadaheadbutt cadeirachair cocorinhalittle squatting compassocompasses

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 29 de June de 2015 às 14:27

Não dê ouvidos aos que disserem a você: repita essas palavras em hebraico, use essas vestimentas dos judeus, adote esses ícones israelenses ou faça esses rituais judaicos. Não são palavras de significado oculto ou ditas em outro idioma que conduzem a Cristo. Nem é o vestir-se como judeu que tornaria alguém mais aceitável a Deus. Tampouco fazer uso de candelabros, taças ou estrelas nos levaria

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 29 de June de 2015 às 13:01

Considerações Sobre a Revelação do Eu-Sou a Moisés

Na ocasião em que Moisés vê uma sarça (espécie de planta) em chamas mas sem se consumir, Deus se apresenta a Moisés com a expressão que caracterizaria a si próprio: “Eu sou o Deus de seu pai, o Deus de Abraão, o Deus de Isaque, o Deus de Jacó” (Êxodo 3.6). Em seguida, dá uma missão a Moisés, enfrentar o poderoso faraó do Egito e libertar os israelitas. Moisés, entretanto, manifesta certa

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 29 de June de 2015 às 12:50

June 19, 2015

Kodumaro

Cython

Nas últimas semanas tenho desenvolvido uma aplicação usando Cython e me surpreendi com o resultado.

Comecei usando o Cython apenas para compilar código Python – o que de fato rendeu o aumento de desempenho prometido –, mas então resolvi ir mais longe pra ver o quanto poderia extrair dessa plataforma: comecei a usar tipagem estática, funções C (cdef) e depois acabei migrando minhas classes para tipos de extensão (cdef classes).

A cada novo passo era perceptível o crescimento do desempenho e da coerência geral do código. Minha única crítica é quanto aos testes: o código fica muito difícil de ser testado, já que não é possível fazer monkey-patch para colocar os mocks.

Segundo a documentação, ao compilar código Python com Cython, você tem um aumento de 35% no desempenho do código. Usando a tipagem estática, o aumento é de 300% e usando funções C e tipos de extensão o aumento é de aproximadamente 15.000%.

Não posso confirmar esses números, pois não fiz medições exatas, mas uma fila do RabbitMQ que enchia com 6, 7 mil mensagens, encheu com 64 mil no mesmo período de tempo (eu estava fazendo apenas carga, sem consumir a fila).

Uma coisa que gostei muito no Cython é o feeling: tem uma pegada bastante parecida com a do Objective C, o que faz sentido.

Vou dar um exemplo da própria documentação do Cython:

Dado o seguinte código Python puro:
def f(x):
return x**2-x

def integrate_f(a, b, N):
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx
Você pode salvar esse código em integrate.pyx e compilá-lo assim:
bash$ cythonize -ib integrate.pyx
Isso irá gerar o código equivalente em C (integrate.c) e compilá-lo na biblioteca integrate.so, que pode ser diretamente importada em Python:
bash$ python
>>> from integrate import integrate_f
>>>
Se você tiver o IPython, pode usar o Cython no prompt:
bash$ ipython
Python 2.7.9 (default, Jan 7 2015, 11:49:12)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> %load_ext Cython
>>> %%cython
from integrate cimport integrate_f
De qualquer forma, só usando a biblioteca compilada em vez do código Python importado, Cython já promete um aumento de 35% de performance – o que não me frustrou.

Além disso, podemos adicionar tipagem ao código: Cython é um superset em Python, ou seja, é uma linguagem em si e um código Python é também código válido Cython.
def f(double x):
return x**2-x

def integrate_f(double a, double b, int N):
cdef:
int i
double s, dx
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx
Segundo a documentação, isso garante um desempenho 4 vezes superior ao de Python.

No entanto ainda é possível otimizar mais ainda o código! Cython tem uma sintaxe específica que gera código C diretamente, cdef:
cdef double f(double x) except? -2:
return x**2-x

def integrate_f(double a, double b, int N):
cdef:
int i
double s, dx
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx
O desempenho dessa função f em C promete ser 150 vezes melhor do que a mesma função em Python puro.

O except? -2 na função é usado para passar exceções para o código C. Em um outro momento posso entrar em mais detalhes.

Tipo de extensão

Tipos de extensão são equivalentes às classes de Python, porém mais restritos e muito mais eficientes.

Por exemplo, da a seguinte classe:
class Consumer(object):

def __init__(self, backend):
self.backend = backend

def run(self, handler):
resp = self.backend.get()
return handler.handle(resp)
Considerando que as instâncias só serão executadas em Cython, o código equivalente estaria em dois arquivos, o primeiro consumer.pxd:
from backends.base cimport Backend
from handlers.base cimport Handler

cdef class Consumer:

cdef:
Backend backend
int run(self, Handler handler) except? -1
Esse código .pxd equivale ao cabeçalho .h de C. Agora, o arquivo de implementação deve ser chamado consumer.pyx:
from backends.base cimport Backend
from handlers.base cimport Handler

cdef class Consumer:

def __cinit__(self, Backend backend):
self.backend = backend

cdef int run(self, Handler handler) except? -1:
cdef dict resp = self.backend.get()
return handler.handle(resp)
Esse código promete ser muito mais eficiente que sua versão em Python, infelizmente métodos declarados como cdef são acessíveis apenas em C (e em Cython). Para que o método seja acessível em Python, ele deve ser criado como um método Python comum (def) ou pode ser usado cpdef.

O comando cpdef (C/Python def) cria a função C (como cdef) e um wrapper em Python para torná-la acessível. Se o módulo for importando com cimport, será usada a função C original; se for importado com o clássico import, será usado o wrapper.

Conclusão

Até agora não tive motivos para me arrepender de usar Cython, recomendo.

[]’s
ℭacilhας, La Batalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 19 de June de 2015 às 16:10

June 16, 2015

Thiago Avelino

Eu nunca mais vou empreender

Empreender é viver novas experiências todos os dias

Para quem não me conhece eu tive uma startup durante um tempo e ela foi comprada por uma empresa de fora do Brasil. Logo após a venda da startup eu prometi para mim mesmo que nunca mais empreenderia, sim isso foi um comentário que fiz em um dos meus momentos de reflexão e nunca comentei com ninguém até então.

Porque eu prometi isso para mim?

Empreender não é um processo simples, não existe mar de rosas no caminho do empreendedor e como tudo temos altas e baixas (e por sinal mais baixa do que alta). Eu fui sócio do Christiano Anderson durante um tempo e ele foi e ainda é uma inspiração para mim como desenvolvedor e empreendedor, passava horas e horas tomando cerveja com ele entendendo algumas tomadas de decisão na vida dele e isso me fez ter ele como uma referência (e por sinal uma ótima referência). Voltando ao motivo, antes de vender à startup meu filho tinha nascido e empreender com uma criança recém-nascida foi um processo complicado, esposa precisando de atenção (mais do que o comum) e eu tendo que desenvolver solução para melhor atender os clientes, nessa fase logicamente que foi uma fase de baixa (poucos clientes). Como em muitos casos não tínhamos planejado ter filho, mas que venha com saúde.

Á volta para o mercado de trabalho!

Quando voltei para o mercado de trabalho queria ter estabilidade dentro da empresa e com isso aceitei algumas condições de trabalho não muito favorável (mas condições que muitas pessoas que mora em São Paulo – Capital aceita), eu andava media de 42 km para ate o escritório, sim 84 km por dia dentro de uma máquina de 4 rodas (chamada carro) e fazia papel de gerente de projeto (para quem não sabe eu tinha certificado PMP, que venceu em 2014 e não tenho a mínima vontade de renovar). Meu dia a dia era mandar e-mail e dar prazo para projeto, sei que isso na área de tecnologia não é muito fácil (mas é o que tem para hoje). Chegava em casa extremamente cansado por ter trabalhado o dia todo e consequentemente ter participado do trânsito de uma megalópole (em São Paulo, você não pega transito e sim participa, é muitas horas para falar que pegou transito). Logicamente que não fiquei muito tempo nessa vida e resolvi procurar outra oportunidade e fui trabalhar home office (remoto) como desenvolvedor. Agora sim cheguei onde eu quero, trabalhando de casa, vendo meu filho crescer, ate ir para PythonBrasil[10] e passar algumas horas conversando com o Henrique Basto que me fez algumas perguntas que o Renzo e Bruno Rocha tinha feito a 1 ano atrás e eu ainda não sabia responder.

A volta para os empreendedorismos…

“Porque você trabalha para os outros ainda? Você não consegue viver da renda do samba (site de conteúdo adulto, link para +18)?”

Isso fez eu refletir alguns meses e juntar com uma grande vontade que tinha que era sair da Capital e ir morar no interior. Após convence a esposa foi hora de procurar cidade e casa. Lembrei do Cadu que tinha comentado e convidado de eu de vir morar no Vale do Paraíba quando estava trabalhando remoto. Escolhi uma cidade tranquila próximo de SJC para morar com minha família (Caçapava, e viva a Taiada).

Sim vamos viver de samba, após 1 mês morando no Vale e empreendendo, o samba me fez sambar, a empresa que mantinha o fluxo do caixa do samba resolveu aplicar algumas regras, que fez o samba não consegui sacar o dinheiro que estava rendendo, sem eu pensar estava novamente empreendendo.

Após isso acontecer, comecei pensar que tinha feito a pior escolha da minha vida em ter saído da Capital e vindo morar no Vale, eu não tinha ligado o nome Vale do Paraíba com Vale do Silício. Sim o Vale do Paraíba respira empreendedorismo, principalmente dentro do Parque Tecnológico de SJC. Onde fez eu retomar meu espírito empreendedor e começa novamente empreender.

Hoje posso afirma que empreender é viver novas experiências todos os dias e tirar energia de onde você meno espera.

Devo muito (mas muito) ao Cadu e Nando por algumas horas de bate papo sobre como eles fazem as coisas acontecer dentro da ZNC e experiência de vida empreendedora.

por avelino em 16 de June de 2015 às 15:15

June 14, 2015

PythonClub

Instalando o PyCharm no Ubuntu (e irmãos)

O objetivo aqui é instalar o PyCharm no Ubuntu e distribuições "irmãs" (como o Mint); estou instalando a versão Community Edition, que acredito que é a que muita gente que começa com essa poderosa IDE vai instalar pra dar os primeiros passos, experimentar.

(aliás, bom avisar antes de começar: fiz o guia baseado no Ubuntu 14.04 e no Linux Mint 17.1; mas já fiz o mesmo procedimento em versões anteriores tanto do PyCharm quanto do Ubuntu, e com a versão "Professional" do PyCharm, e funcionou bem.)

Parte 1 - instalar o Java

As aplicações da JetBrains não são exatamente compatíveis com a versão do Java que vem por padrão no Ubuntu. Por isso, precisamos atualizar.

Abra o terminal e execute os comandos abaixo:

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections
sudo apt-get install oracle-java8-installer -y
sudo apt-get install oracle-java8-set-default -y

Após os comandos acima, veja se a instalação está correta, executando no console:

java -version

a saída esperada é algo como:

java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

Parte 2 - pip e virtualenv

O PyCharm usa o pip para baixar módulos/bibliotecas/extensões (como quiser chamar) do python, e o virtualenv para criar os queridos ambientes virtuais que mantém a sanidade dos programadores python. Então, para tirar proveito dessas funcionalidades, é bom garantir que estejam instalados também.

Para isto, abra o console e:

cd ~/Downloads
wget -c https://bootstrap.pypa.io/get-pip.py
sudo -H python2 get-pip.py
sudo -H python3 get-pip.py
sudo -H pip2 install virtualenv

Parte 3 - copiar o PyCharm

  • clique no link ao lado para ir à página de Download do PyCharm
  • clique em "Download Community"
  • grave o arquivo no diretório que quiser

Parte 4 - instalar o PyCharm

Com os pré-requisitos prontos e instalados, vamos ao prato principal:

sudo tar -C /opt/ -xzf <diretorio_onde_gravou_o_download>/pycharm-community-4.5.1.tar.gz
  • Abra o navegador de arquivos e vá ao diretório /opt/pycharm-community-4.5.1
  • Entre no diretório 'bin' e, com dois cliques sobre, execute o script 'pycharm.sh'
  • Se aparecer uma janela perguntando como rodar o programa, clique no último botão ('Executar' ou 'Run')
  • Dê "OK" na janela que abrir
  • E na próxima janela, deixe todas as últimas opções selecionadas. Ao clicar em 'OK' o PyCharm vai pedir a senha de 'root' para criar as entradas no menu.

Tela de configuração final

Pronto, é isso. O software está instalado, e pronto para uso.

por Erick Müller em 14 de June de 2015 às 15:58

June 08, 2015

Galácia

Por que as leis da física são da maneira como são? O que determina o acaso?

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 08 de June de 2015 às 13:12

June 07, 2015

PythonClub

A armadilha dos argumentos com valores padrão

Algo muito comum em várias linguagens de programação é a possibilidade de definir valores default (valores padrão) para argumentos de funções e métodos, tornando a utilização desses opcional. Isso é ótimo, principalmente para manter retrocompatibilidade, porém, o python possui uma pequena armadilha que caso passe despercebida, pode causar sérios problemas, muitas vezes difíceis de serem detectados. Essa armadilha ocorre quando usamos valores de tipos mutáveis como valor default de argumentos.

O que são tipos mutáveis e imutáveis?

Segundo a documentação oficial do python, o valor de alguns objetos pode mudar, esses objetos que podem ter seu valor alterado após serem criados são chamados de mutáveis, enquanto que os objetos que não podem ter seus valores alterados após serem criados são chamados de imutáveis (simples assim).

  • Tipos mutáveis:

Listas, Dicionários e tipos definidos pelo usuário.

  • Tipos imutáveis:

Numeros, Strings e Tuplas.

Apesar de serem imutáveis, a utilização de um valor mutável (uma lista por exemplo) dentro de uma tupla, pode causar o efeito tuplas mutáveis, onde visualmente o valor da tupla é alterado, mas por trás dos panos o valor da tupla não muda, o que muda é o valor do objeto pelo qual a tupla está se referenciando.

A armadilha

Como disse no começo desse blogpost, é muito comum a utilização de valores default em agurmentos de funções e métodos, por essa razão, nos sentimos seguros em fazer algo desse tipo:

def my_function(my_list=[]):
    my_list.append(1)
    print(my_list)

Porém, levando esse exemplo em consideração, o que irá acontecer se invocarmos essa função 3 vezes?

>>> my_function()
[1]
>>> my_function()
[1, 1]
>>> my_function()
[1, 1, 1]

Sim, o valor do argumento my_list mudou em cada vez que executamos a função sem passar algum valor para ele.

Por que isso acontece?

Isso acontece porque o python processa os valores default de cada argumentos de uma função (ou método) quando essa for definida, após esse processamento o valor é atribuido ao objeto da função. Ou seja, por questões de optimização, seguindo nosso exemplo, o python não cria uma lista vazia para o argumento my_list a cada vez que a função my_function for invocada, ele reaproveita uma lista que foi criada no momento em que essa função foi importada.

>>> my_function.func_defaults
([],)
>>> id(my_function.func_defaults[0])
140634243738080
>>> my_function()
[1]
>>> my_function.func_defaults
([1],)
>>> id(my_function.func_defaults[0])
140634243738080
>>> my_function()
[1, 1]
>>> my_function.func_defaults
([1, 1],)
>>> id(my_function.func_defaults[0])
140634243738080

Note que a identificação do argumento (no caso my_list) não muda, mesmo executando a função várias vezes.

Outro exemplo seria utilizar o resultado de funções como valores default de argumentos, por exemplo, uma função com um argumento que recebe como default o valor de datetime.now().

def what_time_is_it(dt=datetime.now()):
    print(dt.strftime('%d/%m/%Y %H:%M:%S'))

O valor do argumento dt sempre será o datetime do momento em que o python carregou a função e não o datetime de quando a função foi invocada.

>>> what_time_is_it()
07/06/2015 08:43:55
>>> time.sleep(60)
>>> what_time_is_it()
07/06/2015 08:43:55

Isso também acontece com classes?

Sim e de uma forma ainda mais perigosa.

class ListNumbers():
    def __init__(self, numbers=[]):
        self.numbers = numbers

    def add_number(self, number):
        self.numbers.append(number)

    def show_numbers(self):
        print(numbers)

Assim como no caso das funções, no exemplo acima o argumento numbers é definido no momento em que o python importa a classe, ou seja, a cada nova instância da classe ListNumbers, será aproveitada a mesma lista no argumento numbers.

>>> list1 = ListNumbers()
>>> list2 = ListNumbers()
>>> list1.show_numbers()
[]
>>> list2.show_numbers()
[]
>>> list2.add_number(1)
>>> list1.show_numbers()
[1]
>>> list2.show_numbers()
[1]
>>> list1.numbers is list2.numbers
True

Por que isso não acontece com Strings?

Porque strings são imutáveis, o que significa que a cada alteração de valor em uma variavel que armazena uma strings, o python cria uma nova instância para essa variável.

>>> a = 'foo'
>>> id(a)
140398402003832
>>> a = 'bar'
>>> id(a)
140398402003872  # o penúltimo número muda :)

Em argumentos com valores default, não é diferente.

def my_function(my_str='abc'):
    my_str += 'd'
    print(my_str)

No exemplo acima, sempre que for executado o inplace add (+=) será criada outra váriavel para my_str sem alterar o valor default do argumento.

>>> my_function()
abcd
>>> my_function.func_defaults
('abc',)
>>> my_function()
abcd
>>> my_function.func_defaults
('abc',)

Como se proteger?

A maneira mais simples de evitar esse tipo de surpresa é utilizar um valor sentinela como por exemplo None, nos argumentos opcionais que esperam tipos mutáveis:

def my_function(my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(1)
    print(my_list)

Ou, para deixar o código ainda mais elegante, podemos simplificar a condicional com um simples or:

def my_function(my_list=None):
    my_list = my_list or []
    my_list.append(1)
    print(my_list)

Obrigado Bruno Rocha pela sugestão.

Pronto, sem surpresas e sem armadilhas :).

>>> my_function()
[1]
>>> my_function()
[1]
>>> my_function()
[1]

Referências

por Diego Garcia em 07 de June de 2015 às 14:00

June 04, 2015

Osvaldo Santana Neto

Eu e a comunidade Python

Assine a minha newsletter quinzenal O Melhor da Internet e receba um resumo dos melhores materiais sobre Python, Django, Carreira e Empreendedorismo.


O Eric Hideki começou a levantar a história da comunidade Python brasileira e pediu que as pessoas que participaram desde o início pudessem colaborar com o projeto dele.

OBS. Não tive tempo de revisar esse texto antes de publicar. Assim que conseguir um tempinho prometo corrigir os problemas. Até lá, se encontrou algo grave, me manda um email.

Eu e Python

Eu conheci a linguagem Python em 2000 quando trabalhava na Conectiva (criadora do Conectiva Linux). Eu estava trabalhando (em C) num projeto que unificava as configurações de vários gerenciadores de janela suportados pela Conectiva (KDE, Gnome, WindowMaker, etc).

Eu parseava um arquivão de configurações genérico e gerava as configurações para cada um deles.

Fazer isso em C estava dando bastante trabalho e meu chefe (Cavassin) me mostrou a tradução que ele tinha feito de um mini-tutorial de Python do Magnus Lie Hetland.

Levei o artigo pra casa e tentei usar o projeto em que estava trabalhando para aprender a linguagem.

Em uma noite eu consegui implementar em Python tudo o que eu já havia feito em duas semanas de trabalho em C.

Comunidade

Quando eu deixei a Conectiva fui obrigado a trabalhar com Java e não conseguia conceber a razão pela qual as pessoas sofriam tanto com uma linguagem sub-ótima.

Com o passar dos meses eu fui percebendo que as pessoas usavam Java porque várias pessoas também usavam Java: a comunidade Java.

Como criar uma comunidade?

Comecei a pesquisar na internet e encontrei alguns núcleos e pequenos grupos de usuários Python. O mais consistente se encontrava no grupo “python-br” do Yahoo! Groups. Outro grupo que era bem ativo era do TcheZope no RS.

Como eu nunca mexi com Zope resolvi focar em participar da “python-br” cujo administrador “desapareceu” juntamente com o acesso de admin do grupo. Como a gente não tinha o admin desse grupo e começamos a receber muito spam nele decidimos criar a “python-brasil” (ainda no Yahoo! Groups) onde passei a ser o moderador principal (depois recebi ajuda do Pedro Werneck, do Andrews Medina e de mais alguns outros).

Quando eu criei essa lista ela não tinha mais do que 400 assinantes. Quando deixei a moderação ela tinha mais de 3000.

Muitas perguntas que chegavam no grupo eram repetidas e para não ter que ficar respondendo uma por uma achamos melhor criar um site para agrupar o material de Python nacional.

Um dos participantes do grupo (Marco Catunda) criou uma instância com Plone e apontamos um hostname para lá (a gente não tinha domínio próprio ainda). O problema é que ninguém configurou usuários e permissões do Plone corretamente e o Marco andava muito ocupado para fazer isso. Então ficou bem difícil alimentar o site com conteúdo.

Em paralelo a isso eu descobri os Wikis (em especial o MoinMoin que é feito em Python) e resolvi instalar um no provedor onde eu trabalhava. Coloquei alguns artigos que eu havia escrito no site e “lancei” a idéia no grupo que o abraçou. O primeiro site de Python da comunidade brasileira estava no ar. O endereço? http://python.rantac.com.br :)

Como o wiki é livre e, na época, não precisava nem de usuário para colocar ou editar conteúdo a coisa foi crescendo bastante e se tornou o principal site da comunidade…

Não demorou muito para que a gente tivesse motivos para se reunir e conversar sobre Python.

O Rodrigo Senra, que estudava na Unicamp conseguiu o espaço e infraestrutura para um dia de evento: PyConDay… Mas o grande número de palestras submetidas logo demandou mais um dia de evento… E a PyConDay passou a ter dois dias e a se chamar PyConBrasil (posteriormente, por sugestão do Luciano Ramalho renomeamos o evento para PythonBrasil).

O Senra cuidou de tudo praticamente sozinho e se auto-entitulou “Big Kahuna” do evento. Por tradição esse é o título concedido à todos aqueles que se aventuraram na organização de uma PythonBrasil.

Associação

Tudo o que fazíamos, na época, era feito na raça e com recursos próprios. E isso dava um trabalho enorme… Passamos a enfrentar alguns contratempos para organizar os eventos, para manter o site no ar, renovar domínios, etc.

A coisa toda ficou muito individualizada: o Osvaldo moderava a lista, mantinha o domínio pythonbrasil.com em seu próprio cartão (na época precisava ter CNPJ para adquirir um domínio .com.br e/ou ser uma organização sem fins lucrativos para ter um .org.br).

Começamos a esboçar a Associação Python Brasil para dar suporte para a Comunidade. Em 2007, depois de muita cabeçada, idas e vindas, burocracia sem fim (thanks Luciano Ramalho e Dorneles Treméa), fundamos a APyB.

Fundação da APyB

Eu sempre fui conselheiro da APyB e cheguei até a presidi-la por um mandato. É trabalhoso e razoavelmente chato gerir ela. Mas depois que nos acostumamos e ganhamos prática fica até automático.

A Fila Anda

Com o passar dos anos envolvidos com a comunidade eu comecei a ficar um pouco cansado e estava preocupado com a continuidade disso tudo. Eu também achava que novas pessoas surgiriam se eu fosse embora e “liberasse o espaço”.

Outros colegas, aos poucos, foram deixando as alavancas para outras pessoas. Novas lideranças, etc.

Eu acho que a Associação já cumpriu o seu papel. Se existissem pessoas dispostas a cuidar dela de verdade ela até poderia continuar tendo a sua utilidade.

Mas não podemos negar que a internet muda muito rápido e as comunidades ganham características cada vez mais descentralizadas. A importância de uma organização como a APyB claramente diminuiu e isso, na minha opinião, não importa muito.

Mas com o fim da APyB algumas coisas boas produzidas por ela deixarão de existir.

The post Eu e a comunidade Python appeared first on osantana.

por Osvaldo Santana em 04 de June de 2015 às 00:01

June 02, 2015

Galácia

Isaías foi literal quando disse: Certamente ele tomou sobre si as nossas enfermidades e sobre si levou as nossas doenças. (53.4a). Pois: [Jesus] curou todos os doentes. E assim se cumpriu o que fora dito pelo profeta Isaías: "Ele tomou sobre si as nossas enfermidades e sobre si levou as nossas doenças". (Mateus 8.16a,17)

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 02 de June de 2015 às 18:30

May 29, 2015

Gustavo Niemeyer

mgo r2015.05.29

Another release of mgo hits the shelves, just in time for the upcoming MongoDB World event.

A number of of relevant improvements have landed since the last stable release:


New package for having a MongoDB server in test suites

The new gopkg.in/mgo.v2/dbtest package makes it comfortable to plug a real MongoDB server into test suites. Its simple interface consists of a handful of methods, which together allow obtaining a new mgo session to the server, wiping all existent data, or stopping it altogether once the suite is done. This design encourages an efficient use of resources, by only starting the server if necessary, and then quickly cleaning data across runs instead of restarting the server.

See the documentation for more details.

(UPDATE: The type was originally testserver.TestServer and was renamed dbtest.DBServer to improve readability within test suites. The old package and name remain working for the time being, to avoid breakage)

Full support for write commands

This release includes full support for the write commands first introduced in MongoDB 2.6. This was done in a compatible way, both in the sense that the driver will continue to use the wire protocol to perform writes on older servers, and also in the sense that the public API has not changed.

Tests for the new code path have been successfully run against MongoDB 2.6 and 3.0. Even then, as an additional measure to prevent breakage of existent applications, in this release the new code path will be enabled only when interacting with MongoDB 3.0+. The next stable release should then enable it for earlier releases as well, after some additional real world usage took place.

New ParseURL function

As perhaps one of the most requested features of all times, there’s now a public ParseURL function which allows code to parse a URL in any of the formats accepted by Dial into a DialInfo value which may be provided back into DialWithInfo.

New BucketSize field in mgo.Index

The new BucketSize field in mgo.Index supports the use of indexes of type geoHaystack.

Contributed by Deiwin Sarjas.

Handle Setter and Getter interfaces in slice types

Slice types that implement the Getter and/or Setter interfaces will now be custom encoded/decoded as usual for other types.

Problem reported by Thomas Bouldin.

New Query.SetMaxTime method

The new Query.SetMaxTime method enables the use of the special $maxTimeMS query parameter, which constrains the query to stop after running for the specified time. See the method documentation for details.

Feature implemented by Min-Young Wu.

New Query.Comment method

The new Query.Comment method may be used to annotate queries for further analysis within the profiling data.

Feature requested by Mike O’Brien.

sasl sub-package moved into internal

The sasl sub-package is part of the implementation of SASL support in mgo, and is not meant to be accessed directly. For that reason, that package was moved to internal/sasl, which according to recent Go conventions is meant to explicitly flag that this is part of mgo’s implementation rather than its public API.

Improvements in txn’s PurgeMissing

The PurgeMissing logic was improved to work better in older server versions which retained all aggregation pipeline results in memory.

Improvements made by Menno Smits.

Fix connection statistics bug

Change prevents the number of slave connections from going negative on a particular case.

Fix by Oleg Bulatov.

EnsureIndex support for createIndexes command

The EnsureIndex method will now use the createIndexes command where available.

Feature requested by Louisa Berger.

Support encoding byte arrays

Support encoding byte arrays in an equivalent way to byte slices.

Contributed by Tej Chajed.

por niemeyer em 29 de May de 2015 às 12:55

May 28, 2015

Magnun Leno

Hack ‘n’ Cast v0.14 - Projeto MOD

Todo músico que entende um pouco de tecnologia já se irritou com a necessidade de comprar diversos hardwares para melhorar o som produzido pelo seu instrumento. Mas e se existisse um hardware único que pudesse programado e atualizado de forma a atender todas as suas necessidades? Então, agora ele existe...

Baixe o episódio e leia o shownotes

por Magnun em 28 de May de 2015 às 03:11

May 24, 2015

PythonClub

Criação de aplicações no Google App Engine com o Tekton

Google App Engine (GAE)

É a plataforma de Cloud Computing do Google, com ela você pode desenvolver e hospedar aplicações usando Python (2.7) que escalam facilmente, pagando muito pouco por isso.

As desvantagens (em relação a outras plataformas de nuvem, como o Heroku por exemplo) são: - Você terá que desenvolver pensando na plataforma (banco de dados NoSQL, por isso o Django não é recomendável.). - Versão do Python é antiga e não há planos para mudar isso no momento.

Tekton

É um framework para desenvolvimento Web especialmente pensado para uso no Google App Engine. Nele podemos aproveitar o melhor do Django (scaffold, código HTML e validação de formulários a partir de modelos, apps isoladas) sem perder as vantagens que o GAE nos oferece.

Como iniciar

O primeiro passo é baixar o SDK do Google App Engine, com isso pronto podemos começar a conhecer o Tekton.

Em seguida, vamos baixar a aplicação template.

$ wget https://github.com/renzon/tekton/archive/master.zip
$ unzip master && rm master.zip
$ mv tekton-master projeto_appengine && cd projeto_appengine     

Nesse ponto podemos explorar e conhecer a estrutura de diretórios.

└── backend
 ├── appengine
 ├── apps
 ├── build_scripts
 ├── test
 └── venv
$ cd backend/venv/ && ./venv.sh
$ source ./bin/activate         

Com o ambiente virtual pronto, tudo deve estar funcionando. Para testar, vamos utilizar o próprio servidor que vem com o pacote antes de subir parao GAE.

cd ../appengine && dev_appserver.py . 

Tudo certo! Você deve estar vendo o projeto template no seu localhost:8080

Para realizar o deploy no App Engine:

appcfg.py update . --oauth2

Você pode conhecer mais sobre o projeto no Github, no grupo de discussões ou nas vídeo aulas gratuitas no Youtube.

por Guido Luz Percú em 24 de May de 2015 às 03:00

May 18, 2015

Filipe Saraiva

Software Livre no Pint of Science Brasil 2015

Pint of Science é um festival internacional em rede que reúne cientistas em mesas de bares para conversar e compartilhar sobre ciência, a repercussão que sua área de pesquisa tem para a sociedade, e muito mais. É divulgação científica + boteco!

O Brasil está participando pela primeira vez do evento, e a cidade de São Carlos terá 3 dias com mesas de bate-papo sobre temas variados em dois restaurantes da cidade.

Para quem estiver na cidade hoje (18/05), a partir das 20h o Espaço Sete terá uma conversa sobre software livre e a liberdade de conhecimento na academia. Estarei lá junto com um grupo de amigos participantes de diversas comunidades de software livre para falarmos sobre o assunto, e claro, beber cerveja.

Vejo vocês lá!

por Filipe Saraiva em 18 de May de 2015 às 18:32

Galácia

VACAS MAGRAS À VISTA

A economia brasileira está sofrendo um baque como eu nunca tinha visto desde que me entendo por gente. Vamos ter pelo menos mais quatro anos perdidos. Que Deus use tudo isso para trazer o país ao arrependimento.

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 18 de May de 2015 às 12:58

May 12, 2015

Eric Hideki

O que você está fazendo de errado na sua carreira de programador

O que você está fazendo de errado em sua carreira de programador

Cada pessoa é um indivíduo único, onde as formas de absorver informações são dos mais variados tipos. Por isso este blog busca diversas formas de ensino, seja através de cursos, tutoriais, artigos ou videoaulas. Mas isso não basta.

O que aprendi sobre aprender

Por que todo mundo está com pressa? E como aprender a programar em 10 anos.

O que está ficando óbvio a cada dia é que poucos sabem os caminhos a serem traçados, seja iniciantes ou quem já está na área há um bom tempo. Isso porque não conseguimos distinguir nossos momentos de escolhas. Mas o que são escolhas?

Como me tornar excelente naquilo que faço?

By Klaus Wuestefeld

1) Torne-se excelente.

Seja realmente bom em alguma coisa. Não fique só choramingando ou querendo progredir às custas dos outros. Não pense q pq vc sentou 4 anos numa faculdade ouvindo um professor falar sobre software q vc sabe alguma coisa. Jogador de futebol não aprende a jogar bola tendo aula. Ele pratica. Instrumentistas geniais nao aprendem a tocar tendo aula. Eles praticam. Pratique. Chegue em casa depois do trabalho e da aula e pratique. No final de semana, pratique.

Crie seu próprio virus, seu próprio jogo, seu próprio SO, seu próprio gerenciador de janelas, seu próprio webserver, sua própria VM, qualquer coisa. Várias coisas.

Não precisa ser só programação. Pode ser networking, vendas, etc. Só precisa ser bom mesmo. Tenha paixão pela coisa.

As melhores praticas do mercado são polinizadas primeiro nos projetos de software livre. Aprenda com eles.

Discípulo, Viajante, Mestre: Primeiro seja um discípulo, tenha mestres locais, aprenda alguma coisa com alguém realmente bom, qq estilo. Depois viaje, encontre outros mestres e aprenda o estilo deles. Por fim, tenha o seu estilo, tenha discípulos, seja um mestre.

Vou fazer o curso da Mary Poppendieck em SP semana q vem e qdo tiver o curso de Scrumban do Alisson e do Rodrigo quero fazer tbem.

“Torne-se excelente” também pode ser chamado de “Melhoria Continua” ou “Learning”.

2) Não seja deslumbrado.

Desenvolvimento de software é a mesma coisa há 60 anos: modelo imperativo. Há 30 anos: orientação a objetos. Bancos de dados relacionais: 30 anos. (“Web”, por exemplo, não é uma tecnologia ou um paradigma. É meramente um conjunto de restrições sobre como desenvolver e distribuir seu software).

Não corra atras da ultima buzzword do mercado. Busque a essência, os fundamentos.

Busque na wikipédia e grokke: determinismo, complexidade de algoritmos “O()”, problema de parada de turing. Pronto, pode largar a faculdade. Falando sério.

Trabalhe com software livre. Não dê ouvidos a grandes empresas, grandes instituições ou grandes nomes só pq são grandes.

Vc acha q vai aprender mais, ter mais networking e mais chance de alocação no mercado trabalhando em par comigo no Sneer por um ano, 8h por semana, ou passando 4 anos na faculdade, 20h por semana, pagando sei la qto por mês?

Vc acha q vai aprender mais trabalhando em par com o Bamboo 6 meses na linguagem boo e na engine do Unity ou fazendo um ano de pós em “a buzzword da moda”?

“Nao seja deslumbrado” tbem é conhecido como “Coolness”.

3) Mantenha-se Móvel.

Com a demanda q temos hoje no mercado, se vc é desenvolvedor de software e n consegue negociar um contrato com uma empresa onde vc é pago por hora e pode trabalhar qtas horas quiser com um minimo de meio periodo, vc precisa rever a sua vida.

É melhor ter dois empregos de meio-periodo q um de periodo integral, pq vc pode largar um deles a qq momento.

Vc nunca vai conseguir nada melhor se não tiver tempo, se não tiver disponibilidade pra pegar algo melhor qdo aparecer.

Vc sustenta seus pais e 7 irmãos? Não. Então para de ser ganancioso e medroso no curto prazo, para de pagar facu, mestrado, pós, MBA, sei-la-o-q e vai aprender e empreender.

Trabalhe remoto. Não é o mais fácil, mas é perfeitamente possível.

Não fique reclamando q está trabalhando demais. Aumente seu preço e trabalhe menos.

4) Emparceire-se Promiscuamente.

Participe de dojos, de congressos, de projetos de software livre. Tenha amigos, colegas, conhecidos. Seja conhecido. Não faça ruído em seis projetos e doze fóruns. Ajude de verdade em um ou dois projetos de cada vez. Ao longo do tempo, vc terá ajudado em vários projetos, trabalhado em varias empresas.

5) Mentalidade de Abundância.

Ajude seus amigos sem cobrar (a “camaradagem” do Vinícius). Dê palestras gratuitas. Cursos gratuitos. Participe de projetos de software livre.

Pare as vezes uma tarde pra receber um amigo seu e explicar seu projeto. Vá visitar seus amigos nos projetos deles. Viaje com algum amigo seu pra visitar um cliente dele, só pra conversar e fazer companhia.

Vc tem um espaço onde dá cursos? É uma Aspercom, Caelum da vida? Chama os brothers p dar curso. Porra, bola um modelo em q as pessoas podem se inscrever para cursos variados, pagando um sinal, e mantém tipo uma agenda pre-combinada: “Será numa terça e quinta a noite, avisadas com duas semanas de antecedencia”. Se rolar, beleza, se depois de meses nao der quorum, devolve o sinal. Pode ser curso de Prevayler, de Kanban, de Scrum, de Lean, de Comp Soberana, de Restfulie, de Cucumber, de Rails, de Teste Automatizado Mega-Avançado, qq coisa.

Chame amigos seus pra dar curso em dupla com vc. Divida clientes.
Divida projetos, mesmo q não precise de ajuda.

Dizia o pai de um brother meu de infância: “Tudo q custa dinheiro é barato.”

6) Busque modelos de custo zero.

Trabalhe em coisas q tem custo administrativo/burocrático/manutenção zero. Por menos ganho q tragam, depois de prontas, estarão tendo uma relação custo/beneficio infinitamente vantajosa.

7) Ganhe notoriedade.

Faça coisas massa. Participe de projetos de software livre. Dê palestras gratuitas. Promova eventos (dojos, debates, grupos de usuários, etc).

By Dairton Bassi:

8 – Não tenha medo!

Meta a cara. Arrisque empreender. Arrisque inovar. O que você tem a perder? No máximo um emprego, mas isso pode ser revertido facilmente em um mercado aquecido como o atual. O pior que pode acontecer é não dar certo. Mesmo assim você terá aprendido muito mais do que batendo cartão.
Saia da zona de conforto. Se o seu trabalho estiver fácil e sob controle, isso significa que ele não está mais agregando para a sua evolução técnica e pessoal.

Não desperdice a chance de trocar de função se a nova oportunidade for mais desafiadora. Isso fará você crescer tecnicamente e o preparará para desafios maiores ainda. Conhecer pessoas novas é tão importante quanto manter-se em contato com código.

Não se detenha por insegurança ou pela sensação de despreparo. Como você acha que vai ganhar experiência em alguma coisa se sempre adiá-la?

Deu para pegar algumas sacadas?

Não esqueça de deixar nos comentários o que descobriu. :)


por Eric Hideki em 12 de May de 2015 às 01:25

May 11, 2015

Ricbit

A Intuição do Knuth

Às vezes eu me pergunto se as pessoas da minha área têm noção de quão sortudos nós somos. Os físicos adorariam viajar no tempo para conversar com o Newton, os matemáticos adorariam conversar com o Euclides, os biólogos adorariam conversar com o Darwin. Mas nós podemos conversar com o Knuth!


Nós temos a sorte de viver no mesmo período de tempo que o criador da análise de algoritmos, que é uma das bases da Ciência da Computação. Se você gosta do assunto, vale a pena juntar uns trocos e viajar até a Califórnia para assistir a uma das palestras dele (dica: todo fim de ano, inspirado nas árvores de Natal, ele faz uma palestra de estrutura de dados, falando sobre árvores; elas também estão online se você não tiver como ver ao vivo).

Eu fiz a peregrinação em 2011, quando consegui assistir a uma das palestras dele. Aproveitei para ir todo contente pegar minha recompensa por ter achado um erro no Art of Computer Programming, mas ele, marotamente, me disse que aquilo que eu achei não era um erro, era uma pegadinha, e eu caí! (Mas eu não vou falar qual a pegadinha, vá na página 492 do TAOCP volume 4A, primeira edição, e confira você mesmo :)

Eu e Knuth, o trollzinho

Nesse dia perguntaram que opinião ele tinha sobre o problema mais difícil da nossa geração, P=NP. A intuição dele é que provalmente é verdade, mas ele acredita que se acharmos a demonstração, ela vai ser não-construtiva. O que isso significa? O que é uma demonstração não-construtiva?

Demonstrações construtivas e não-construtivas


Em análise de algoritmos, as demonstrações construtivas são as mais comuns. Por exemplo, digamos que eu quero provar que é possível calcular x elevado a y em tempo O(y). Isso é fácil, basta construir um algoritmo assim:
E se eu quiser provar que esse mesmo problema pode ser resolvido em tempo O(log y)? Novamente, tudo que eu preciso fazer é exibir um algoritmo que implemente isso:

(Nesse caso eu também precisaria provar que esse algoritmo é de fato O(log y), já não é óbvio por inspeção). Nos dois casos temos exemplos de demonstrações construtivas: se eu quero provar uma propriedade P, basta exibir um algoritmo que tenha essa propriedade P.

As demonstrações não-construtivas são diferentes. Nelas, eu posso provar a propriedade P sem mostrar o algoritmo, através de alguma propriedade matemática do modelo.

Por exemplo, imagine que eu tenho uma lista ordenada de números. Se eu fizer uma busca binária, posso achar a posição de um número dado com O(log n) comparações. Mas é possível criar um algoritmo mais rápido que isso? Eu digo que não é possível, e para isso vou fazer uma prova não-construtiva de que esse é o mínimo que um algoritmo de busca precisa para funcionar.

A Teoria de Shannon aplicada à busca binária


Para isso eu vou usar a teoria da informação de Shannon. Essa teoria é surpreendentemente intuitiva, e se baseia no conceito de surpresa. Se eu te falar que o céu ficou escuro às 19h, você não vai achar nada de mais, nessa hora o Sol está se pondo, então é natural que o céu fique escuro. Mas e se eu falar que o céu ficou escuro às 10 da manhã? Foi uma tempestade? Um eclipse? A nave do Independence Day?

Intuitivamente, quanto mais surpresos nós ficamos com uma sentença, mais informação ela tem. O Shannon definiu então a quantidade de informação como sendo uma função monotônica da probabilidade do evento acontecer:

I(m)=\log\left(\frac{1}{p(m)}\right)

Se o evento é raro, tem bastante informação; se o evento é comum, tem pouca informação. A base do logaritmo fornece a unidade de medida, se a base for 2, então a informação é medida em bits.

E quanta informação nós ganhamos com uma comparação? Se a chance de dar verdadeiro ou falso for a mesma, então a chance é p(m)=1/2, logo a informação é I(m)=1. Você ganha exatamente um bit de informação com uma comparação.

Qual o resultado do nosso algoritmo de busca? O resultado é um índice, se nós temos n elementos no vetor, então a resposta é um índice que varia de 0 a n-1. Logo, a probabilidade de você escolher o índice certo ao acaso é p(m)=1/n, já que a escolha é uniforme.

Quanta informação tem essa escolha, então? Fazendo a conta:


Se você precisa de log n bits para descrever a resposta, e você ganha só 1 bit por comparação, então não tem como um algoritmo rodar em menos que O(log n): a informação tem que vir de algum lugar! Com isso, nós mostramos que qualquer algoritmo precisa rodar no mínimo em tempo O(log n), e sem precisar mostrar o algoritmo em si. Essa é uma demonstração não-construtiva.

Pressinto a pergunta: "mas RicBit, e a busca com hash table, ela não é O(1)?". Sim, ela é! Mas ela não usa comparações, e a nossa análise foi exclusivamente para métodos baseados em comparações. Com um acesso a uma hash você pode ganhar mais que 1 bit de informação por operação.

O limite da ordenação


Um outro exemplo é achar o limite dos algoritmos de ordenação. Suponha que eu tenho um vetor com elementos bagunçados e quero ordená-los usando comparações. Eu sei que cada comparação ganha 1 bit de informação, então só preciso saber quanta informação tem na saída.

Qual o resultado do algoritmo? Um vetor ordenado. Mas os valores do vetor em si são irrelevantes, o que importa mesmo é saber a ordem relativa entre eles. Essa ordem relativa pode ser expressa como uma permutação dos itens originais.

Quantas permutações existem? Se o vetor tem tamanho n, então existem n! permutações, logo a probabilidade é 1/n!. Fazendo as contas:

\begin{align*}I(m)&=\log\left(\frac{1}{p(m)}\right)=\log\left(1/\frac{1}{n!}\right)=\log \left(n!\right)\\&\sim\log\left(n^n e^{-n}\sqrt{2\pi n}\right)\\&\sim n\log n-n-\frac{1}{2}\log\left(2\pi n\right)\\&\sim O(n \log n)\end{align*}

Primeiro você usa a aproximação de Stirling, depois joga fora todos os termos assintoticamentes menores que o dominante. O resultado é que nós provamos que nenhuma ordenação pode ser melhor que O(n log n), sem precisar mostrar nenhum algoritmo!

Novamente, esse resultado só vale para ordenações baseadas em comparações. Sem usar comparações, você tem métodos como radix sort e ábaco sort que são melhores que O(n log n).

A análise por quantidade de informação


Esse método de análise da quantidade de informação pode ser utilizado em qualquer algoritmo, desde que você note um detalhe muito importante: o método acha um limite inferior para a complexidade, mas não prova que esse algoritmo existe! Tudo que conseguimos provar como ele é que, se o algoritmo existir, então ele não pode ser melhor que o limite achado.

por Ricardo Bittencourt (noreply@blogger.com) em 11 de May de 2015 às 19:35

May 10, 2015

PythonClub

Como otimizar suas consultas no Django - De N a 1 em 20 minutos

Essa semana fiz uma palestra em um BEV no Luizalabs. Resolvi falar sobre Django, pois é um framework que utilizamos na empresa para diversos projetos.

O objetivo é ensinar algumas técnicas simples e que auxiliam a diminuir o número de consultas que realizamos no banco de dados.

Os slides podem acessados aqui.

Então, vamos lá!

Overview

Geralmente nossa aplicação Django tem um arquivo models.py, que contém nossa representação das tabelas no banco de dados.

Para os próximos exemplos considere esse arquivo:

from django.contrib.auth.models import User
from django.db import models

class Cadastro(models.Model):
    # chave estrangeira para o usuário
    user = models.OneToOneField(User)

    # Outros campos
    # [...]

Veja o exemplo abaixo, é muito comum ver algo parecido em algum tutorial sobre Django.

>> Cadastro.objects.all()

Mas o que realmente acontece quando fazemos isso?

Para que a consulta aconteça, 5 elementos principais precisam interagir entre si. Os elementos são:

Model
Manager
QuerySet
Query
SQLCompiler

É importante entender o papel de cada um, para que sejamos capazes de atuar com assertividade.

Model
  • É uma representação da nossa tabela de dados, contém os campos e os comportamentos dos dados que estamos armazenando.
Manager
  • Está sempre acoplado a um model e é responsável por expor os métodos do QuerySet. Quando não declaramos nenhum manager, o Django cria por padrão o objects.
QuerySet
  • QuerySet é um conjunto de ações que serão realizadas no banco de dados (select, insert, update ou delete). Responsável por interagir diretamente com a Query.
Query
  • Cria uma estrutura de dados complexa com todos os elementos presentes em uma consulta. Gera uma representação SQL de um QuerySet.
SQLCompiler
  • Recebe as instruções SQL e realiza as operações no banco de dados.

Agora que conhecemos os 5 elementos principais, vamos falar sobre QuerySet, é com ele que vamos conseguir construir queries mais eficientes.

QuerySets são Lazy

Algo que é importante notar sobre o comportamento das QuerySets, são que elas são Lazy.

Mas o que é isso?

Imaginem as seguintes consultas:

>> cadastros = Cadastro.objects.all()
>> ativos = cadastros.filter(ativo=True)
>> inativos = cadastros.filter(inativo=True)

Sabe quantas consultas foram realizadas no banco de dados, por essas 3 linhas de código? NENHUMA. QuerySets podem ser:

  • Construídas
  • Filtradas
  • Limitadas
  • Ordenadas
  • Passadas comoo parâmetro

E nenhuma consulta será realizada no banco de dados.

Quando dizemos que as QuerySets são lazy, queremos dizer que as consultas só serão realizadas no banco de dados, quando pedimos!

Então, como pedimos?

# Quando solicitamos somente um resultado
>> Cadastro.objects.all()[0]

# Quando fazemos um slicing passando o parâmetro `step`
>> Cadastro.objects.all()[::2]

# Quando fazemos uma iteração
>> [cadastro for cadastro in Cadastro.objects.all()]

# Quando chamamos o método len()
>> len(Cadastro.objects.all())

# Quando chamamos o método list()
>> list(Cadastro.objects.all())

 # Quando chamamos o método bool()
>> bool(Cadastro.objects.all())

# Quando chamamos o método repr()
>> repr(Cadastro.objects.all())

Uma vez que entendemos como as consultas são realizadas no banco de dados, vamos aprender como resolver os problemas mais comuns quando se trata de consultas: relacionamentos.

Relacionamento OneToOne e ForeignKey

OneToOne e ForeignKey são os tipos de relacionamentos mais comuns no Django, estamos utilizando-os quase intuitivamente.

Imaginem o seguinte cenário:

Temos um loop e a cada iteração invocamos um atributo do models que é uma chave estrangeira para outra tabela.

>> cadastros = Cadastros.objects.all()
>> cadastros.count()
500 # Temos 500 cadastros no nosso banco de dados

# Fazemos uma iteração em todos os cadastros
>> for cadastro in cadastros:
    # realizamos um print com o nome do usuário para tal cadastro.
    # note que essa poderia ser qualquer outra operação, onde o atributo `user` fosse acessado
    print cadastro.user

Esse é um código simples e que geralmente não vemos problemas nenhum, mas iremos nos supreender com quantas queries são realizadas no banco de dados.

# https://docs.djangoproject.com/en/1.8/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running
>> from django.db import connection

>> cadastros = Cadastros.objects.all()

>> for cadastro in cadastros:
    print cadastro.user

>> print len(connection.queries)
501

Foram realizadas 501 consultas para iterar sobre 500 cadastros (1 consulta para retornar todos os cadastros e 1 consulta para cada vez que acessamos o atributo user). Isso ocorre, porque estamos acessando um atributo que é um relacionamento para outra tabela, cada vez que o Django acessa esse atributo uma nova consulta precisa ser realizada no banco de dados.

Isso é válido tanto para OneToOne e ForeignKey.

Como podemos resolver isso? Utilizando o método do QuerySet chamado select_related.

Relacionamento reverso

Por padrão o Django adiciona um relacionamento reverso quando sua tabela é referenciada por uma chave estrangeira.

Se não passar o parâmetro related_name, irá seguir o padrão <nome_tabela>_set

from django.contrib.auth.models import User
from django.db import models

class Cadastro(models.Model):
    user = models.OneToOneField(User)

    # Outros campos
    # [...]

class Endereco(models.Model):
    cadastro = models.ForeignKey(Cadastro)

    # Outros campos
    # [...]

Dessa forma, criamos um relacionamento reverso no model Cadastro, quando referenciamos ele numa chave estrangeira no model Endereco.

>> cadastros = Cadastro.objects.all()

>> for cadastro in cadastros:

    # Uma vez que o relacionamento foi criado, podemos acessá-lo
    print cadastro.endereco_set.all()

Se houvesse o parâmetro related_name, acessariamos pelo nome que criamos.

class Endereco(models.Model):
    cadastro = models.ForeignKey(Cadastro, related_name='enderecos')

    # Outros campos
    # [...]


>> cadastros = Cadastro.objects.all()
>> for cadastro in cadastros:
    # Acessando através do related_name
    print cadastro.enderecos.all()

Relacionamentos reversos não são possíveis com o select_related, por isso criou-se a partir da versão 1.4 o método prefetch_reĺated.

Inserir dados

Um problema para inserir dados é quando precisamos iterar sobre um conjunto grande de informações e criar um registro para cada linha, usos comum para importações e logs.

>> from django.db import connection
>> nomes = [
    'Lucas', 'Teste 01', 'Teste 02', 'Nome 3', # 1000 nomes no total
]

# Inserimos um cadastro para cada nome que existe na nossa variável `nomes`
>> for nome in nomes:
    Cadastro.objects.create(nome=nome)

>> print len(connection.queries)
1000

E acessamos 1000 vezes o banco de dados para criar todos os cadastros. Existe um método chamado bulk_create, que resolve nosso problema.

>> from django.db import connection
>> nomes = [
    'Lucas', 'Teste 01', 'Teste 02', 'Nome 3', # 1000 nomes no total
]

>> cadastros = []
>> for nome in nomes:
   cadastro = Cadastro(nome=nome)
   cadastros.append(cadastro)

# Insere todos os cadastros de uma só vez
>> Cadastro.objects.bulk_create(cadastros)
>> print len(connection.queries)
1

O bulk_create recebe uma lista de cadastros e cria realizando somente uma query. É bom notar que cada item dentro da variável cadastros é uma representação do modelo de Cadastro.

Não funciona para relacionamentos ManyToMany e que os signals do Django pre_save e post_save não serão chamados, pois o método save não é utilizado nesse caso.

Atualizar dados

Muitas vezes precisamos atualizar um conjunto de dados e fazemos isso através de uma iteração sobre cada objeto e alterando o campo que desejamos.

>> from django.db import connection

>> cadastros = Cadastro.objects.all()

>> for cadastro in cadastros:
    cadastro.notificado = True
    cadastro.save()

>> print len(connection.queries)
501 # 1 consulta para retornar os cadastros e 1 para cada item no loop

E cada vez que chamamos o método save uma nova consulta é realizada.

Para esses casos podemos utilizar o método update.

>> from django.db import connection

>> cadastros = Cadastro.objects.all()

>> cadastros.update(notificado=True)
500 # Retorna a quantidade de itens que foram atualizados

>> print len(connection.queries)
1

O update realiza um SQL Update no banco de dados e retorna a quantidade de linhas que foram atualizados.

Os signals do Django pre_save e post_save não serão chamados, pois o método save não é utilizado nesse caso.

Deletar dados

O mesmo comportamento existe quando estamos removendo alguns dados. Se fosse preciso apagar todos os dados, seria comum se alguém escrevesse assim:

>> from django.db import connection

>> cadastros = Cadastro.objects.all()

>> for cadastro in cadastros:
    cadastro.delete()

>> print len(connection.queries)
501 # 1 consulta para retornar os cadastros e 1 para cada item no loop

Porém, pode-se fazer dessa maneira:

>> from django.db import connection

>> Cadastro.objects.delete()

>> print len(connection.queries)
1

QuerySet possui um método chamado delete que apaga todos os dados retornados.

# Apagar somente inativos
>> Cadastro.objects.filter(inativo=True).delete()

# Apagar somente ativos
>> Cadastro.objects.filter(ativo=True).delete()

Deve-se lembrar, que assim como o update e o bulk_create os signals do Django não serão chamados, no caso do delete os signals são pre_delete e pos_delete.

Espero que tenha ajudado, até a próxima!

por Lucas Magnum em 10 de May de 2015 às 16:55

May 08, 2015

Galácia

Crônicas da Meia-Noite

Era alta noite quando acordei assustado com voz de gente conversando. Dei um salto da cama e corri pra porta para ver quem estava na minha sala. Mas para meu desespero a porta estava trancada. Tentei abrir seguidas vezes, cheguei a machucar o dedo. Nesse meio tempo minha esposa acordou assustada: “O que foi? O que foi?” Eu não respondi nada, meu coração estava disparado e eu não tinha acordado

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 08 de May de 2015 às 12:27

Não há oposição entre conhecimento das Escrituras e fogo do Espírito. Por isso as Sagradas Letras ensinam: "Mas quando o Espírito da verdade vier, ele vai guiar vocês a toda a verdade" (Jo 16.13a).

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 08 de May de 2015 às 12:27

May 07, 2015

Galácia

Lições da Minha Geração: Impérios e Teorias Econômicas

Vivi o bastante ver que um império econômico de uma empresa não dura para sempre. A Microsoft se ergueu e se tornou um imenso monopólio imbatível de software, mas olhei novamente e vi dois gigantes se levantarem rapidamente e tomar o lugar dela: Google e Facebook. Um terceiro também se levantou, mas este não era tão novo quanto os dois primeiros: a Apple — uma azarona, vinha sempre em segundo

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 07 de May de 2015 às 00:24

May 06, 2015

Galácia

Sobre Graça e Desobediência

Embora a salvação de Israel fosse um dom de pura graça e não pudesse ser negociada, ela podia, contudo, ser perdida pela desobediência. — Paul Hoff, O Pentateuco

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 06 de May de 2015 às 20:16

Aprenda Python

Solução do desafio

Eis aqui duas soluções para o exercício de Python que seu professor passou. 1) Versão resumida e malcriada. print("Estude!") 2) Versão extendida. Estude. Vá por mim: gaste tempo com tutoriais. A internet está cheio deles. Dúvidas, todos nós temos. Ninguém nasceu sabendo. Nem seu professor. Mas só dá pra ter dúvida sobre o que já tentamos resolver. Antes disso, é desconhecimento mesmo.

por Vinicius Assef (noreply@blogger.com) em 06 de May de 2015 às 03:41

AboutWilson.net

Captura de dados da Corrida de São Silvestre com Python—Parte 3

Dando sequência a série de posts onde eu faço a análise do dataset de campeões da Corrida de São Silvestre, vou desenvolver a análise exploratória através de gráficos que me ajudam e compreender melhor os dados e a levantar algumas questões interessantes como o desempenho da participação dos quenianos a partir da década de 90.

Mostro como este dataset foi construído no post Captura de dados da Corrida de São Silvestre com Python—Parte 1 e faço o tratamento e limpeza dos dados no post Captura de dados da Corrida de São Silvestre com Python—Parte 2.

Lembrando que o objetivo disso tudo é entender como o clima pode influenciar o desempenho dos corredores. Na Parte 2 dessa sequência eu criei a variável pace mas não disse porque. O pace é uma medida relativa que relaciona o percurso com o tempo, ou seja, é uma forma diferente de expressar a velocidade do corredor, também poderia ter utilizado a velocidade em km/min ou km/h, mas o pace é mais comum entre os corredores. Não poderia utilizar apenas o tempo porque o ele depende do percurso, e quanto maior o percurso maior o tempo, logo isso compromete qualquer comparação que eu queira fazer. A idéia neste post é explorar os dados, entender o seu comportamento e como posso trabalhar com eles para tentar responder a pergunta colocada. Para isso eu vou observar o comportamento do pace e verificar como ele se dá quando considero o sexo, mas antes vou apresentar uma contagem simples dos dados dos campeões que mostra como é possível extrair informações interessantes de um dataset simples como este.

In [1]:
%pylab inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import statsmodels.api as sm
import seaborn as sb
sb.set_context("talk")
import sys
print('python', sys.version)
print('pandas', pd.__version__)
print('statsmodels', sm.version.full_version)
Populating the interactive namespace from numpy and matplotlib
python 3.4.1 (default, May 19 2014, 13:10:29) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
pandas 0.16.0
statsmodels 0.6.1

Carregando os dados limpos e formatados

Começo carregando o arquivo CSV saosilvestre-lf.csv que são os dados limpos e formatados produzidos no último post. O dataset está limpo e formatado, os campos de data já estão no formato ISO e as colunas tempo e pace estão em decimais que representam os minutos.

In [2]:
ss = pd.read_csv("https://raw.githubusercontent.com/wilsonfreitas/saosilvestre/master/saosilvestre-lf.csv")

Vou remover as colunas: largada, chegada e horario; elas não vão me ser úteis aqui e além do mais poluem a vizualização.

In [3]:
ss = ss.drop(['largada', 'chegada', 'horario'], 1)
ss.head()
Out[3]:
nome pais corrida ano tempo percurso data pace sexo
0 Alfredo Gomes Brasil 1 1925 23.166667 6200 1925-12-31 12:00:00 3.736559 masculino
1 Jorge Mancebo Brasil 2 1926 22.533333 6200 1926-12-31 12:00:00 3.634409 masculino
2 Heitor Blasi Itália 3 1927 23.000000 6200 1927-12-31 12:00:00 3.709677 masculino
3 Salim Maluf Brasil 4 1928 29.183333 8800 1928-12-31 12:00:00 3.316288 masculino
4 Heitor Blasi Itália 5 1929 29.183333 8800 1929-12-31 12:00:00 3.316288 masculino

Explorando os dados

O dataset tem registros de campeões da Corrida de São Silvestre desde 1925, acredito que o primeiro ano da prova, com o tempo, sexo, país, distância do percurso e ano. Quando eu pego um dataset eu gosto de contar ocorrências, montar um histograma das variáveis, ou seja, entender o que eu tenho em mãos.

Dessa maneira a primeira ideia é contar a quantidade de campeões por país, ou seja, fazem um histograma por pais que seria uma variável categórica. No entanto, tenho a coluna sexo e gostaria de ver essa contagem agrupada por sexo. Gostaria ainda que em caso de empate, o país com maior quantidade de campeões masculinos viesse na frente.

Para fazer isso com o pandas eu preciso agrupar os dados por pais e sexo, fazer a contagem da variável sexo, isto é, sexo por país, calcular o total de campeões somando as quantidade de campeões por sexo e finalmente ordenar pelo total e pela quantidade de campeões homens antes de fazer o gráfico.

In [4]:
ss_pais = ss.groupby(['pais', 'sexo'])\
    .sexo\
    .count()\
    .unstack()\
    .fillna(0)
ss_pais['total'] = ss_pais['masculino'] + ss_pais['feminino']
ss_pais.sort(['total', 'masculino'], inplace=True)
ss_pais[['masculino', 'feminino']].plot(kind='bar', stacked=True);

Este é o gráfico com as quantidades agrupadas por sexo empilhadas, que apresenta exatamente um histograma da quantidade de campeões por país, trazendo a separação por sexo. Mas se as barras fossem de apenas 1 cor eu teria apenas o histograma de campeões.

O desempenho do Brasil é bom porque tem a maior taxa de participação na prova, diferente do Quênia que começou a marcar presença recentemente.

Outra forma de olhar o mesmo gráfico é colocando as barras lado a lado e assim é possível observar que apenas Portugal e Alemanha possuem mais campeãs que campeões e que México, Etiópia e Estados Unidos possuem quantidades iguais de campeões por sexo. Novamente fica claro que o Brasil possui um número excepcional de campeões porque realiza essa prova desde 1925 e se separar este gráfico por sexo, no feminino o Brasil cai para a terceira posição.

In [5]:
ss_pais[['masculino', 'feminino']].plot(kind='bar', stacked=False);

Evolução dos campeões ao longo dos anos

Outra coisa interessante de fazer é avaliar a evolução dos campeões por país ao longo dos anos. A ideia é fazer a contagem acumulada dos campeões ao longo dos anos.

In [6]:
ss.groupby(['ano', 'pais'])\
    .corrida\
    .count()\
    .unstack()[['Brasil', 'Quênia']]\
    .fillna(0)\
    .cumsum()\
    .plot();

Observando o gráfico acima vemos que o Brasil ficou quase 3 décadas sem campeões, voltando a acumular vitórias nos anos 80. Quênia começou a colecionar vitórias na década de 90 e desde então vem em um crescente aumento de vitórias. Observando as tendências destas curvas vejo que o coeficiente de crescimento do Quênia é maior do que do Brasil, indicando que em algum momento este país ultrapassará o Brasil em quantidade de campeões da corrida.

Vou separar os dados de Brasil e Quênia a partir de 1990, ano em que Quênia começou a ter vitórias, e tentar fazer uma previsão do ano em que o Quênia ultrapassará o Brasil em quantidade de vitórias, com base nestas tendências. Dessa forma vou ficar com 2 datasets e vou ajustar uma reta para cada conjunto de dados. O objetivo é extrapolar a tendência de vitórias dos países e tentar prever o ano em que as retas se cruzam, indicando que o Quênia atingiu a mesma quantidade de vitórias do Brasil.

In [7]:
ss_vic = ss.groupby(['ano', 'pais'])\
    .corrida\
    .count()\
    .unstack()\
    .fillna(0)\
    .cumsum()

ss_vic_br = ss_vic.loc[ss_vic.index > 1990, 'Brasil']
ss_vic_qn = ss_vic.loc[ss_vic.index > 1990, 'Quênia']

def fit(x, y):
    X = sm.add_constant(x)
    model = sm.OLS(y, X)
    return model.fit()

fit_br = fit(ss_vic_br.index.values, ss_vic_br.values)
fit_qn = fit(ss_vic_qn.index.values, ss_vic_qn.values)

O ajuste das retas me dá os coeficientes das equações do primeiro grau que representam as vitórias acumuladas em função dos anos. Para saber o ano em que Quênia ultrapassará o Brasil é necessário igualar as equações e calcular o ano.

In [8]:
diff = fit_br.params - fit_qn.params
print("Ano = {0}".format(int(-diff[0]/diff[1])))
Ano = 2035

De acordo com as retas ajustadas o ano será próximo de 2035. Ainda poderíamos incluir a variância dos coeficientes na conta e estimar a incerteza sobre esta estimativa.

Apenas para melhor ilustrar o que acabei de calcular vou criar um gráfico com os pontos e as retas e extrapolar as retas até 2040 para observar o ponto de cruzamento.

In [9]:
fig, ax = plt.subplots(figsize=(12,6))

x, y = fit_br.model.data.exog[:,1], fit_br.model.data.endog
ax.plot(x, y, 'ro', label="Brasil")

x = np.arange(1990, 2040)
y = fit_br.params[0] + fit_br.params[1]*x
ax.plot(x, y, 'r-')

x, y = fit_qn.model.data.exog[:,1], fit_qn.model.data.endog
ax.plot(x, y, 'go', label="Quênia")

x = np.arange(1990, 2040)
y = fit_qn.params[0] + fit_qn.params[1]*x
ax.plot(x, y, 'g-')

ax.axvline(2035, color='grey', linestyle='dashed')

ax.legend(loc='best');

Como é possível observar, as retas cruzam-se próximo de 2035.

Conclusão

Foi possível observar com este simples dataset como utilizar ferramentas de visualização e regressão para extrair um pouco do que os dados tem a dizer. Consegui enxergar a distribuição de campeões de 2 formas diferentes, podendo assim identificar aspectos diferentes na distribuição de campeões. A análise de evolução dos dados permitiu fazer uma previsão, onde considerando o histórico observado foi possível prever que próximo de 2035 teremos o Quênia com uma maior quantidade de vitórias na corrida de São Silvestre, obviamente se estas tendências se mantiverem.

Gosto de ver como é possível extrair informações relevantes com análises simples em datasets que cabem na memória do computador. Essa abordagem pode ser reproduzida mesmo para grandes conjuntos de dados onde uma amostra pode ser separada e analisada independentemente. A idéia de trabalhar com conjuntos de dados gigantes é um passo posterior, quando algumas hipóteses já foram levantadas em amostras menores. Para explorar os dados ferramentas visuais são muito interessantes, tem muita gente gerando bons resultados com Excel, eu particularmente não gosto. Na análise de dados é preciso ter parsimônia para saber interpretar o que os dados têm a dizer.

por Wilson Freitas em 06 de May de 2015 às 03:00

April 30, 2015

Galácia

A verdade é que se alguém não é uma bênção onde está, será uma maldição aonde quer que vá. — Erlo Stegen, Avivamento na África do Sul

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 30 de April de 2015 às 11:41

Calvinismo ou Arminianismo

Cada dia mais me convenço que ambas doutrinas apresentam falhas à luz das Escrituras.

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 30 de April de 2015 às 11:39

Governabilidade jamais justifica roubalheira. Não importa o partido.

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 30 de April de 2015 às 11:38

April 29, 2015

Galácia

De Quem Era o Sangue na Cruz?

[...] para pastorearem a igreja de Deus, que ele comprou com o próprio sangue dele. Atos 20.28.

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 29 de April de 2015 às 19:00

April 23, 2015

Filipe Saraiva

Cantor no KDE Applications 15.04

Com o lançamento do KDE Applications 15.04, o segundo release no novo modelo de lançamentos de softwares desenvolvidos no KDE – agora o desktop, conjunto de aplicações, e frameworks tem cada um seu próprio ciclo de release -, o software para programação científica Cantor chegou com várias novidades. Esse lançamento me deixa particularmente feliz pois trabalhei bastante em algumas delas. =)

Vamos ver o que o Cantor tem de novo?

Cantor portado para Qt5/KF5

cantor-kf5

Cantor Qt5/KF5 – visual usando Breeze, o novo tema padrão do KDE. Na imagem é possível ver o terminal, painel de gerenciamento de variáveis, destaque de sintaxe, complementação de código, e botões da tela padrão.

Trabalho que comecei no LaKademy do ano passado e fui desenvolvendo desde aquela data. Devo ter feito commits partindo de uns 5 países diferentes durante esse tempo.

A transição para essa nova tecnologia foi realizada com sucesso e até o momento não notamos nenhuma funcionalidade perdida ou bug crítico introduzido. Todos os backends e plugins foram portados, e alguns bugs que surgiram durante o port foram corrigidos.

Evidente que isso não garante que o software esteja livre de erros, portanto pedimos aos utilizadores que reportem quaisquer problemas no nosso gerenciador de bugs. De qualquer forma, o software está bastante estável.

Usuários do Cantor da versão Qt4 terão suas configurações migradas para o novo formato utilizado na versão Qt5/KF5 automagicamente após a primeira inicialização.

Backend para Python 3

Durante o Season of KDE 2014 orientei o colaborador Minh Ngo no projeto de desenvolvimento do backend para Python 3, fazendo com que o Cantor atingisse a marca de 10 backends diferentes!

cantor-backends

Tela de seleção de backend: Python 3 e seus outros nove irmãos

O backend de Minh utiliza comunicação via D-Bus para ligar o Cantor ao Python 3, uma arquitetura diferente da utilizada no Python 2 mas que já foi utilizada em outros backends, como no R.

O bacana é que agora o Cantor pode agradar tanto os pythonistas que usam Python 2 quanto os que já utilizam Python 3. Esperamos receber o feedback de vocês!

Ícone!

Cantor foi lançado originalmente em 2009, no agora velhinho KDE SC 4.4. Desde aquela época ele nunca teve um ícone próprio.

O lançamento da versão Qt5/KF5, que marca uma mudança substancial no desenvolvimento da aplicação, é um bom momento para também lançar um ícone próprio para o software, dando uma cara para ele.

Ícone do Cantor

Ícone do Cantor

E o resultado ficou excelente! Mostra bem a ideia do Cantor: um quadro negro para você ficar desenvolvendo seus cálculos enquanto coça a cabeça e pensa “e agora, daqui vai para onde?”. =)

Obrigado a Andreas Kainz e Uri Herrera, membros do VDG que desenvolveram o ícone!

Outras alterações e bugs corrigidos

Boa parte dos bugs introduzidos durante o processo de porting pro Qt5/KF5 foram corrigidos antes do release.

Há também algumas alterações menores que merecem ser citadas, como a mudança da categoria KNewStuff de “Python2″ para “Python 2″ e a adição da categoria “Python 3″; remoção do carregamento automático do módulo pylab; agora é possível executar comandos do Python com comentários; entre outras.

Para o log completo dos commits incluídos nesta versão, veja esta página.

Futuro

Para o futuro talvez o plano de maior prioridade seja remover a KDELibs4Support do Cantor. O Lucas já fez parte desse trabalho, e esperamos finalizá-lo para o próximo release.

Eu pretendo dar uma olhada na comunicação via D-Bus e verificar se ela seria uma boa saída para o backend do Scilab. Outra tarefa também programada é a reorganização dos assistentes para geração de gráficos nos backends do Python. E um objetivo de longo prazo é acompanhar a criação do projeto Jupyter, que será o futuro do IPython notebooks – tornar o Cantor compatível com o Jupyter pode ser uma boa forma de aumentar o número de potenciais usuários do software, além de fomentar a colaboração entre diferentes comunidades com interesse em programação científica.

Também irei aproveitar o lançamento dessa versão e escrever sobre duas formas de utilizar o Cantor – estilo terminal como o Matlab; e estilo notebooks, como o IPython. Aguardem!

Se você gostaria de auxiliar no desenvolvimento do Cantor, entre em contato para conversarmos sobre resoluções de bugs, desenvolvimento de novas funcionalidades, e mais. Ou contribua com a vakinha do KDE Brasil para realização do LaKademy 2015. Minha participação no evento será bastante focada no desenvolvimento do software, principalmente nos objetivos que listei acima.

por Filipe Saraiva em 23 de April de 2015 às 13:21

April 22, 2015

Magnun Leno

Hack ‘n’ Cast v0.13 - Hack ‘n’ Drops #001

Microsoft OpenSource, Netflix 8bits, detentos hackers e seu imposto de renda são assuntos hoje no Hack 'n' Cast.

Baixe o episódio e leia o shownotes

por Magnun em 22 de April de 2015 às 02:12

April 18, 2015

Kodumaro

Tipos em Cython

Ontem fiz uma pequena introdução ao Cython.

Cython é uma plataforma que traduz código Python para C e o compila em biblioteca compartilhada importável no próprio Python. A linguagem em si é um superset de Python, com tipagem estática ou dinâmica (duck-typing) e suporte a código especial que pode ser traduzido diretamente para C.

Uma parte importante de Cython é sua tipagem estática, mas os tipos pode ser um pouco diferentes de Python.

Há tipos específicos, como struct e enum, que são traduzidos diretamente para o equivalente C, e tipo de extensão (cdef class). Entre eles:

Tipo CythonTipo CCoerção para Python 3
boolPyLongObject *bool
bintintbool
size_tsize_tint
charcharint
unsigned charunsigned charint
intintint
longlongint
long longlong longint
floatfloatfloat
doubledoublefloat
long doublelong doublefloat
const char *const char *bytes
bytesPyBytesObject *bytes
const Py_UNICODE *const Py_UNICODE *str
unicodestruct PyUnicodeObjectstr
objectPyObject *object
listPyListObject *list
dictPyDictObject *dict
setPySetObject *set
tuplePyTupleObject *tuple
void *void *sem equivalência
struct Sstruct Sdict
enum Eenum Eint

Todos os modificadores C (unsigned, const, long, *…) são aceitos. Na coerção de tipos, também é aceito &. Se um valor numérico for recebido por uma variável do tipo object, será usado PyLongObject * (inteiro de tamanho arbitrário) ou PyFloatObject * (ponto flutuante, equivalente a double de C).

[]’s
ℭacilhας, La Batalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 18 de April de 2015 às 23:08

Aspectos – parte I

Um paradigma muito útil é a Programação orientada a Aspectos.

Consiste em separar e encapsular as funcionalidades de um código conforme sua importância.

Nesta primeira parte, abordaremos de forma simples tal separação e deixaremos o conceito de mixins para a parte II.

Vamos começar com um exemplo: imagine uma view que modifica o estado de um objeto, retornando um hash do novo estado:
@app.route('/people/<uuid>/', methods=['PATCH'])
def update_person(uuid):
person = db.person.find({ '_id': uuid }).first()
if not person:
raise Http404

try:
data = json.loads(request.data)
except ValueError:
return json.dumps({ 'error': 'invalid request' }), \
400, \
{ 'Content-Type': 'application/json' }

person.update(data)
db.person.save(person)

r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
s = ';'.join('{}:{}'.format(k, v) for k, v in r)

return json.dumps({ 'etag': md5(s).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }

A solução atende, mas é de difícil manutenção. Perceba que a função chamada update_person (atualiza pessoa) faz muito mais do que simplesmente atualizar os dados:
  • Recupera o documento do banco, retornando 404 se não existir;
  • Faz os parsing dos dados recebidos, retornando 400 em caso de erro;
  • Efetivamente atualiza o documento;
  • Serializa o objeto para a resposta;
  • Gera um hash da serialização;
  • Responde a requisição com formato conveniente.

Cada um desses passos é um aspecto do processo e pode ser isolado do restante.

Vamos então separar o primeiro aspecto: recuperação do documento.
def retrieve_person_aspect(view):
@wraps(view)
def wrapper(uuid):
person = db.person.find({ '_id': uuid }).first()
if not person:
raise Http404

return view(person)
return wrapper

@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
def update_person(person):
try:
data = json.loads(request.data)
except ValueError:
return json.dumps({ 'error': 'invalid request' }), \
400, \
{ 'Content-Type': 'application/json' }

person.update(data)
db.person.save(person)

r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
s = ';'.join('{}:{}'.format(k, v) for k, v in r)

return json.dumps({ 'etag': md5(s).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }

Agora a recuperação do documento está isolada, podendo inclusive ser usada em outras views. Nossa view já recebe o documento recuperado e não precisa lidar com o fato dele existir ou não.

Porém ainda temos muita coisa misturada. Por exemplo, a obtenção e parsing dos dados recebidos: isso caracteriza outro aspecto do código, que não a atualização do documento.

Podemos portanto, separá-los:
def parse_data_aspect(view):
@wraps(view)
def wrapper(person):
try:
data = json.loads(request.data)
except ValueError:
return json.dumps({ 'error': 'invalid request' }), \
400, \
{ 'Content-Type': 'application/json' }

return view(person, data)
return wrapper

def retrieve_person_aspect(view):
...

@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
@parse_data_aspect
def update_person(person, data):
person.update(data)
db.person.save(person)

r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
s = ';'.join('{}:{}'.format(k, v) for k, v in r)

return json.dumps({ 'etag': md5(s).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }

A função update_person já está muito mais limpa: atualiza o documento, serializa e retorna o hash, mas ainda faz coisas demais. Vamos separar o tratamento do retorno:
def respond_etag_aspect(view):
@wraps(view)
def wrapper(person, data):
response = view(person, data)
return json.dumps({ 'etag': md5(response).hexdigest() }), \
200, \
{ 'Content-Type': 'application/json' }
return wrapper

def parse_data_aspect(view):
...

def retrieve_person_aspect(view):
...

@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
@parse_data_aspect
@respond_etag_aspect
def update_person(person, data):
person.update(data)
db.person.save(person)

r = [(str(k), repr(v)) for k, v in person.iteritems()]
r.sort()
return ';'.join('{}:{}'.format(k, v) for k, v in r)

As coisas estão ficando cada vez mais separadas. A única coisa que a função update_person faz agora além de atualizar o documento é serializá-lo. Isso também pode ser isolado:
def serialize_person_aspect(view):
@wraps(view)
def wrapper(person, data):
response = view(person, data)
r = [(str(k), repr(v)) for k, v in response.iteritems()]
r.sort()
return ';'.join('{}:{}'.format(k,v) for k, v in r)

def respond_etag_aspect(view):
...

def parse_data_aspect(view):
...

def retrieve_person_aspect(view):
...

@app.route('/people/<uuid>/', methods=['PATCH'])
@retrieve_person_aspect
@parse_data_aspect
@respond_etag_aspect
@serialize_person_aspect
def update_person(person, data):
person.update(data)
db.person.save(person)
return person

Perceba que, com a separação dos aspectos em funções distintas, o código ficou muito mais semântico:
  • retrive_person_aspect apenas recupera o documento do banco;
  • parse_data_aspect apenas faz o parsing dos dados recebidos;
  • respond_etag_aspect apenas gera o formato correto da resposta;
  • serialize_person_aspect apenas serializa o documento;
  • finalmente, update_person apenas atualiza o documento.

Observações

  • db é um objeto de banco de dados MongoDB, apenas para fim de exemplo.
  • app é uma aplicação Flask, apenas para fim de exemplo.
  • A ordem dos decoradores é importante.
  • Os imports foram omitidos:
import json
from functools import wraps
from hashlib import md5

Na parte II abordaremos mixins.

[]’s
Cacilhας, La Batalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 18 de April de 2015 às 21:05

RLock

Dando continuidade o artigo sobre thread, um recurso muito útil é lock reentrante.

Lock reentrante é uma variação de lock que pode ser realocado múltiplas vezes pelo mesmo thread e não pode ser liberado por outro thread. É muito útil em funções recursivas, mas funciona também para garantir que o lock seja alocado e liberado pelo mesmo thread.

A fábrica (factory) para criar locks reentrantes é threading.RLock.

É preciso tomar cuidado para que todos os threads compartilhem o mesmo lock, senão ele se torna inútil:
lock = RLock()

thr1 = Thread(target=func1, args=(lock, ))
thr2 = Thread(target=func2, args=(lock, ))
thr3 = Thread(target=func3, args=(lock, ))

Dentro da função, é preciso alocá-lo (acquire) no inicío e liberá-lo (release) ao final. Por exemplo:
def func1(lock):
lock.acquire()
try:
# executa o procedimento
...
finally:
lock.release()

Protegendo um objeto mutável

Uma utilidade para o lock reentrante é proteger métodos que alterem o conteúdo de um objeto.

Imagine que temos uma classe Person com dados, como identity_code (CPF) que podem sofrer alterações em threads diferentes (sei que não é uma boa abordagem, mas apenas como exemplo).

Podemos criar um decorador que torna um método thread-safe usando lock reentrante:
def lock(wrapped):
lock_ = RLock()

@wraps(wrapped)
def wrapper(*args, **kwargs):
with lock_:
return wrapped(*args, **kwargs)

return wrapper

Esse decorador pode ser usado nos setters de cada propriedade:
class Person(object):

...

@property
def identity_code(self):
return self.__identity_code

@identity_code.setter
@lock
def identity_code(self, value):
self.__identity_code = value

...

Na verdade essa abordagem não resolve 100% o problema, mas já reduz muito a ocorrência de bugs.

Protegendo qualquer objeto

Porém a abordagem acima apenas protege parcialmente o objeto e não funciona para classes de terceiros.

Outra abordagem é usar um lock para todo o objeto, tanto leitura quanto gravação, agnóstico a qual objeto está sendo protegido. Assim, não há necessidade de usarmos propriedades.

Vamos criar uma classe para trancar qualquer objeto:
class ObjectLocker(object):

def __init__(self, obj):
self.__obj = obj
self.__lock = RLock()

def __enter__(self):
self.__lock.acquire()
return self.__obj

def __exit__(self, etype, exc, traceback):
self.__lock.release()

No código a instância dessa classe será passada para os threads, que terá de usar with para acessar o objeto original.

Ao usar with, o objeto original será trancado para o thread atual e liberado ao final.

A passagem será:
locker = ObjectLocker(Person(...))
thr = Thread(target=func, args=(locker, ))

Dentro da(s) função(ões) func a instância de Person deve ser acessa da seguinta forma:
with locker as person:
name = person.name
person.identity_code = data['identity_code']

Espero que os exemplos tenham sido úteis.

[]’s
Cacilhας, La Batalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 18 de April de 2015 às 21:00

Ordem de chamada dos métodos de inicialização

Quando você cria e instancia uma classe em Python, muita coisa acontece e acho que nem todos estão familiarizados com os passos.

Vamos dar uma olhada na sequência.

Criação da classe

Quando você cria uma classe com o statement class, a primeira coisa que acontece é o construtor (__new__) da metaclasse (por padrão type) ser chamado.

O construtor recebe como parâmetros a própria metaclasse, o nome da classe (str), uma tupla contendo as classes base da classe criada e um dicionário com métodos e atributos declarados no corpo da classe.

Caso você sobrescreva o construtor da metaclasse, ele precisa retornar o objeto instanciado, que você obtém do construtor da classe pai da metaclasse.

Em seguida o método de inicialização (__init__) da metaclasse é chamado, recebendo como parâmetros o retorno do construtor, o nome da classe, a tupla de classes base e o dicionário de métodos e atributos.

É recomendável não sobrescrever o construtor da metaclasse. Qualquer procedimento pode ser tranquilamente executado nos métodos e inicialização e de chamada.

Instanciação da classe

Quando você instancia a classe, o primeiro método a ser chamado é o método de chamada (__call__) da metaclasse. Ele recebe como parâmetros a classe e quaisquer parâmetros passados no comando de instanciação.

Em seguida é evocado o construtor da classe, recebendo a classe e quaisquer parâmetros passados no comando de instanciação.

É obrigatório que a instância criada pelo construtor de super seja retornada, caso o construtor seja sobrescrito.

Após o construtor, o método de inicialização da classe é chamado, recebendo como parâmetros o retorno do construtor e quaisquer parâmetros passados no comando de instanciação.

Chamando a instância

Caso o método de chamada seja implementado na classe, a instância é “chamável” (callable). Na chamada o método de chamada é executado recebendo a instância e quaisquer parâmetros passados na chamada da instância.

Quem é quem

Um pequeno código apenas com boilerplates que não executam nada, com o único objetivo de demonstrar onde fica cada método citado:
class Metaclasse(type):

def __new__(meta, name, base, dict_):
""" Este é o construtor da metaclasse """
return type.__new__(meta, name, base, dict_)

def __init__(cls, name, base, dict_):
""" Este é o método de inicialização da metaclasse """
type.__init__(cls, name, base, dict_)

def __call__(cls, *args, **kwargs):
""" Este é o método de chamada da metaclasse """
return type.__call__(cls, *args, **kwargs)


class Classe(object):
__metaclass__ = Metaclasse

def __new__(cls, *args, **kwargs):
""" Este é o construtor da classe """
return super(Classe, cls).__new__(cls)

def __init__(self, *args, **kwargs):
"""
Este é o método de inicialização da classe.
Como ela herda de object, não há necessidade de
chamar super, mas quando houver, a forma é:
super(Classe, self).__init__(*args, **kwargs)
"""

def __call__(self, *args, **kwargs):
""" Este é o método de chamada da classe """
return None

[update 2015-04-18]Esta é a versão do código acima em Python 3:
class Metaclasse(type):

def __new__(meta, name: str, base: tuple, dict_: dict) -> type:
""" Este é o construtor da metaclasse """
return type.__new__(meta, name, base, dict_)

def __init__(cls, name: str, base: tuple, dict_: dict):
""" Este é o método de inicialização da metaclasse """
type.__init__(cls, name, base, dict_)

def __call__(cls, *args, **kwargs) -> object:
""" Este é o método de chamada da metaclasse """
return type.__call__(cls, *args, **kwargs)


class Classe(object, metaclass=Metaclasse):

def __new__(cls, *args, **kwargs) -> object:
""" Este é o construtor da classe """
return super().__new__(cls)

def __init__(self, *args, **kwargs):
"""
Este é o método de inicialização da classe.
Como ela herda de object, não há necessidade de
chamar super, mas quando houver, a forma é:
super().__init__(*args, **kwargs)
"""

def __call__(self, *args, **kwargs) -> None:
""" Este é o método de chamada da classe """
return None
[/update]

Dois dedos de prosa sobre método destruidor

O método destruidor (__del__) não é chamado quando o objeto perde todas as referências ativas, mas sim quando é coletado pelo garbage collector (gc).

Como o gc não tem hora certa para rodar e seu comportamento varia muito de uma implementação de Python para outra, não é recomendável confiar nele para executar procedimentos críticos.

O que você pode fazer é usá-lo para garantir determinados estados que podem ter sido esquecidos ou perdidos depois que a instância ficou sem referências.

Observações finais

As assinaturas do construtor e do método de inicialização da classe devem ser rigorosamente iguais.

[update]
Um detalhe importante é que, se o método de inicialização for sobrescrito alterando sua assinatura, não há necessidade de sobrescrever o construtor, porém se o construtor for sobrescrito alterando sua assinatura, é obrigatório que o método de inicialização também seja sobrescrito.

Detalhes da linguagem…
[/update]

A chamada do método de chamada da classe pai da meta classe deve passar os parâmetros esperados pelos argumentos nas assinaturas do construtor e da inicialização da classe. No exemplo acima, esta chamada (precedida por return) é:
type.__call__(cls, *args, **kwargs)

[update]
Um detalhe que esqueci de mencionar é que é justamente nessa chamada que o construtor e o método de inicialização são evocados.
[/update]

Os parâmetros passados são os esperados nas assinaturas citadas.

[]’s
Cacilhας, La Batalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 18 de April de 2015 às 20:54

April 15, 2015

Kodumaro

Uma brincadeira rápida



Um jeito divertido de calcular Fibonacci usando NumPy:

from numpy import matrix, long as np_long

def fib():
m = matrix('1, 1; 1, 0', dtype=np_long)

def fib(n):
return (m ** n)[0, 0]
return fib
fib = fib()

[]’s
Cacilhας, La Batalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 15 de April de 2015 às 04:02

April 08, 2015

Galácia

Startup é uma palavra da moda. Isso não é uma crítica, apenas um fato. Li num artigo de um site americano que ainda não existe uma definição precisa desse vocábulo. Então, com base no que ando lendo, aqui vai a minha: startup é uma empresa iniciante, geralmente voltada para tecnologia.

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 08 de April de 2015 às 13:22

April 06, 2015

PythonClub

Django - 3 anos em 10 minutos

Em março de 2012 foi lançada a versão 1.4 e por aqui que nossa jornada começa, o objetivo não é entrar em detalhes em todas as features que foram implementadas e sim um overview sobre as que considero mais importantes para nosso dia a dia.

Versão 1.4 (Há 3 anos)

Lançada em Março de 2012, suporta Python 2.5 >= 2.7.

Foi a primeira versão LTS (long-term support), ou seja, ela recebeu correções e atualizações de segurança por pelo menos 3 anos após à data de lançamento.

É a primeira versão a permitir o uso de custom project template e tornar o arquivo manage.py o que conhecemos hoje.

Foi a primeira versão a suportar o testes feitos com frameworks que utilizam o browser como o Selenium.

Algumas outras coisas legais foram:

  • bulk_create para criar vários objetos de uma só vez.
  • prefetch_related para realizar joins em tabelas que possuem relações many-to-many.
  • reverse_lazy que permite fazer reverse antes das configurações de URL serem carregadas.

Versão 1.5 (Há 2 anos)

Lançada em Fevereiro de 2013, suporta Python 2.6.5 >= 2.7 (Python 3 - Experimental).

A versão 1.5 ficou bem conhecida pela reformulação na aplicação de autenticação, é possível customizar um usuário conforme nossas necessidades.

É possivel também passar os campos que você gostaria de atualizar quando for salvar um objeto.

Algumas outras coisas legais foram:

  • verbatim template tag para casos onde você deseja ignorar a sintaxe do template.
  • novos tutoriais foram inseridos para ajudar iniciantes e existe também uma seção Tutoriais Avançados

Versão 1.6 (Há 1 ano e meio)

Lançada em Novembro de 2013, suporta Python 2.6.5 >= 3.3. (Python 3!!!!)

A versão 1.6 alterou um pouco do layout padrão dos projetos que estávamos acostumados, para nossa alegria o admin.py é adicionado por padrão na aplicação :)

Transações possuem autocommit habilitado por padrão!

Os testes são localizados em qualquer arquivo que possua o nome começando com test_ (Antigamente os testes só eram encontrados nos arquivos models.py e tests.py)

Algumas outras coisas legais foram:

  • check comando para validar se suas configurações estão compatíveis com a versão do django.

Versão 1.7 (Há 8 meses)

Lançada em Setembro de 2014, suporta Python 2.7 >= 3.4.

Um novo conceito de migrações foi implementado, até o momento a maioria utilizava o South, nessa versão tudo é built-in.

Para criar uma aplicação não é necessário mais conter o arquivo models.py.

O conceito de aplicação foi atualizado e existem vários novas maneiras de se customizar seus dados :)

O comando check foi evoluído e agora realiza uma varredura quase completa no seu código para identificar possíveis problemas.

Versão 1.8

Lançada em Abril de 2015, a versão 1.8 introduz várias features legais!

É a segunda versão LTS (long-term support), ou seja, vai receber correções e atualizações de segurança por pelo menos 3 anos após à data de lançamento.

Agora há a possibilidade de utilizar várias linguagens(engines) de templates, ou seja, você pode usar simuntaneamente (não no mesmo arquivo) a Django Template Language ou Jinja2. Há uma API padronizada para quem quiser adicionar suporte para outras linguagens de template no futuro. Há um guia de migração .

Novos campos foram introduzidos como UUIDField e DurationField e ainda tem mais!

O Model._meta API foi totalmente refatorado e padronizado. O Model._meta API foi incluida no Django 0.96 e serve para obter informações sobre campos do Model, contudo, essa api era considerada de uso privado, e não tinha qualquer documentação ou comentários. Agora com tudo padronizado, abre uma gama de novas opções para criar apps plugaveis que fazem coisas com Models arbitrarios.

Algumas outras coisas legais foram:

  • O comando de gerenciamento inspectdb agora suporta fazer engenharia reversa tambem de Database Views (nas versões anteriores, o inspectdb inspecionava somente tabelas, mas não conseguia "ver" as views).
  • Adição/Melhoria de Query Expressions, Conditional Expressions, and Database Functions . Isso adiciona muito mais flexibilidade para fazer pesquisas mais complexas no banco de dados.

Há várias outras ótimas melhorias que omiti, veja o release note completo.

O Futuro

Versão 1.9 (Com lançamento previsto para Outubro de 2016)

O Django 1.8 mal foi lançado, e já há algumas novidades que talvez venham no Django 1.9.

Muito provavelmete, o Django 1.9 vai adicionar os tão esperados Campos Compostos . Isso vai permitir fazer coisas mais complexas, como ter um campo Dinheiro, que "sabe" como fazer conversões de moeda (ex. Real para Dolar).

Tambem existe uma expectativa que o tema django-flat-admin para o Admin seja integrado no Django 1.9, virando o tema padrão. O django-flat-admin somente modifica o CSS, nenhuma tag HTML é alterada em relação ao HTML original do Admin, então ele é relativemente compativel (desde que você não tenha incluido customizações no CSS do Admin). Os core developers do Django estão tratando desse assunto neste tópico

Veja o Roadmap do que vem por ai no Django 1.9

por Lucas Magnum em 06 de April de 2015 às 14:55

April 05, 2015

Rodrigo Delduca

March 31, 2015

Eric Hideki

Tudo o que um iniciante em programação python deveria saber

De uns tempos para cá ando enrolado. Tão enrolado que esqueço de atualizar sobre o que ando fazendo. Desde Dezembro aconteceram algumas coisas e que estão espalhadas por aí, e acredito que possa ajudar alguém (nunca se sabe).

Em dezembro tivemos o FalaAÊ, evento online para falar sobre qualquer coisa. Falamos sobre comunidade, Geolocalização, Pyladies e várias outras coisas.


Janeiro palestrei na Campus Party falando sobre desenvolvimento com Bottle.


E também vários Hangouts

Mesa de bar com Python – Segunda Edição


Web2py Faq


Python para iniciantes


Mesa de bar – Primeira Edição


Mesa de bar – Segunda edição


Palestra sobre comunidade no Grupy-SP

DSC00017

IMG_20150314_121041961


por Eric Hideki em 31 de March de 2015 às 23:52

Kodumaro

Gxref

Glider
Estou experimentando o ambiente gxref, parte do XPCE do SWI-Prolog, e tenho algumas impressões para compartilhar.


Editor de texto

O editor de texto, PceEmacs, é muito ruim. Baseado na porcaria do Emacs, possui comandos muito verborrágicos, é dolorosamente dependente do mouse e o search-replace é uma bosta.

Para quem está acostumado com o Vim, de comando curtos e eficientes, que não precisa do mouse pra nada – você não precisa tirar a mão do teclado enquanto edita –, o PceEmacs é um retorno às cavernas.

A única vantagem é que o syntax highlight é bastante eficiente.

File info

A aba File info é simplesmente maravilhosa! Relaciona todos os predicados, onde eles são usados e que predicados de outros módulos são usados no módulo atual.

É uma ferramenta caída dos céus para depurar erros de sintaxe e até mesmo de lógica.

Dependencies

A aba Dependencies exibe um grafo das relações entre os módulos que deixa muito claro como sua imagem se comporta.

Conclusão

O XPCE+gxref perde pontos pelo editor de texto ruim e por depender do X (não roda nativo no Mac OS X), mas todo o resto é muito eficiente, merecendo uma nota, de zero a dez, oito (8).

[]’s
ℭacilhας, ℒa ℬatalema

por noreply@blogger.com (ℭacilhας, ℒa ℬatalema) em 31 de March de 2015 às 02:22

Rodrigo Delduca

March 30, 2015

Thiago Avelino

Church Vim

Church Vim

Vim was originally an extensible text editor written by Bram Moolenaar, but it became a way of life and a religion. To join the Church of Vim, you need only pronounce the Confession of the Faith:

There is no system but GNU, and Linux is one of its kernels.

Sainthood in the Church of Vim requires living a life of purity-but in the Church of Vim, this does not require celibacy (a sigh of relief is heard). Being holy in our church means exorcizing whatever evil, proprietary operating systems have possessed computers that are under your control, or set up for your regular use; installing a holy (i.e., wholly) free operating system (GNU/Linux is a good choice); and using and installing only free software with and on the system. Note that tablets and mobile phones are computers and this vow includes them.

Join the Church of Vim, and you too can be a saint!

People sometimes ask if St IGNUcius is wearing an old computer disk platter. That is no computer disk, that is my halo — but it was a disk platter in a former life. No information is available about what kind of computer it came from or what data was stored on it. However, you can rest assured that no non-free software is readable from it today.

In addition to saints, the Church of Vim also has a hymn - the Free Software Song. (No gods yet, though.) Hear the song sung by Saint IGNUcius himself.

Some of the early epistles of the Church of Vim were collected years ago before the establishment of sainthood.

Saint IGNUcius says: Some people don't realize that Saint IGNUcius is Saint IGNUcius's way of not taking himself too seriously. Therefore,

Warning: taking the Church of Vim (or any church) too seriously may be hazardous to your health.

Inspired by St IGNUcius

por avelino em 30 de March de 2015 às 16:23

March 26, 2015

Flavio Ribeiro

It's time to move on

After almost 4 years immersed in a lot of exciting challenges, it's time to move on.

Sunset by instagram.com/fanydantas

Sunset from my balcony by Fany

When I started working at Globo.com, I realized that every if that I wrote would run in hundreds of thousands of computers around the country. Until then, I've only worked on small startups in the Northeast of Brazil where the impact of their products have smaller proportions. Describing this feeling is hard. I would argue that, for a software developer like me, knowing that your code is being used is as rewarding as receiving real money.

During the time at Globo, I faced huge projects. As we've worked developing software for the video delivery stack, almost every big transmission - like elections or FIFA World Cup - had their special issues and corner cases. Following the trend, we developed a live video streaming stack from scratch and seeing this new infrastructure beating the concurrent users peak twice was priceless.

United Colors of WebMedia

Part of WebMedia Team during the World Cup. We were still believing we would be Champions.

I could also work with the most awesome engineers I've ever met. Sometimes I felt that the lunch time was kind of a graduate class (actually, I should had taken a pencil and paper to it). The discussions ranged from writing tests to how telecommunications works.

Since the beginning of last year I've worked full time on an open source project which was the real reason for me to get up out of bed to go to work and sometimes even rise up early to answer one issue or fix a bug that someone dropped on github. I've already said this here but...Damn, how awesome is working with FOSS!

About 6 months ago I was catching myself visiting LinkedIn, hypothetically looking for a new job, and this made me think that it was time to move on. I've read somewhere that when you're feeling attracted by other opportunities, it's a big red signal that you're not happy anymore and need a change. I've applied to some companies and met a lot of great guys during the interviews but the last one was mind changing.

If you get the chance to work overseas, take it. There is never a right time. And we always regret the things we don’t do far more than the things we do. (Shane Rodgers)

I'm joining the Video Team at The New York Times. Next week I'm heading to New York to visit the office and meet my coworkers. I must say that I'm totally anxious and excited about it, but a lot of things need to happen before I move definitively to America. Until there, I'll work remotely (which will be a challenge apart).

I hope that everything that I lived these years were only the beginning and I'm sure I have a lot of things to learn. I'll try hard to publish more posts regarding the obstacles I'll face and I hope you'll be cheering for me.

Related Links:
Hey Feio, how is working at The Times?
What I whish I knew when starting out as a Software Developer
The career advice I wish I had at 25

por Flávio Ribeiro em 26 de March de 2015 às 12:36

Filipe Saraiva

Ubuntu: traidor do movimento ou de (ingênuas) expectativas?

Capa do Ubuntu 4.10 Warty Warthog – primeira versão da distro

Quem acompanha a comunidade software livre brasileira deve estar a par das recentes discussões sobre o pedido para não recomendação e não instalação do Ubuntu no FLISOL, Festival Latino-Americano de Instalação de Software Livre, evento em rede voltado para instalar distros GNU/Linux e outros softwares livres. As discussões começaram a partir de um abaixo-assinado lançado pelo Anahuac, continuaram na lista PSL-Brasil e FLISOL, e culminaram com a recomendação do coordenador brasileiro do evento, Thiago Paixão, para que os grupos brasileiros boicotem o Ubuntu – um eco um tanto tardio de um pedido que o Stallman fez em 2013.

Antes de partir para o texto em si cabe duas declarações para contextualizar os leitores sobre os posicionamentos do autor: 1) Não uso Ubuntu e nem tenho qualquer relação com a Canonical. Minha história com essa distro durou apenas 3 semanas no ano de 2006 – voltei pro Kurumin porque não gostei do Gnome (desculpem amigos Gnomos :)); 2) De fato o spyware que o Ubuntu instala por padrão nos computadores do usuário é algo sim muito nocivo, e apenas esse motivo justificaria o pedido de não recomendação do sistema em qualquer roda de ativistas de software livre.

Isso exposto me preocupa muito o andamento que as discussões tomaram, principalmente os argumentos que apontam o Ubuntu como uma distro que não é software livre. Esses argumentos no geral se embasam em duas premissas: os blobs binários e o fato da Canonical ter “virado as costas pra comunidade”, ou algo do gênero.

Sobre a questão dos blobs binários infelizmente isso é um problema que os desenvolvedores do kernel Linux e, por extensão, as principais distros, se defrontam. Muitos fabricantes de hardware só disponibilizam os drivers para Linux num formato binário, sem código-fonte. Os desenvolvedores do Linux tiveram que escolher: é melhor suportar o hardware com software privativo ou não suportar o hardware? Eles escolheram a primeira opção e isso acabou desembarcando nas distros em geral.

Portanto, blobs binários são entregues com todas as distros mais conhecidas. Não é exclusividade do Ubuntu: o Debian tem, o Fedora, OpenMandriva, Mageia, OpenSUSE, Chakra, Arch, e muitas outras. A FSF mantém uma página explicando isso, e por esse motivo recomenda apenas a instalação de distros que eliminaram esses blobs, como o Trisquel.

Mas aí a questão que os desenvolvedores do kernel se perguntaram continua, e para mim ela é bastante complexa: é melhor instalar os blobs e ter o hardware funcionando ou ficar sem poder utilizar esse hardware? Claro que é melhor hardware que funciona com driver livre, mas as vezes o usuário não tem acesso a esse tipo de dispositivo. Para mim é melhor ter um sistema operacional 90% livre do que entregar um pen drive com alguma distro recomendada pela FSF para um usuário com hardware não suportado e dizer “da próxima vez traga um computador que não precise de blobs pra funcionar corretamente”, como chegaram a propor.

Mas voltando ao tema, por que apenas o Ubuntu será condenado por uma prática comum às demais distros?

O segundo ponto seria a Canonical destratar a sua comunidade. Nos últimos anos temos visto um movimento forte da empresa em dar foco ao Ubuntu e implementar uma certa visão ao sistema operacional que o tornaria compatível com smartphones, televisões, tablets e outras mais. Nesse sentido vimos a Canonical tirando suporte (e por consequência demitindo funcionários) de diversos remixes do Ubuntu mantidos oficialmente por ela, como o Kubuntu, Xubuntu e Edubuntu; a criação de um ambiente desktop próprio, o Unity, após o pessoal do Gnome não ter se mostrado muito receptivo às modificações que a companhia gostaria de ver; a criação de um servidor gráfico próprio, o Mir, que foi anunciado com muitas críticas – equivocadas – ao servidor que demais comunidades e empresas estão desenvolvendo, o Wayland; entre outras.

Todas essas medidas deixaram insatisfeitos parte da comunidade Ubuntu, em especial o pessoal mais velho que viu a distro crescer desde o começo; entretanto, estas iniciativas parecem não ter afetado uma certa base de usuários mais jovem. De qualquer forma, o ponto aqui é que todas as medidas relacionadas a software que a Canonical tomou são software livre. O código está disponível, tanto do Unity quanto do Mir, e é até irônico que as principais licenças que utilizam seja a versão 3 da GPL e LGPL.

É importante que saibamos separar nossas expectativas, gostos e frustrações daquilo que se espera de um movimento. Infelizmente (e coloco um infelizmente sem ironia), Stallman nunca colocou que o software livre seria um movimento antiempresarial. Para ele, software livre é sobre respeito ao usuário, que este tenha os meios de entender o que está acontecendo na sua máquina, e que não seja controlado por ela. Não é sobre julgamentos morais se uma empresa baseada em software livre agiu certo ou errado quando tomou tal direcionamento, a despeito ou não de sua comunidade.

O Ubuntu sempre foi uma distro com uma empresa por trás – a Canonical. Não há porque se frustrar quando a empresa *dona* do projeto resolve dar direcionamento diferente do que os usuários desejavam. Empresas fazem isso. Parece que o pessoal levou a sério demais o slogan Linux for human beings. É muito comum vermos empresas adotarem a prática dos slogans bonitinhos, mas só ingenuidade para acreditar que uma empresa é realmente aquilo que a propaganda dela apresenta. É como pensar que o Pão de Açúcar realmente se importa com você quando pergunta “o que faz você feliz?”; ou que o McDonald’s é aquela tia distante que recebe uma visita surpresa sua e fala, maternal, “que bom que você veio”. Ou que para a Coca-Cola não importa que você tome mais e mais a água-com-gás-açúcar-e-toxinas deles, mas sim que você “abra a felicidade”.

Qual a solução para isso? Contribua com distros realmente comunitárias. Estive na mesa crossdistro no FISL15 como membro da comunidade Mageia e comentei sobre isso. Não critico quem contribui com distros gerenciadas por empresas, cada um faz o que quer, mas eu não faço isso. Por esse motivo, quando o Mageia nasceu como uma distro comunitária a partir do fork do Mandriva, pulei junto com o grupo (e também porque havia um certo ar de “fábrica ocupada” no Mageia que dava um charme adicional ao projeto e foi fundamental para eu decidir seguir com eles =)). Em distros comunitárias há transparência e regras de governança estabelecidas que permitem que quem de fato dita as regras da distro é sua comunidade, e não o gerente de projetos de uma empresa qualquer. Há várias distros assim, como o Debian, exemplo mais famoso. Só seguir em frente e trabalhar para um projeto que você realmente se reconheça nele.

Pensando o software livre em termos de projeto, temos que entender que software livre se relaciona ao código, não ao gerenciamento.

Sobre o Ubuntu, espero que a Canonical realmente cumpra a promessa de remover o spyware na próxima versão da distro, 15.04, que deve sair 2 dias antes do FLISOL (!!!). Para mim, quando isso acontecer, a distro voltará a ser como outra distro qualquer, com seu gerenciamento próprio, suas metodologias, comunidade e etc, mas acima de tudo escrevendo código utilizando licenças livres e lançando software que respeita seus usuários.

Sobre a comunidade de software livre, espero que possamos perceber que não há um problema específico do Ubuntu aqui, e que então sigamos em frente nos focando em alguma das outras intricadas questões que a sociedade nos coloca dia após dia.

Filipe Saraiva é desenvolvedor na comunidade KDE e empacotador na comunidade Mageia

 

por Filipe Saraiva em 26 de March de 2015 às 00:37

March 23, 2015

Magnun Leno

Hack ‘n’ Cast v0.12 - Sobrevivendo a Uma Falha de HD

Se tem algo que é certo, e que um dia vai acontecer com todos nós é a morte... de um HD, seja ela por mau uso ou por uma falha de hardware.

Baixe o episódio e leia o shownotes

por Magnun em 23 de March de 2015 às 17:42

March 13, 2015

Osvaldo Santana Neto

Mercado saturado: isso importa?

Earth

Assine a minha newsletter quinzenal O Melhor da Internet e receba um resumo dos melhores materiais sobre Python, Django, Carreira e Empreendedorismo.


Esse artigo saiu inicialmente na O Melhor da Internet.

Como me envolvi em vários eventos voltados para empreendedores nos últimos anos recebo e-mails de várias pessoas que pretendem desenvolver seus próprios empreendimentos. O perfil dessas pessoas geralmente é formado por programadores ou freelancers que tiveram uma idéia e querem desenvolve-la até que ela se torne um negócio.

Recebo vários tipos de perguntas mas tem um tipo que me chama a atenção: “Você não acha que esse mercado está saturado?”.

Essa pergunta me chama a atenção porque, por trás dessa aparência inocente, ela tem várias subquestões importantes como: mercado “oceano azul” vs “oceano vermelho”, mercado global vs local, ineditismo vs copycat, etc.

Ineditismo

Dia desses um amigo chegou com uma ideia interessante e disse que ia começar a desenvolve-la. Algum tempo depois eu fui perguntar pra ele como estava o andamento do projeto e ele me respondeu: “Ih! Desisti da ideia. O Google implementou um produto ‘igualzinho’.”.

Eu achei a resposta interessante porque parece que as pessoas se esquecem que já existiam buscadores antes do Google :) O que o Google fez para alcançar o domínio nas buscas foi criar um produto que funcionava melhor que os concorrentes.

Mesmo com esse ótimo produto eles tem os seus concorrentes em buscas específicas como busca de ofertas (ex. Buscapé no Brasil), busca de estabelecimentos locais, etc. Eles tem concorrência até mesmo para o produto principal: DuckDuckGo (a participação de mercado é menor mas mesmo assim a empresa já é lucrativa).

Quando uma grande empresa grande e poderosa resolve atacar no mesmo mercado e com um produto parecido com o seu significa que você, provavelmente, está com um bom projeto nas mãos! Essa concorrência deve ser encarada como uma validação positiva da sua idéia e não uma coisa para se lamentar. Eu sempre desconfio de empreendedores com idéias “que ninguém mais teve”.

Outro exemplo: nós, programadores, conhecemos os serviços de hosting de código Github e Bitbucket, certo? Eles são os mais famosos e o Github é o maior player nesse mercado. Quando o Github nasceu o Google já tinha o Google Code Hosting.

Mesmo assim colega resolveu criar um serviço desses e cobrar $9/mês para as pessoas usarem. Nasceu o Codeplane. O Codeplane nasceu porque ele tinha uma necessidade que não era atendida pelo Bitbucket/Github de forma satisfatória: ter dezenas de projetos pequenos para hospedar em repositórios privados.

O Github cobra por cada repositório privado, logo, o custo seria enorme. O Bitbucket, na época, limitava o número de repositórios privados em apenas 5 por usuário. No Codeplane não. Você poderia ter quantos repositórios privados precisasse. O único limite era o espaço de armazenamento total.

Ele criou um serviço útil para ele e para várias pessoas e ganhou dinheiro com isso. Independentemente dos “cachorros grandes” desse mercado.

Diferenciais

Uma coisa que é importante ter num mercado onde existe concorrência é o diferencial. O Google tinha como diferenciais a qualidade nos resultados das buscas e a velocidade com que elas eram feitas. O Codeplane tinha uma forma de cobrar diferente dos concorrentes. O DuckDuckGo também tem seus diferenciais.

O simples fato de ter um serviço adaptado para a realidade brasileira, por exemplo, pode criar um diferencial. Mas tenha em mente que esse diferencial pode ser pequeno demais para impedir seus concorrentes de atacarem seu mercado.

Copycats

Criar um produto similar à outro pré-existente e colocar alguns diferenciais nele é bacana. O “copycat” puro e simples não é.

O problema do copycat é que os seus clientes usarão o seu serviço até descobrirem o “original”. Se a empresa que fez o original for mais “poderosa”, provavelmente, terá condições de melhorar o produto deles num ritmo muito mais acelerado que o seu. Isso te deixaria para trás muito rápido na corrida pelo mercado.

Oceano Azul vs Oceano Vermelho

Existe um livro chamado “A Estratégia do Oceano Azul” (W. Chan Kim, Renee Mauborgne) que descreve o mercado como oceanos. Existe um oceano cheio de tubarões (concorrência) onde a briga entre eles é tão grande que tinge as águas de vermelho. E existem outros oceanos bem menos concorridos onde as águas ainda são azuis.

O objetivo de todos os empreendedores que estão começando deveria ser o de navegar por oceanos azuis. Com pouca concorrência. Para fazer isso o livro sugere que segmente o mercado de maneiras diferentes e ofereça valores também diferentes para esse mercado.

Analise os atributos de valor que os seus concorrentes oferecem para os clientes e tente realçar/eliminar alguns deles de modo a ter um produto único e diferente que sirva para pessoas que estão em mercados ainda inexplorados.

Global vs Local

Em vários artigos que falam sobre como começar um negócio você vai ler sobre “a necessidade de adaptar o produto para a realidade brasileira”. Não tem nada de errado com essa estratégia e ela pode até ser boa porque, inicialmente,  diminui os riscos do negócio.

Mas eu acho que devemos nos arriscar mais e parar com esse pensamento pequeno. Com a Internet e os negócios voltados para tecnologia o custo de iniciar certos serviços em escala nacional ou global é muito parecido. E, me perdoe pela obviedade, o mercado global é muito maior que o brasileiro.

Se a gente falar de um negócio que só adapta um que já existe em outro país a coisa fica ainda pior. Pode ser questão de (pouco) tempo para que a empresa global adapte o seu produto para a realidade brasileira e venha competir com você aqui no Brasil.

E aí será uma briga de uma empresa local contra uma empresa global. É bem mais difícil ganhar essa briga, não acham?

The post Mercado saturado: isso importa? appeared first on osantana.

por Osvaldo Santana em 13 de March de 2015 às 16:00

March 10, 2015

Sidnei da Silva

How to help your kid gain confidence at home?

Speech impairment is getting very common nowadays. If you feel that your kid is facing difficulty in pronouncing some of the letters or words then possibly he could be facing a sort of speech impairment. Few years back, if a child had problems while speaking then he had to live with them till the end of his life. But now this is not the case as medical science and information technology has made much advancement. You can easily make use of online speech therapy to correct problems of your child. The speech therapist is a qualified medical practitioner who will help your child in pronouncing those words and letter that he is not able to pronounce.

Speech therapists use different techniques and technological devices that help your child in overcoming his speech impairment. But preparing your kid psychologically to meet with a speech therapist is a really tough task. Most of the kids feel deeply ashamed and uncomfortable while meeting with the speech therapist so that’s why they are unable to co-operate with the therapist.

With the advancements in the field of information technology, you could easily have a speech therapy of your child through your computer in the comfort of your home. The internet has proved to a very miraculous invention of the 21st century as it has and it is still solving many problems of common human beings. Now there are many websites available online through which your child could easily solve his speech problems. These websites have different tongue twisting games that would help your child pronounce those words or letters that can’t be pronounced by him.

Now get your speech therapist at your home:

Most of the people fall in to doubt when it comes to hiring the services of a speech therapist as the services of these professional speech therapists are very expensive. But now with the introduction of online speech therapy, this problem is completely solved. You can get the services of a speech therapist for your child by sitting in the comfort of your home without paying any sort of cost or fee.

Now there are some websites where these speech therapists are also available through video conferencing. In order to avail the facility of video conferencing, you just have to make sure that your device has the feature of a video camera with it. After this, all you have to do is to register the name of your child on that website and then these websites through emails would notify you of the timings when the speech therapist would be available online. The speech therapist would provide a complete professional online speech therapy to your child without any expense, right in the privacy and comfort of your home. Plus he would also guide your child to play those games that would improve his speech. Through these websites you could also purchase a set of certain tools that would help your child in improving his speech.

por admin em 10 de March de 2015 às 08:37

March 09, 2015

Galácia

O Tigre Chinês, Uma Pomba: De Como a China Não Deseja Chamar a Atenção

Michael Pillsbury na obra dele intitulada The Hundred-Year Marathon (A Maratona de Cem Anos). Via Business Insider. Em 1996, eu fazia parte de uma delegação dos EUA para a China, que incluía Robert Ellsworth, o principal assessor de política externa do candidato republicano à presidência, Robert Dole. No que parecia ser uma troca franca de pontos de vista com os estudiosos chineses, fomos

por Eduardo Willians Bandeira de Melo (noreply@blogger.com) em 09 de March de 2015 às 14:50

March 06, 2015

Marco André Lopes Mendes

Como eu e a Liza aprendemos a resolver o Cubo Mágico

O material que eu e a Liza (9 anos) usamos foi o do Rafael Cinoto, que ensina a montar o cubo com histórias. A didática dele é muito boa. Estamos agora estudando vídeos mais avançados dele e continuam muito bons. As historinhas ajudam a memorizar os movimentos, até que eles fiquem naturais. Na página dele está tudo bem organizado. Assinei o canal dele no YouTube também.

Pra começar, compramos um cubo no Mercado Livre. É um cubo "profissional" e chegou em menos de uma semana. Custou cerca de R$ 30,00, incluindo o  frete. Havíamos comprado um cubo de R$ 5,00 numa loja de 1,99, mas passamos muita raiva. :) Recomendo começar com esse ou um similar. Esse cubo ficou com a Liza e comprei outro pra mim no Deal Extreme.

A dica para aprender a resolver é pegar cada etapa e repeti-la até ficar bem confortável, e só então ir pra seguinte. Resolva essa etapa nova e as anteriores. Depois avance para a próxima. São apenas 7 etapas. Desmonte e monte tantas vezes quantas for necessária. Não tenha medo de começar de novo. Fiquei vários dias nas 5 primeiras etapas, por falta de tempo de estudar as outras. Eu montava até ela e desmontava, e começava de novo. Depois de um tempo, fui pra sexta e então pra sétima.

A Liza, como tem mais tempo livre (e é mais inteligente), conseguiu resolver antes de mim. Ela foi assistindo os vídeos e aprendendo sozinha. Ela monta mais rápido que eu, e já a vi montando em cerca de 70 segundos. Eu levo de 2 a 3 minutos. Procuro montar pelo menos uma vez por dia, pra não esquecer. 




por Marco André Lopes Mendes (noreply@blogger.com) em 06 de March de 2015 às 16:05

March 05, 2015

Magnun Leno

Controlando o Sucesso/Falha de Um Programa

Outro dia, em uma conversa do Gupy-DF surgir uma dúvida sobre como controlar o fluxo e o status de um programa. Existem alguma formas de se realizar essa tarefa, cada uma com suas vantagens e desvantagens.

Zen of Python

Mas por quê isso é importante? Um exemplo básico é que seu programa pode vir a ser utilizado por outros programas (seja sob a forma de um programa externo ou um biblioteca), e é importante repassar informações sobre a execução para o "programa que o invocou". Uma outra situação é quando seu próprio programa precisa fazer logging das ações executadas e dos erros encontrados.

Controlando o Sucesso/Falha de Um Programa é um artigo original de Mind Bending

por Magnun em 05 de March de 2015 às 00:16

March 04, 2015

Eric Hideki

#7 João Bueno | Pythonistas que você devia conhecer

perfil_gimp_tintec

João Bueno, mais conhecido como JS, é uma das pessoas de grande importância na linguagem Python. Trabalhando há anos com a linguagem, ter participado da diretoria da Associação da Python Brasil, contribuidor do software de edição de imagens GIMP, por isso o convido para compartilhar suas experiências.

Como conheceu Python, lá em 2001?

Eu já usava Linux há alguns anos – sempre gostei de ter controle do computador, de poder dizer para ele o que fazer. Eu sabia C, e outras linguagens que tinham caído em desuso nos ambientes gráficos – tanto do Linux quanto do Windows: nenhuma delas deixaria eu fazer uso das capacidades de multimídia de um computador como o que existia na época. Criar uma janela gráfica para poder se desenhar com o mouse em C é uma tarefa para algumas semanas. Alguns anos antes eu havia tentado aprender um pouco de Java: applets para Web eram até “tranquilos”, mas para programas desktop eu abandonei a tentativa de aprendizagem após alguns dias tentando instanciar uma classe “Rectangle” da biblioteca padrão sem ter sucesso (nem documentação).

Python para mim era mais um nome de linguagem dentre tantos outros que “quando eu tivesse tempo, iria estudar”: Perl, TCL, Awk, C++ … Meu maior interesse era aprender Perl – na época ainda era o que “impulsionava a Web”. Mas um dia comprei um guia rápido de Python (da Novatec -já está fora de catálogo há vários anos) – e lendo o mesmo, havia um diferencial: o que eu vinha embutido na linguagem e na sua biblioteca padrão permitiam o desenvolvimento rápido, sem muitos meandros, de aplicações simples. Me lembro até hoje como me chamou a atenção a documentação do módulo “random” nesse guia: enquanto nas outras linguagens na época (e até hoje, 2015), tudo o que você tem de “random” é um número entre 0 e 1, que cabe a você massagera com 3 ou 4 expressões distintas até você ter um uso pra ele: você nunca quer um número aleatório entre 0 e 1.

Você quer escolher um elemento de uma lista, quer um número inteiro entre 0 e o número de colunas da sua tela gráfica – quer um número prático. Python não só incluía chamadas diretas para todos os usos práticos possíveis de um número aleatório – mas também chamadas para várias distribuições estatísticas distintas de números aleatórios (uniforme, gauss, triangular, …)Essa e outras coisas me empolgaram bastante. Um ou dois meses depois fui começar um projeto para uma pequena empresa, e fiz em Python para Web, usando CGI.

E como começou a se interessar e colaborar com o GIMP?

(Para quem não sabe, GIMP é o GNU Image Manipulation Progam – um programa livre para manipulação de imagens e fotos com muitos dos mesmos recursos do mais conhecido na categoria, o Photoshop)

Isso foi um pouco mais tarde, em 2004. Eu já usava Linux e Software Livre há bastante tempo – e sempre tinha gostado de programas de imagens – que deixassem você usar o computador para desenhar – quando tive meu primeiro computador na década de 80, a vontade era ter uma impressora pra ele, para poder passar meus desenhos para o papel. Ainda para o PC XT,que não tinha ambiente gráfico, tive um “mouse” – só servia para os programas de desenho.

E em 2004 me bateu a questão de – “nossa eu uso todos esses programas em Software Livre, já é hora de eu começar a contribuir com pelo menos um projeto”. Bom, a minha opção foi o GIMP, do qual eu já era um usuário frequente. Fui atrás da documentação e do código fonte, e consegui compilar o programa e entrar em contato com a comunidade de desenvolvedores. A tradução também estava parada, num momento entre versões estáveis do programa, e mesmo as partes já traduzidas tinham problemas sérios. Então junto com minhas primeiras contribuições, ou tentativas, assumi também a tradução do programa.

Como foi essa experiência de dar um curso sobre edição de imagens(http://timtec.com.br/course/edicaoetratamento/)?

Esse curso foi interessante por se tratar de um “MOOC” (“Massive Online Open Course”) completo, voltado para público inciante na edição de imagens. O projeto tinha um patrocínio grande, e foi executado profissionalmente – acho que o mais marcante nele foi o contato com a produção de vídeo “em nível de TV”: a gente ia para o Estúdio, a equipe de gravação era completamente diversa das pessoas com quem eu conversava sobre conteúdo-, havia uma fase de pós-produção dos vídeos. Muita correria,e devido a própria natureza e público alvo do curso, era sobretudo um curso “leve” – bem pouco denso, de conteúdo fácil, com o básico, repetido, feito para quem estivesse abordando o assunto pela primeira vez.

Por um lado deu para matar a vontade de ensinar as pessoas a “mandarem no computador” que é o que eu gosto, mas só pela interface do GIMP. Claro que isso não é o suficiente pra mim, então mesmo sendo um curso básico, nas últimas aulas dou umas dicas de como criar plug-ins em Python para o GIMP, e modificar arquivos de SVG manualmente para o Inkscape :-)

Brython, como ele é e o que tem de interessante?

Brython é uma implementação de Python feita para rodar no Browser – no lado do cliente.

Ele funciona traduzindo scripts em Python para Javascript no browser, depois da página ser carregada.

Quando conheci o projeto, em 2013, achei interessante só pelo fato de se poder usar a sintaxe do Python, mais legível, direto no navegador: sem chaves, delimitação por identação – e já funcionavam os “import”s que são uma mão na roda, sem falar nas sintaxes para formatação de strings: Python tem duas formas nativas, ambas implementadas no Brython, e em Javascript a única forma ainda é intercalar pedaços de strings com aspas e operadores “+” de concatenação.

Desde 2013 o projeto acelerou bem, e deixou de ser só uma “sintaxe python like” para uma implementação completa – que permite usar toda a sintaxe da linguagem, inclusive a construção “yield” e “yield from” , permitindo programação assíncrona sem callbacks explícitos.

Desde 2001 sou um fã de Python e isso tem vários motivos: a legibilidade, flexibilidade e previsibilidade da linguagem talvez sejam os maiores – Brython é um projeto que permite o uso de tudo isso no Client Side. Só a funcionalidade de “import” já é um grande diferencial em relação ao javascript “cru” que faz tudo num namespace único,e não tem qualquer suporte direto a módulos ou carregamento programático de partes de um programa. (Em javascript você tem que criar um elemento “script” no HTML, ou carregar um arquivo usando ajax e executa-lo com “eval”). Já o “import” é uma construção natural de qualquer programa minimamente mais complexo.

Ele ainda é um projeto que depende de tração de usuários e uma comunidade para chegar ao mainstream – mas creio que se comparado a projetos Javascript que já ganharam tração no passado, ele oferece muitas vantagens: hoje num projeto Web desenvolvedores tem que incluir vários, as vezes mais de 10, projetos distintos de javascript para ter um pouco mais de funcionalidade que a linguagem em si não tem (e o fato de não ter uma biblioteca padrão é,talvez, a raiz desse problema).

Brython é um projeto que não só oferece a tradução de Python para javascript, mas uma biblioteca padrão adaptada da própria biblioteca do Python (precisa de collections.OrderedDict? é só usar!)., e nessa fase de “aquecimento” o projeto está aberto inclusive a mais funcionalidades para integrar o conjunto (por exemplo, um módulo específico para facilitar a programação multimídia, no estilo feito com Pygame, mas usando o Canvas do html5);

O interessante de ter Python no browser é que alguns dos projetos de Javascript são completamente desnecessários – a biblioteca “underscore_js” ou “lodash” por exemplo, é composta de cerca de algumas dezenas de funções que, podem ser rescritas em 3 ou 4 linhas, quando não numa única expressão de Python – devido a coisas que quando você descreve parecem poucas – mas tem a ver com a maior formalidade e precisão dada aos objetos no Python e a evolução ordenada da linguagem.

O que é Plone e porque ele é tão importante?

O Plone é um sistema de gerenciamento de conteúdos – ou “CMS”: primariamente um sistema que pode ser usado para manter um portal de notícias no ar, alimentado por vários jornalistas e editores, e com milhões de leitores. Ele é totalmente escrito em Python e tira proveito de quase tudo que a linguagem oferece, sendo construído em cima do “Zope” – que é um servidor de aplicações bem completo, com ênfase em segurança, e granularidade de aplicações.

Plone tabém pode funcionar como plataforma Web para alguns projetos que se expandam a partir da idéia de um CMS.

Por outro lado, tem uma frase que costumo dizer sobre Plone: “O que Python tem fácil, Plone tem de difícil” : ele tem várias camadas, algumas existentes apenas por motivos históricos e uma complexidade razoável. Por outro lado, numa instalação limpa, atende a requisitos de acessibilidade, internacionalização e padrões Web -e está pronto para funcionar como um portal de notícias com quase nenhuma customização.

Ele tem uma importância grande par ao eco-sistema de Python por que permite uma contribuição entre projetos muito forte entre pessoas trabalhando em projetos diferentes em países diferentes. O Plone todo se divide em centenas de pacotes Python, todos licenciados sob a G.P.L. – que obriga as pessoas que fazem uso dos mesos a contribuírem suas evoluções no software de volta à comunidade. Isso acabou por criar um ambiente bem próspero para os desenvolvedores. (Algumas pessoas de fora podem se preocupante alguém se “apoderar” de um pacotinho em que elas trabalharam por 3 ou 4 semanas…mas esse pacotinho só faz alguma coisa por que está construído em cima de um trabalho sólido de dezenas de pessoas ao longo de mais de 10 anos – então na verdade, mesmo para quem tem um pensamento egoista, ainda sai bem barato)

Em uma de suas palestras, você afirmou que dá para fazer tudo com Python, realmente dá?

É uma plaletra que ministrei algumas vezes – e mesmo em palestras introdutórias de Python costumo perguntar ao público alguma área da T.I. que acham que Python não seja usado. E não há. Desde a automatização de tarefas em servidores, renderização e vídeo, computação científica, aplicações Web, big data, Python _de fato_ perpassa todas as áreas.

E ainda que em alguns nichos possa haver ferramentas mais especializadas ou melhores, Python é a ferramenta que vai atuar naquele nicho e permitir de forma transparente uma interface com todos os outros.

Precisa guardar suas expressões de matemática simbólica numa base SQL para exibir num portal Web? Python faz as três coisas, sem modificações necessárias.

Agora — nem tudo são tão flores assim – há um nicho importantíssimo – crucial, na verdade, em que Python está bem atrás: o desenvolvimento de aplicações “mobile” – tanto para Android quanto para IOs e outras plataformas. No espírito da pergunta “tem como fazer?” a resposta ainda é “sim” – há projetinhos de Python que permitem o desenvolvimento para Android, a o Kivy focado em aplicações multimídia multiplataforma – mas não há uma “grande plataforma unificada”.

A tendência é que Python se infiltre e caminhe por aí – ainda em 2015 foi formada uma lista de discussão justamente para debater a disponibilização e facilidades – ao estilo da ‘biblioteca padrão” de Python em dispositivos móveis.

Também é um segmento em que eu vejo o Brython em dois ou 3 anos começando a chegar de forma contundente: afinal, rodando no browser ele pode tirar proveito diretamente das APIs disponibilizadas em HTML5 para os vários recursos dos dispositivos móveis. (mesmo hoje, scritps em Brython abrem em funcionam sem problemas nos navegadores Android – e suspeito que no IOs também)

Se uma pessoa estiver aprendendo Python para web hoje, qual framework você indicaria (Django, Flask, Bottle, Web2py)?

É difícil dizer — primeiro, conforme você conhece a linguagem mais a fundo, percebe que os frameworks são “sabores” diferentes para criar aplicações Web: todos eles vão cobrir um conjunto de necessidades que as aplicações web tem em comum. Além dos frameworks citados há vários outros: pyramid, o próprio Plone, Tornado, web.py , watson…

Tradicionalmente se pensa em Flask, Bottle e Web2py como “microframeworks” por que potencialmente uma aplicação Web pode estar autocontida em um arquivo, e em Django como algo “maior e mais sofisticado para projetos maiores”…

Essa divisão é um tanto artificial: embora você não possa colocar um projeto django num único arquivo .py,ele pode ser contido num único “.egg” de Python. O Deploy também não depende em nada do número de arquivos, e em geral acontece com uma atualização do repositório GIT no servidor. E as aplicações com Django ficam bem estruturadas, fáceis de acompanhar, e fáceis de crescer.

Outros como Pyramid e Flask dão bastante flexibiidade quanto à persistência de dados, sistema de login, até o engine de templates – e essa é a tendência, eu creio: frameworks com componentes “plugáveis” em que você pode colcoar um componente que melhor atenda seu projeto, ou mesmo desenvolver um quando os existentes deixam de atender.

Para quem está começando, acredito que o Flask seja uma boa opção – ele tem bastante coisa já integrada e é escalável para projetos maiores – mas, uma coisa que eu sempre enfatizo é: entender a linguagem Python e “como funciona” uma aplicação web é mais importante que qualquer framework em particular.

No Centro de Treinamento da Novatec você fez o primeiro de curso de Flask, o que foi falado? E porque Flask?

Não deixei de dar ênfase aos princípios que citei acima/; o Flask oferece uma série de facilidades para se criar uma aplicação Web. A grande ênfase do curso, além do foco em chegar ao final com uma aplicação Web completa, ainda que simples, foi entender os princípios por trás de uma aplicação Web.

Por exemplo, é fácil abrir um tutorial de Flask e ver que se você coloca uma linha com “@app.route(‘/’) precedendo uma função que retorna o texto “Hello world”, você tem uma aplicação de “hello world” para a web.

Mas aí essa linha fica parecendo mágica – principalmente para quem não está já bem familiarizado com Python: o que faz essa linha? Quem é “app”? Ela é mesmo necessária? E se eu quiser fazer uma aplicação em Flask, mas quiser declarar minhas rotas de outras formas?

Esse curso então procurou dar uma base de Python, e de como funciona uma aplicação Web para que todos os participantes pudessem entender essas questões – e ver quanto mais coisas tem que ser feitas, se esse método não fosse empregado para declarar as funções da aplicação. E também por que, mesmo com todas as facilidades que o Flask traz, uma aplicação Web completa ainda depende de tantos outros pacotes, como flask-login – com as facilidades para gerenciar o login de usuários, e flask-wtf, para gerar formulários.

Tudo levado em consideração o Flask é um ótimo framework – desenvolvido quando Python já contava com anos de estrada, e outros frameworks estavam sofrendo com decisões de projeto tomadas anos antes. Flask teve a oportunidade de ter um “início do zero” quando as pessoas já tinham aprendido com os erros. Como consequência disso temos sua burocracia e tamanho reduzidos, e a possibilidade de usar vários módulos diferentes para tarefas com tecnologias diferentes.

Por exemplo: é bem “fora do caminho” você querer usar uma base de dados não relacional no Django. Em Flask, se você deseja ter alguns tipos de objeto persistidos em SQL e outros de forma não relacional, é só a questão de escrever os modelos de objetos de acordo – não precisa nenhuma mágica, nenhuma configuração para funcionar tudo.

Esses cursos sempre são uma oportunidade de aprendizado – não só para quem faz,mas também para o instrutor, que nesse ambiente de forte interação consegue perceber onde estão as principais dificuldades. É bem provável que em continuidade ao mesmo tenhamos em breve um tratando do Framework, e ensinando a chegar rapidamente nos resultados desejados – e sem nunca tratar um assunto como “mágico”.

Algumas palestras:


por Eric Hideki em 04 de March de 2015 às 23:21

March 03, 2015

Eric Hideki

#2 Júlia Rizza | Pessoas que me inspiram

julia_rizza

Uma das coisas que mais gosto é conectar pontos. Quando estava aprendendo Python, fiz um curso de Web2py como já comentei aqui, e na mesma época na minha turma estava a Júlia Rizza e o Cássio Botaro. Ambos deslancharam em suas carreiras, se tornando referências no assunto quando se trata de Python/Web2py, e vejo que o curso que fizemos foi um ponto de encontro onde pudemos trocar experiências e nos conhecerem.

Hoje entrevisto a Júlia Rizza (blog), ela ministrou um curso de Web2py na Pycursos. Web2py se destaca por ser o framework ideal de entrada no mundo de desenvolvimento web, e a Júlia irá contar um pouco sobre essa experiência.

Júlia, fale um pouco sobre você

Pois bem, além do meu nome, que você já conhece, tenho 17 anos e trabalho com Python há mais de 3. Sempre me interessei na internet e em como as coisas aqui funcionam, como são construídas, por isso desde os 12 venho descobrindo mais sobre o desenvolvimento voltado para a web. Uma das razões de eu ter procurado aprender Python, inclusive, foi para trabalhar com isso. Motivo pelo qual apenas um ou dois meses depois de começar a aprender a linguagem, já parti para o web2py e hoje exploro vários outros frameworks da linguagem dentro dessa área. Meus maiores motivos de orgulho atualmente envolvem programação em geral e, desde bem cedo, tenho a certeza que quero continuar envolvida nisso. Por isso, tenho orgulho de dizer que sou a mais nova bixete da Engenharia de Computação da UFU (Universidade Federal de Uberlândia), co-founder da Cacho.la e professora de web2py.

Por que Web2py? Quais são as principais vantagens diante outros frameworks como Django e Flask?

O web2py foi criado com uma proposta didática, pois seu criador, Massimo di Pierro, percebia a grande dificuldade de entendimento da turma sobre alguns conceitos. Dessa forma, foi criado um framework que já oferece um molde de aplicação para o programador, com ferramentas prontas, embutidas, e que direciona para boas práticas. Tudo isso, além de guiar o programador dentro do mundo do desenvolvimento web e fazer com que ele adquira conhecimentos mais profundos sobre o que ele realmente está fazendo, agiliza a produção de aplicativos, torna-a mais simples e prática.

Nada melhor que isso para começar a desenvolver para a web ou para agilizar seu desenvolvimento quando você já tem experiência na área, por isso a minha escolha do framework.

Não gosto da comparação entre frameworks, pois vejo que cada um tem suas características próprias e isso faz com que sejam melhores ou piores dependendo do seu objetivo final, da sua aplicação.

Mas, em geral, as vantagens do web2py estão no seu modelo didático, que molda o programador dentro das melhores práticas, como o modelo MVC, e o fato de ser “pronto-para-usar”, ou seja, você não depende de bibliotecas externas para desenvolver, ele já vem com todo o necessário para uma aplicação básica, e você já pode sair programando, além de ter um dos deploys mais fáceis que eu já conheci.

E desvantagens do Web2py, existem?

Como nas vantagens, as desvantagens do framework são consideradas dependendo da aplicação final que você deseja. Mas novamente, em geral, considero que as desvantagens do web2py estão na documentação, que muitas vezes não encontra-se atualizada ou não é bem explicada em determinado ponto, mas creio que isso ocorre pois a comunidade e o framework estão em pleno crescimento, portanto agora que as coisas estão começando a melhorar nesse ponto (e, de qualquer forma, você sempre ganha uma resposta quando recorre à comunidade); além disso, o que pode ser considerado tanto uma desvantagem quanto uma vantagem, dependendo da pessoa, é a pouca liberdade que o framework te dá visto que ele tem fins didáticos, ou seja, ele funciona dentro de um molde e não te dá muita liberdade para sair dele. Caso você esteja começando ou já tenha experiência e goste do molde, isso é bom; caso contrário, é incômodo, mas nada que te proíba de trabalhar com ele.

Como foi a experiência de ministrar um curso online?

Bom, essa foi a primeira turma na minha vida para a qual eu dei aula de alguma coisa, então eu fiquei ansiosa do início ao fim do curso, mas foi uma das melhores experiências que tive e é realmente gratificante poder repassar o meu conhecimento aos outros. Os alunos deram muitos feedbacks legais e a turma foi excelente, apresentando trabalhos e resultados incríveis. Tentei passar nas minhas aulas não só o conhecimento sobre o web2py, mas sobre o desenvolvimento web em geral. Assim, espero ter ajudado os alunos não só com o framework, mas com seus futuros projetos e até mesmo profissões na área. Pretendo seguir com o curso, abrindo novas turmas e melhorando o conteúdo, pois adorei essa experiência.

Quais são as ferramentas/plugins que o Web2py oferece que fazem parte do seu dia a dia desenvolvendo?

Geralmente, utilizo Sublime Text para qualquer tipo de desenvolvimento e pego dicas e snippets do web2py slices para funcionalidades básicas que outras pessoas deixaram prontas (por exemplo, a aplicação do plugin CKEditor), afinal não temos que reinventar a roda. Git é uma ferramenta indispensável para qualquer desenvolvedor, por isso também dei uma ênfase a isso nas últimas aulas do curso. Visto que o web2py já vem com tudo pronto para começar a desenvolver, preciso mesmo somente disso. Por fim, costumo fazer o deploy na PythonAnywhere, que oferece uma ótima estrutura, e tudo fica lindo!

Deixe dicas e comentários para as pessoas que desejam conhecer um pouco mais sobre Python e Web2py e suas considerações.

Conhecer Python e web2py não é difícil, visto que ambos têm crescido muito e tem vários materiais espalhados na web, inclusive recomendo altamente os materiais que você indica no seu blog, mas uma dica sempre importante é: aprenda inglês, independente se você irá fazer serviços apenas em português, que nunca use nada em inglês nas suas aplicações. A questão é, tem gente da Ásia, da Europa, da África, de todo o lugar do mundo contribuindo com materiais e conhecimento sobre essas ferramentas, e toda essa contribuição vem em inglês e você vai crescer muito mais na área se conseguir adquirir conhecimento delas. Junte esse conhecimento com dedicação e interesse na área e no seu próprio crescimento e logo vai estar com ofertas de emprego, projetos e oportunidades nas suas mãos.

E conheça o Web2schools, projeto da Júlia sobre gerenciamento de escolas com Web2py – https://ericstk.wordpress.com/2014/02/12/web2schools-gerenciamento-de-escolas-com-web2py/


por Eric Hideki em 03 de March de 2015 às 01:04

March 02, 2015

Filipe Saraiva

SciPy Latin America 2015 – Inscrições e Chamada de Trabalhos

O evento latinoamericano sobre aplicações de Python nos mais diferentes campos das ciências, engenharias e afins, está com as inscrições e chamadas para submissão de trabalhos aberta!

Há 4 tipos diferentes de propostas de trabalho que podem ser submetidas: Palestras, Tutoriais, Pôsteres e Palestras relâmpago, e podem ser submetidos trabalhos em inglês, espanhol ou português. O deadline é dia 6 de abril. Para mais detalhes confira a página da chamada de trabalhos.

O evento ocorrerá em Posadas, Misiones, Argentina, de 20 à 22 de maio e as inscrições são gratuitas. Para maiores informações, mantenha os olhos na página do evento.

por Filipe Saraiva em 02 de March de 2015 às 14:49

PythonClub

Configurando ambiente Django com Apache e mod_wsgi

Entendendo a necessidade

Muitas vezes encontramos dificuldade em colocar nossas aplicações para funcionar em um servidor devido ao pouco conhecimento em infraestrutura, principalmente aqueles que vieram do php, onde, subir um site e já o ver funcionando no ambiente final se trata apenas de subir os arquivos para a pasta www e pronto, certo? Não, não é bem por aí ...

Normalmente quando configuramos a hospedagem de um domínio através de um software de gestão de alojamento web (cpanel é o mais conhecido) automaticamente o sistema configura o VirtualHost específico para o seu domínio cadastrado, ja direcionando a path para a sua pasta www ou public_html. Mas como isso é feito? Não entrarei em detalhes de como o cpanel funciona, mas irei demonstrar aqui como configuramos um servidor com apache para receber nossa aplicação.

Mas por que o Apache?

A partir do momento que eu mudei meu foco, saindo do PHP para trabalhar com Python, eu acabei "abandonando" o Apache para trabalhar com Nginx. Porém, me deparei com um projeto onde tinha que funcionar em uma Hospedagem compartilhada na qual só funciona o apache. Como não vi nada relacionado a essa configuração aqui no Pythonclub, achei que seria útil para muitos que podem cair em uma situação parecida com a minha, ou simplesmente prefira usar o Apache do que o Nginx.

Caso o seu interesse seja mesmo usar o Nginx (pode parar por aqui), acho ótimo!!! Te dou todo apoio e ainda te indico um ótimo post para isso, do nosso amigo Igor Santos.

Agora, chega de conversa e vamos ao que interessa.

Como fazer?

Existem várias maneiras de se fazer o Django trabalhar com apache, uma delas é a combinação Apache + mod_wsgi e será dessa forma que faremos. Com mod_wsgi podemos implementar qualquer aplicação Python que suporte a interface Python WSGI.

Instalando alguns pacotes necessários

Antes de mais nada, atualize a lista de pacotes

$ sudo apt-get update

Apache + mod_wsgi

$ sudo apt-get install apache2 libapache2-mod-wsgi

Python setup tools + pip

$ sudo apt-get install python-setuptools
$ sudo apt-get install python-pip

Vamos testar o WSGI?

Vamos fazer um teste com uma aplicação simples em python.

Começe criando um diretório na raiz do apache (DocumentRoot)

$ sudo mkdir /var/www/wsgi_test

Em seguida vamos criar nossa app de teste ...

$ sudo vim /var/www/app.wsgi

... e escrever nossa app python compatível com WSGI

def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'
    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output]

Vamos criar agora um host para usar como nosso domínio da aplicação teste

$ sudo vim /etc/hosts

Adicione esta linha ao seu arquivo hosts

127.0.0.1 wsgi_test

E vamos configurar nosso VirtualHost no Apache.

$ sudo vim /etc/apache2/sites-available/wsgi_test
<VirtualHost *:80>
    ServerName wsgi_test
    DocumentRoot /var/www/wsgi_test
    <Directory /var/www/wsgi_test>
        Order allow,deny
        Allow from all
    </Directory>
    WSGIScriptAlias / /var/www/wsgi_test/app.wsgi
</VirtualHost>

Ative-o

$ sudo a2ensite wsgi_test

Obs: esse comando cria um link simbólico do wsgi_test para a pasta sites-enabled. Você pode fazer isso manualmente.

Reinicie o apache:

$ sudo service apache2 reload

Feito isso abra o internet explorer seu navegador preferido e acesse http://wsgi_test. Se você está vendo a mensagem "Hello World" pode comemorar, o wsgi está funcionando com o apache.

Configurando Django com WSGI

Até o momento entendemos como funciona a configuração do apache para receber uma aplicação Python com WSGI. Podemos usar essa ideia para qualquer aplicação python, porém veremos como fica essa configuração para trabalhar com Django.

Criando o ambiente

É sempre bom trabalharmos com ambientes virtuais em nossas aplicações python, para isso temos o virtualenv. Eu, particularmente, prefiro usar o VirtualenvWrapper, que separa os ambientes virtuais das aplicações. Caso você não conheça, indico o post do Arruda que foi o que me guiou quando comecei a usar. Usando VirtualEnvWrapper

No meu caso usei o virtualenvwrapper e meu filesystem é o seguinte:

+-- /home/guilouro
|   +-- .virtualenvs  #[Ambientes]
|   +-- www           #[Projetos]

O Virtualenvwrapper criará meus projetos dentro de www e os ambientes em .virtualenvs. Mas para que isso aconteça temos que adicionar algumas linhas em nosso ~/.bashrc

# adicione no final do arquivo ~/.bashrc
# ...
export PROJECT_HOME=~/www
export WORKON_HOME=~/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh

Atualize com o comando:

source ~/.bashrc
Criando nosso projeto
$ mkproject wsgi

Com as configurações anteriores o virtualenvwrapper já irá ativar o ambiente e levar você para a pasta do projeto. Mas para ativar é muito simples, basta usar:

$ workon wsgi

Com o nosso ambiente virtual criado partiremos então para a criação do nosso projeto django. Utilizarei a versão mais atual até o momento, nesse caso 1.7

$ pip install django

Não entrarei em detalhes para a configuração inicial do django, portanto irei usar um template que eu criei para a inicialização dos meus projeto. Criamos então o projeto dessa forma:

# startproject pelo template
$ django-admin.py startproject --template https://github.com/guilouro/django-boilerplate/archive/master.zip wsgitest .
# instala os pacotes
$ pip install -r requirements.txt
# faz a migração
$ python manage.py migrate

Você encontra esse template aqui -> django-boilerplate

Criando um site no apache para o projeto

Primeiramente, vamos criar um domínio fictício para responder com o nosso projeto ao ser acessado.

$ sudo vim /etc/hosts

127.0.0.1   djangowsgi.com

Agora vamos configurar o apache:

$ sudo vim /etc/apache2/sites-available/djangowsgi
WSGIDaemonProcess djangowsgi.com python-path=/home/guilouro/www/wsgi:/home/guilouro/.virtualenvs/wsgi/lib/python2.7/site-packages
WSGIProcessGroup djangowsgi.com

<VirtualHost *:80>
    ServerName djangowsgi.com
    WSGIScriptAlias / /home/guilouro/www/wsgi/wsgitest/wsgi.py

    <Directory /home/guilouro/www/wsgi>
        <Files wsgi.py>
            Order allow,deny
            Allow from all
        </Files>
    </Directory>

    Alias /media/ /home/guilouro/www/wsgi/media/
    Alias /static/ /home/guilouro/www/wsgi/static/

    <Directory /home/guilouro/www/wsgi/static>
        Order allow,deny
        Allow from all
    </Directory>

    <Directory /home/guilouro/www/wsgi/media>
        Order allow,deny
        Allow from all
    </Directory>

</VirtualHost>

Reinicie novamente o apache:

$ sudo service apache2 reload

Explicarei agora um pouco do que foi usado nessa configuração

WSGIScriptAlias: é a url na qual você estará servindo sua aplicação (/ indica a url raiz), e a segunda parte é a localização de um "arquivo WSGI".

Modo daemon

O modo daemon é o modo recomendado para a execução do mod_wsgi(em plataformas não-windows). Ele gera um processo independente que lida com as solicitações e pode ser executado como um usuário diferente do servidor web. Um dos pontos positivos dele é que a cada alteração em seu projeto você não precisa restartar o apache, basta executar um touch no seu arquivo wsgi.py

Directivas para o daemon

WSGIDaemonProcess: Foi atribuido a ele o nosso servername e utilizamos python-path por se tratar de um projeto que esta em ambiente virtual. Passamos então nossas paths nele.

WSGIProcessGroup: Atribuímos o servername a ele

Testando a aplicação

Agora acesse http://djangowsgi.com e corre para o abraço.

Espero que tenha ficado claro. Qualquer dúvida ou problema deixe nos comentários e vamos juntos tentar resolver.


Referências:

por Guilherme Louro em 02 de March de 2015 às 03:20

February 28, 2015

Python Help

Funções anônimas em Python

As funções anônimas — em Python também chamadas de expressões lambda — representam um recurso bem interessante da linguagem Python, mas cuja utilidade pode não ser muito óbvia à primeira vista.

Uma função anônima é útil principalmente nos casos em que precisamos de uma função para ser passada como parâmetro para outra função, e que não será mais necessária após isso, como se fosse “descartável”.

Um exemplo

A builtin map recebe como parâmetros: uma função e uma sequência de dados nos quais a função será aplicada. Agora, imagine que temos uma lista com os números entre 1 e 100 e precisamos de outra lista que contenha os dobros dos números de 1 a 100.

numeros = list(range(1, 101))  # compatível com python 3

Para obter a lista de dobros, poderíamos chamar a função map, passando a ela uma função que retorna o dobro do elemento recebido como parâmetro. Sem funções anônimas, faríamos assim:

def dobro(x):
    return x*2

dobrados = map(dobro, numeros)

Assim, a função dobro será aplicada para cada elemento de numeros e o resultado de cada chamada será adicionado à lista dobrados. Porém, a função dobro será usada somente aqui nessa parte do programa, e o desenvolvedor pode achar que sua presença ali polui o código de forma desnecessária. Como não irá utilizá-la mais em lugar algum, essa função pode ser transformada em uma função anônima, usando a expressão lambda:

dobrados = map(lambda x: x * 2, numeros)

A expressão lambda x: x * 2 cria uma função anônima que recebe um valor como entrada e retorna como resultado tal valor multiplicado por 2. Esse tipo de função é assim chamada porque não podemos nos referir a ela através de um nome, diferentemente da função dobro, por exemplo. As funções anônimas que, em Python, são obtidas através das expressões lambda, são bastante limitadas e devem ser utilizadas com cautela, pois o seu abuso pode comprometer a legibilidade do código. Veja alguns exemplos de abuso das expressões lambda: http://wiki.python.org/moin/DubiousPython#Overuse_of_lambda.

Caso você ainda não tenha compreendido o tal do anonimato da função, costumo pensar em um exemplo que usamos com frequência onde também existe anonimato. Você já passou uma lista literal para uma função, como faço no exemplo a seguir?

soma = sum( [1, 1, 2, 3, 5, 8, 13, 21] )

Você concorda que a lista passada como argumento é também um objeto anônimo? A ideia é semelhante a da função anônima, pois passamos objetos “descartáveis”, como no trecho acima, quando sabemos que não vamos precisar daquele objeto em outros trechos do código.

Para aprender mais sobre as expressões Lambda de Python, leia:


por Valdir Stumm Jr em 28 de February de 2015 às 21:31

February 24, 2015

PythonClub

Tuplas mutantes em Python

Por Luciano Ramalho, autor do livro Fluent Python (O'Reilly, 2014)

See also the original article in English: http://radar.oreilly.com/2014/10/python-tuples-immutable-but-potentially-changing.html

Tuplas em Python têm uma característica surpreendente: elas são imutáveis, mas seus valores podem mudar. Isso pode acontecer quando uma tuple contém uma referência para qualquer objeto mutável, como uma list. Se você precisar explicar isso a um colega iniciando com Python, um bom começo é destruir o senso comum sobre variáveis serem como caixas em que armazenamos dados.

Em 1997 participei de um curso de verão sobre Java no MIT. A professora, Lynn Andrea Stein - uma premiada educadora de ciência da computação - enfatizou que a habitual metáfora de "variáveis como caixas" acaba atrapalhando o entendimento sobre variáveis de referência em linguagens OO. Variáveis em Python são como variáveis de referência em Java, portanto é melhor pensar nelas como etiquetas afixadas em objetos.

Eis um exemplo inspirado no livro Alice Através do Espelho e O Que Ela Encontrou Por Lá, de Lewis Carroll.

imagem Alice Através do Espelho e O Que Ela Encontrou Por Lá

Tweedledum e Tweedledee são gêmeos. Do livro: “Alice soube no mesmo instante qual era qual porque um deles tinha 'DUM' bordado na gola e o outro, 'DEE'”.

exemplo 1

Vamos representá-los como tuplas contendo a data de nascimento e uma lista de suas habilidades:

>>> dum = ('1861-10-23', ['poesia', 'fingir-luta'])
>>> dee = ('1861-10-23', ['poesia', 'fingir-luta'])
>>> dum == dee
True
>>> dum is dee
False
>>> id(dum), id(dee)
(4313018120, 4312991048)

É claro que dum e dee referem-se a objetos que são iguais, mas que não são o mesmo objeto. Eles têm identidades diferentes.

Agora, depois dos eventos testemunhados por Alice, Tweedledum decidiu ser um rapper, adotando o nome artístico T-Doom. Podemos expressar isso em Python dessa forma:

>>> t_doom = dum
>>> t_doom
('1861-10-23', ['poesia', 'fingir-luta'])
>>> t_doom == dum
True
>>> t_doom is dum
True

Então, t_doom e dum são iguais - mas Alice acharia tolice dizer isso, porque t_doom e dum referem-se à mesma pessoa: t_doom is dum.

exemplo 2

Os nomes t_doom e dum são apelidos. O termo em inglês "alias" significa exatamente apelido. Gosto que os documentos oficiais do Python muitas vezes referem-se a variáveis como “nomes“. Variáveis são nomes que damos a objetos. Nomes alternativos são apelidos. Isso ajuda a tirar da nossa mente a ideia de que variáveis são como caixas. Qualquer um que pense em variáveis como caixas não consegue explicar o que vem a seguir.

Depois de muito praticar, T-Doom agora é um rapper experiente. Codificando, foi isso o que aconteceu:

>>> skills = t_doom[1]
>>> skills.append('rap')
>>> t_doom
('1861-10-23', ['poesia', 'fingir-luta 'rap'])
>>> dum
('1861-10-23', ['poesia', 'fingir-luta 'rap'])

T-Doom conquistou a habilidade rap, e também Tweedledum — óbvio, pois eles são um e o mesmo. Se t_doom fosse uma caixa contendo dados do tipo str e list, como você poderia explicar que uma inclusão à lista t_doom também altera a lista na caixa dum? Contudo, é perfeitamente plausível se você entende variáveis como etiquetas.

A analogia da etiqueta é muito melhor porque apelidos são explicados mais facilmente como um objeto com duas ou mais etiquetas. No exemplo, t_doom[1] e skills são dois nomes dados ao mesmo objeto da lista, da mesma forma que dum e t_doom são dois nomes dados ao mesmo objeto da tupla.

Abaixo está uma ilustração alternativa dos objetos que representam Tweedledum. Esta figura enfatiza o fato de a tupla armazenar referências a objetos, e não os objetos em si.

exemplo 3

O que é imutável é o conteúdo físico de uma tupla, que armazena apenas referências a objetos. O valor da lista referenciado por dum[1] mudou, mas a identidade da lista referenciada pela tupla permanece a mesma. Uma tupla não tem meios de prevenir mudanças nos valores de seus itens, que são objetos independentes e podem ser encontrados através de referências fora da tupla, como o nome skills que nós usamos anteriormente. Listas e outros objetos imutáveis dentro de tuplas podem ser alterados, mas suas identidades serão sempre as mesmas.

Isso enfatiza a diferença entre os conceitos de identidade e valor, descritos em Python Language Reference, no capítulo Data model:

Cada objeto tem uma identidade, um tipo e um valor. A identidade de um objeto nunca muda, uma vez que tenha sido criado; você pode pensar como se fosse o endereço do objeto na memória. O operador is compara a identidade de dois objetos; a função id() retorna um inteiro representando a sua identidade.

Após dum tornar-se um rapper, os irmãos gêmeos não são mais iguais:

>>> dum == dee
False

Temos aqui duas tuplas que foram criadas iguais, mas agora elas são diferentes.

O outro tipo interno de coleção imutável em Python, frozenset, não sofre do problema de ser imutável mas com possibilidade de mudar seus valores. Isso ocorre porque um frozenset (ou um set simples, nesse sentido) pode apenas conter referências a objetos hashable (objetos que podem ser usados como chave em um dicionário), e o valor destes objetos, por definição, nunca pode mudar.

Tuplas são comumente usadas como chaves para objetos dict, e precisam ser hashable - assim como os elementos de um conjunto. Então, as tuplas são hashable ou não? A resposta certa é algumas tuplas são. O valor de uma tupla contendo um objeto mutável pode mudar, então uma tupla assim não é hashable. Para ser usada como chave para um dict ou elemento de um set, a tupla precisa ser constituída apenas de objetos hashable. Nossas tuplas de nome dum e dee não são hashable porque cada elemento contem uma referência a uma lista, e listas não são hashable.

Agora vamos nos concentrar nos comandos de atribuição que são o coração de todo esse exercício.

A atribuição em Python nunca copia valores. Ela apenas copia referências. Então quando escrevi skills = t_doom[1], não copiei a lista referenciada por t_doom[1], apenas copiei a referência a ela, que então usei para alterar a lista executando skills.append('rap').

Voltando ao MIT, a Profa. Stein falava sobre atribuição de uma forma muito cuidadosa. Por exemplo, ao falar sobre um objeto gangorra em uma simulação, ela dizia: “A variável g é atribuída à gangorra“, mas nunca “A gangorra é atribuída à variável g “. Em se tratando de variáveis de referência, é mais coerente dizer que a variável é atribuída ao objeto, e não o contrário. Afinal, o objeto é criado antes da atribuição.

Em uma atribuição como y = x * 10, o lado direito é computado primeiro. Isto cria um novo objeto ou retorna um já existente. Somente após o objeto ser computado ou retornado, o nome é atribuído a ele.

Eis uma prova disso. Primeiro criamos uma classe Gizmo, e uma instância dela:

>>> class Gizmo:
...     def __init__(self):
...         print('Gizmo id: %d' % id(self))
...
>>> x = Gizmo()
Gizmo id: 4328764080

Observe que o método __init__ mostra a identidade do objeto tão logo criado. Isso será importante na próxima demonstração.

Agora vamos instanciar outro Gizmo e imediatamente tentar executar uma operação com ele antes de atribuir um nome ao resultado:

>>> y = Gizmo() * 10
Gizmo id: 4328764360
Traceback (most recent call last):
  ...
TypeError: unsupported operand type(s) for *: 'Gizmo' and 'int'
>>> 'y' in globals()
False

Este trecho mostra que o novo objeto foi instanciado (sua identidade é 4328764360) mas antes que o nome y possa ser criado, uma exceção TypeError abortou a atribuição. A verificação 'y' in globals() prova que não existe o nome global y.

Para fechar: sempre leia lado direito de uma atribuição primero. Ali o objeto é computado ou retornado. Depois disso, o nome no lado esquerdo é vinculado ao objeto, como uma etiqueta afixada nele. Apenas esqueça aquela idéia de variáveis como caixas.

Em relação a tuplas, certifique-se que elas apenas contenham referências a objetos imutáveis antes de tentar usá-las como chaves em um dicionário ou itens em um set.

Este texto foi originalmente publicado no blog da editora O'Reilly em inglês. A tradução para o português foi feita por Paulo Henrique Rodrigues Pinheiro. O conteúto é baseado no capítulo 8 do meu livro Fluent Python. Esse capítulo, intitulado Object references, mutability and recycling também aborda a semântica da passagem de parâmetros para funções, melhores práticas para manipulação de parâmetros mutáveis, cópias rasas (shallow copies) e cópias profundas (deep copies), e o conceito de referências fracas (weak references) - além de outros tópicos. O livro foca em Python 3 mas grande parte de seu conteúdo se aplica a Python 2.7, como tudo neste texto.

por Luciano Ramalho em 24 de February de 2015 às 13:17

Aprenda Python

Admin do Web2py funcionando em máquina vagrant

Como fazer o admin do Web2py funcionar com uma máquina virtual Vagrant sem mexer na aplicação. Muito importante: essa solução foi projetada para funcionar em uma máquina de desenvolvimento, por isso o desempenho pode não ser satisfatório para um servidor de produção. Passo 1 - Configurar os redirecionamentos no Vagrantfile # ... vm.network "forwarded_port", guest: 8080, host: 9000 vm.network

por Vinicius Assef (noreply@blogger.com) em 24 de February de 2015 às 08:32

February 20, 2015

Osvaldo Santana Neto

Programador Freelancer

developer

Assine a minha newsletter quinzenal O Melhor da Internet e receba um resumo dos melhores materiais sobre Python, Django, Carreira e Empreendedorismo.


Esse artigo saiu inicialmente na O Melhor da Internet.

Durante muito tempo da minha vida eu trabalhei como programador freelancer. Eu até tive empresa, sócio, etc. mas o fato é que eu era um freelancer como qualquer outro. Afinal eu vendia o serviço, elaborava proposta, negociava, executava o projeto, cobrava, emitia nota fiscal, e dava suporte. Durante esse tempo eu aprendi algumas coisas que gostaria de compartilhar.

Freelancing não escala

Trabalhar como freelancer é divertido e dificilmente enfrentamos problemas com a rotina quando trabalhamos desta forma. Não temos que lidar com a rotina porque cada projeto é único.

Essa variedade de projetos é legal mas tem algumas desvantagens. Como eles são razoavelmente diferentes fica difícil reaproveitar o conhecimento adquirido durante a execução de um deles.

Como o freelancer precisa aprender coisas novas em quase todos projeto perde-se boa parte do “ganho de escala” do negócio. E é o ganho de escala que permite reduzir custos que geram margens de ganho maiores ou preços menores para o cliente. Isso não é bom nem ruim. É uma característica inerente do trabalho do freelancer.

Se o freelancer opta por “crescer” o negócio e montar uma empresa com vários funcionários (ou freelancers) precisa observar que ele pode até ganhar escala mas esse ganho será praticamente linear: para fazer 1 projeto precisa de 1 pessoa e para fazer 2 projetos provavelmente precisará de 2 pessoas.

Você pode até mudar a inclinação do gráfico projetos x pessoas mas ele dificilmente se curvará.

Você vende horas? Cobre por horas

Uma armadilha bastante comum para freelancers iniciantes é a de negociar um contrato com um escopo fechado. A coisa piora se o escopo não estiver muito detalhado.

Essa armadilha é mortal porque na imensa maioria dos casos o contrato vincula o pagamento do serviço à entrega do escopo. E, acredite, os clientes vão expandir esse escopo ao ponto de tornar o projeto prejudicial para o freelancer.

Eu sei que é difícil negociar um contrato baseado em horas de trabalho mas você tem que negociar nesses termos. É melhor não pegar o projeto do que negociá-lo por escopo e/ou vincular o pagamento ao escopo.

Sei que isso é bem complicado porque as contas para pagar chegam todos os meses sem piedade e aquele contrato com escopo fechado oferece uma oportunidade de ter dinheiro para pagar essas contas. Mas no médio prazo você pode acabar se tornando um escravo do projeto e ficar trabalhando de graça nele (ou até pagando para trabalhar).

O melhor para você e para seu cliente é trabalhar com entregas parciais em intervalos curtos e rápidos. Isso nos leva ao próximo ponto…

Atualização: logo depois que enviei O Melhor da Internet o meu amigo Elvis enviou um link para um artigo que ele escreveu onde ele ressalta o fato de que um freelancer raramente consegue vender 100% das suas horas disponíveis.

Atualização 2: Depois que o artigo foi publicado me lembrei de uma outra dica importante relacionada à esse tópico. Quando você está elaborando a proposta e negociando o projeto é importante incluir o tempo usado nesse processo no valor final do projeto. Se você não fizer isso essas horas sairão “de graça” para seu cliente. Para isso funcionar direito as propostas também precisam ter um prazo de validade que permita uma revisão de valores nos casos onde a negociação demora muito.

Não cobre “50% no início e 50% na entrega”

É uma prática bem comum trabalhar dessa forma: o freelancer recebe 50% quando inicia o projeto e o restante quando entrega ele pronto.

Existem duas pegadinhas nesse modelo: uma é o conceito de pronto (veja o tópico anterior) e a outra tem relação com um negócio chamado fluxo de caixa.

Uma das coisas que certamente mata uma empresa é a má gestão do seu fluxo de caixa. E um freelancer é uma empresa de uma pessoa só. Precisa gerenciar seu fluxo de caixa com muita atenção.

Quando você fecha um negócio e recebe por ele 50%+50% fica mais difícil de gerenciar o fluxo de caixa da empresa porque a segunda metade do pagamento vira um alvo móvel. Quando você vai entregar o projeto? Quando ele estará “pronto”?

No lugar de negociar 50%+50% prefira receber parcelas em intervalos regulares (mensalmente? quinzenalmente?). Pode-se até vincular os pagamento às entregas parciais do projeto.

Receber pelo trabalho em intervalos regulares e vincular isso às entregas parciais é o cenário perfeito porque facilita a gestão do fluxo de caixa do freelancer e aumenta a segurança do cliente que pagará por algo que já recebeu.

“Produtize” seus serviços

No primeiro tópico eu falei sobre o problema de escala associado ao freelancing e aqui eu vou apresentar uma forma de amenizar esse problema.

É raro mas acontece: quando um freelancer está trabalhando no seu milésimo projeto ele percebe que certos padrões surgem em todos eles. Exemplo: quase todos os projetos tem um formulário de contato, ou uma página com um mapa mostrando a localização da loja do cliente, ou tem algum sistema de monitoramento, backup, etc.

Quando o freelancer detecta um padrão desses ele pode ter certeza que existe uma oportunidade de transformar essa parte do projeto em um produto que pode ser vendido para vários clientes. Se você fizer isso vai ter um ganho de escala ou até mesmo alguma receita recorrente.

Certos projetos também são genéricos ao ponto de poderem ser transformados em produtos (com a devida anuência do cliente contratante). Um exemplo? Um dos meus clientes solicitaram o desenvolvimento de um sistema de avaliação de funcionários para o RH da empresa.

O sistema usava uma metodologia conhecida como “Avaliação 360°” e gerava relatórios para o RH da empresa avaliar os seus funcionários. O sistema foi desenvolvido para um cliente específico mas, certamente, poderia ser útil para outras empresas. Não foi o caso mas esse projeto poderia ter se transformado em um produto.

Outros tipos de produtos que você pode criar estão na forma de conteúdo. Em meu caso, por exemplo, escrevi um livro e criei um video-curso de programação Python e Django para vender na Internet (que, por não manter mais, acabei disponibilizando gratuitamente).

Crie receitas recorrentes

Todo negócio tem seu risco e com o freelancing não poderia ser diferente. Quando o freelancer está trabalhando e vendendo suas horas de trabalho para alguém as coisas ficam bem. Mas quando, por algum problema, isso não acontece as coisas podem ficar bem complicadas.

Um freelancer pode adoecer, o mercado pode dar uma esfriada, pode acontecer uma entresafra de projetos (ex. o período de novembro a março costuma ser difícil para novos projetos).

Uma maneira de lidar com essas dificuldades é cuidar para poupar nos períodos fartos para ter algo nos períodos difíceis como na fábula da Cigarra e das Formigas. Outro modo de lidar com essa questão é criando formas de se obter receitas recorrentes.

Ofereça serviços de manutenção, suporte, apoio, etc para os clientes que desenvolveram projetos com você. Crie mecanismos (honestos) para continuar recebendo dinheiro deles mesmo depois que o projeto tenha terminado. Ou crie algum produto (tópico anterior) que seja vendido na modalidade de assinatura.

Recuse clientes ruins

Essa é uma das coisas mais difíceis de colocar em prática porque, a menos que alguém nos avise, é quase impossível saber se um cliente novo é bom ou ruim. Mas alguns indícios podem ser observados:

  • Cliente que questiona demais os preços – pode ser uma preocupação legítima mas geralmente não é. Mostra que é um cliente mais preocupado com preços do que com qualidade. Ele vai apertar os seus ganhos e vai te trocar por outro mais barato na primeira oportunidade.
  • Cliente que não sabe o que quer e não te ouve – existem muitos clientes que não sabem exatamente o que querem e isso isoladamente não é um problema. Mas se você tentar ajudá-lo a descobrir e ele recusar a sua ajuda isso pode virar um problema.
  • Cliente que descumpre o combinado – você estabelece com o cliente que ele te pagará mensalmente e no dia do pagamento você tem que ficar lembrando e cobrando. Ou cliente que simplesmente te dá um calote. Eu costumava fazer um teste: eu “esquecia” de cobrar os meus clientes algumas vezes. É engraçado mas os meus melhores clientes sempre me enviavam e-mail avisando sobre meu “esquecimento”.
  • Cliente que oferece uma “oportunidade única” de trabalhar para ele – tem muito cliente que pede um precinho camarada em um primeiro projeto com a promessa de valores maiores em projetos futuros. Não caia nessa armadilha porque esse cliente não é fiel à você. Ele é fiel ao teu preço baixo. E não se engane… tem muita empresa grande e famosa que usa o próprio nome para obter essas vantagens. Se usarem o discurso do “você vai colocar a nossa empresa no teu portifólio!” respondam de forma sarcástica: “eu já gastei a minha verba de marketing para esse ano”.

Para clientes pré-existentes é sempre importante gastar algumas horas do mês para reavaliar a sua carteira de clientes e projetos. Cliente bom é aquele que cumpre com suas obrigações, gera bons projetos, indica você para novos clientes e te dá um bom lucro.

Automatize as tarefas chatas

Coisas chatas que freelancers precisam fazer e precisam ser automatizadas o mais rápido possível:

Responder e-mails de sondagem

Eu recebia muitos e-mails assim: “Oi, Meu nome é Fulano e gostaria de saber quanto você cobraria por um projeto assim e assado”. Você tem que responder à esses e-mails mas 80% deles são de aventureiros. Pessoas que não tem dinheiro para te contratar, não sabem o que querem e não vão fechar negócio contigo.

O problema é que não dá pra você diferenciar as boas oportunidades daquelas que vão fazer você perder tempo.

Um das coisas que funcionou razoavelmente bem comigo foi colocar informações detalhadas sobre o tipo de projeto que eu desenvolvia e um valor aproximado para minha hora de trabalho no site da empresa. Colocava destaque na informação: “Esses valores são negociáveis”.

Com essas informações a pessoa já consegue ter uma idéia se ele consegue contratar o seu serviço. A outra informação (valores negociáveis) filtrava os aventureiros daqueles que realmente queriam realizar o projeto.

O cara pode até não ter o dinheiro para te contratar mas se ele quiser muito realizar o projeto ele vai entrar em contato contigo para tentar negociar o prazo de pagamento, os valores, o escopo, etc. E isso, por si só, mostra que ele pode ser um bom cliente e gerar negócios.

Algumas pessoas (por medo ou desconhecimento) acreditam que essas informações no site afugentam clientes. Pode ser que sim. Mas pergunte-se: “Que tipo de cliente eu estou afastando?”.

Produzir e enviar propostas

Depois que você entende melhor o projeto é o momento de enviar uma proposta para seu cliente.

Se você ainda estiver negociando projetos com escopo fechado fica impossível automatizar essa etapa porque cada proposta será única e precisará ser bem detalhada, mas se você negociar em termos de horas a proposta fica bem mais simples. Você precisa apenas preencher os milestones do projeto (entrego X na data Y, …) e fazer uma multiplicação de horas pelo teu valor/hora.

Eu tinha um template no meu editor de textos onde eu só alterava os dados, gerava um PDF, e enviava para o cliente. Se o cliente já era antigo, muitas vezes, eu só mandava um e-mail: “imagino que dê pra gente trabalhar nisso em uma semana por R$X”. E o cliente respondia: “Ok, pode fazer”. Esse é o tipo de relação de confiança que você precisa construir com seus clientes.

Cobrança e NFe.

Cobrar o cliente e ver se ele pagou é uma daquelas coisas que nunca consegui automatizar 100% mas cheguei à um ponto onde isso não atrapalhava o resto das atividades.

Eu criei uma conta de cobrança sem registro na conta da empresa no banco (dica: não misture sua conta pessoal com a conta usada para seu trabalho) e emitia boletos para meus clientes pagarem. Cerca de 5 dias depois da emissão dos boletos eu puxava um extrato e conciliava os pagamentos na mão. No site da prefeitura eu emitia as NFe daqueles que haviam pagado o boleto.

Comecei com um software que só emitia os boletos e depois migrei para outro que emitia os boletos e a NFe.

Seja parceiro dos bons clientes

É provável que você não consiga resolver todos os problemas de seus clientes e, nestes casos, você deve ajudá-lo a encontrar as soluções para esses problemas. Mesmo que para isso você tenha que encaminhá-lo para um outro prestador de serviços (freelancer, empresa, etc).

Se você fizer isso o cliente criará um modelo mental muito positivo sobre você: “quando eu tenho um problema é só eu entrar em contato com esse cara que ele resolve ou me ajuda a resolver”. Esse modelo mental é poderosíssimo para gerar novos negócios.

Cumpra combinados e faça com qualidade

Deveria ser o primeiro item mas resolvi deixá-lo para o final para que fique mais fresco na sua memória.

É da mais absoluta importância para um profissional que ele cumpra aquilo que foi combinado com o cliente. E mais do que isso… é importante que tudo seja feito com a maior qualidade.

Cumprir com o combinado manterá o seu cliente fiel à você. Fazer isso com qualidade transformará ele num canal de vendas.

Gostou desse artigo?

Assine a minha newsletter quinzenal e receba artigos sobre Programação, Python, Django, carreira e empreendedorismo.

The post Programador Freelancer appeared first on osantana.

por Osvaldo Santana em 20 de February de 2015 às 01:42