Pequena dica de Python: __missing__

A partir do Python 2.5, ao estender dicionários, você pode dar a suas classes um método __missing_, que será executado toda vez que você tentar acessar um índice inexistente. Veja:

class Counter(dict):
    def __missing__(self, key):
        self[key]=0
        return self[key]

Veja funcionando:

>>> votos=['john','paul','john','john','ringo',
...        'george','paul','ringo','ringo','john',
...        'paul','john','george','paul','paul',
...        'john','paul','john','ringo','paul']
>>> c=Counter()
>>> for v in votos:
...     c[v]+=1
... 
>>> c
{'ringo': 4, 'paul': 7, 'john': 7, 'george': 2}

Configurando o encoding padrão no Python

Dica: ao iniciar o desenvolvimento com Python em uma máquina nova, procure pelo arquivo sitecustomize.py e acrescente:

import sys
sys.setdefaultencoding('utf-8')

O arquivo sitecustomize.py é automaticamente executado toda vez que você executa o Python (sim, você pode fazer o que quiser nele…) Ele fica em lugares diferentes dependendo da plataforma e da sua instalação do Python. No Ubuntu, fica em /usr/lib/python2.7/ (trocando 2.7 pela versão que você estiver usando.) As linhas acima configuram o encoding padrão como Unicode UTF-8. Claro, você pode configurar outro encoding como o padrão, se preferir.

Recomendo muito que, se você não entende nada de charsets ou nem sabe do que estou falando, use UTF-8.

Dica de Python: iPython

A maioria dos programadores Python gasta bastante tempo no shell interativo. É onde fazemos debugging e testamos novos módulos. É também nossa calculadora (piada interna, quem lê, entenda.) Muitos programadores não conhecem o iPython, uma versão “vitaminada” do shell interativo. No site há versões para download para Windows e em formato de Python-EGG. Para instalá-lo no Ubuntu, você pode usar os repositórios do APT. Use:

sudo apt-get install ipython

Depois disso, é só chamar ipython no terminal ao invés de python quando quiser usar o shell interativo. Mesmo que você não conheça os truques do iPython, já deve achar muito útil usá-lo. Vai ter um formato de output mais fácil de ler que o do shell interativo padrão, prompts coloridos e autocompletar (pressione TAB)

Além disso, há alguns recursos fáceis de usar no iPython que realmente vale a pena conhecer. Experimento digitar, por exemplo:

import glob
glob?

Experimente também:

glob??

O iPython tem muito mais, mas o que já descrevemos aqui deve ser suficiente par quem vai usá-lo pela primeira vez.

Meu ambiente de trabalho em 7 itens

O Mike me convidou, então lá vai:

1. Ubuntu

O sistema operacional que simplesmente funciona. Meu notebook tem Ubuntu, o da minha mulher e os dos meus filhos também. Todos tem o Windows OEM em dual-boot. Nem me lembro quando foi a última vez que vi alguém bootar o Windows lá em casa. Aqui na Visie o Ubuntu também parece ser o sistema predileto de todo mundo que não tem um Mac 😉

Sem brincadeira, se você desenvolve para um sistema Unix-like, deveria usar um. Você vai ter o mesmo modelo de permissões, a mesma estrutura de arquivos e as mesmas ferramentas na sua máquina e na hospedagem. Você vai ter shell script. Um dia desses resolvemos um problema em um projeto criando um link simbólico para um arquivo. Essa solução roda em nossos servidores e em nossos desktops.

2. Git

Ainda encontro muitas empresas por aí que não usam controle de versão. Pode parar de rir, estou falando sério. Eu não entendo como alguém pode escrever software sem um bom sistema de controle de versão distribuído.

3. web2py

O framework de desenvolvimento web mais produtivo que eu já achei.

4. Vim

Vim não é fácil, e deve ser mantido fora do alcance de crianças e animais domésticos. Mas é o editor de código mais rápido do planeta. Extremamente poderoso, indispensável para o bom programador.

5. Firefox e Firebug

O desenvolvimento de HTML, CSS e Javascript se divide em duas eras: antes e depois da Firebug.

6. OpenDNS e Dnsmasq

Nós até conseguimos comprar boas conexões aqui no Brasil. Mas os serviços de DNS de todos os provedores que eu conheço são uma piada.

7. Terminator

Com o Terminator posso dividir uma janela em vários terminais, em abas. Para quem usa vim e muito shell, é uma mão na roda.

E eu vou convidar:

Diego Eis, Ederson Peka, Luciano Motta, Mauro Baraldi, Leandro Lima e Pedro Rogério.

XML não é a resposta 2: parsing

Em meu último post sobre esse assunto, expliquei porque prefiro, na maioria dos casos, usar um formato de descrição de dados como JSON ao invés de XML. Infelizmente, parece que nem todo mundo concorda comigo, e há uma porção de dados úteis disponíveis apenas em XML. O que não é um problema, certo? Do que eu estou reclamando? Os dados estão lá, disponíveis publicamente, muitos de graça, e eu aqui reclamando do formato?

Vamos dar um jeito e ler XML!

A maneira óbvia parece ser usar um parser de XML, e é o que eu faço na maioria dos casos. Toda linguagem e ambiente de desenvolvimento hoje possuem bons parsers de XML para você escolher. Mas nem sempre o parser de XML é a melhor solução.

Vamos tomar como exemplo o retorno do rssWeather.com:

http://www.rssweather.com/wx/br/sao+paulo+aeropor-to/rss.php

A resposta é um RSS com uma tag content:encoded, contendo uma seção CDATA com um trecho de HTML. Você vai ter que fazer duplo parsing se quiser as informações de dentro desse HTML. Ou pode adotar uma solução assim:

import urllib2,re
url='http://www.rssweather.com/wx/br/sao+paulo+aeropor-to/rss.php'
xml=urllib2.urlopen(url).read()
data=dict(re.findall('<dt.*>(.*)</dt><dd.*> ?(.*)</dd>',
        xml.replace(':','').replace('&#176;','\xc2\xb0')))

Cinco linhas de código. Dê uma olhada no retorno disso:

>>> data
{'Barometer': '1028 mb', 'Wind Speed': '10 KMH', 'Dewpoint': '15\xc2\xb0C', 'Wind Direction': 'SSE (160\xc2\xb0)', 'Visibility': '6 km', 'Humidity': '93%', 'Wind Chill': '15\xc2\xb0C', 'Heat Index': '16\xc2\xb0C'}
>>> for i in data.iteritems(): print '%s => %s' % i
... 
Barometer => 1028 mb
Wind Speed => 10 KMH
Dewpoint => 15°C
Wind Direction => SSE (160°)
Visibility => 6 km
Humidity => 93%
Wind Chill => 15°C
Heat Index => 16°C

É importante entender os riscos que estamos assumindo ao adotar essa solução. Se o formato desse HTML for ligeiramente modificado, nosso código pode parar de funcionar. Neste caso, como os dados estão em HTML dentro do XML, isso não é uma desvantagem, porque você teria o mesmo tipo de problema usando um parser SGML.

Será que conseguimos a mesma simplicidade lendo HTML?

import urllib2
url='http://www.bancocentral.gov.br/'
html=urllib2.urlopen(url).read()
dados=html.replace(',','.').split('')[0].split('\r\n')[-7:]
dados=map(float,(dados[0].strip(),dados[3].strip()))

Veja o retorno:

>>> print 'Compra: %.4f, Venda: %.4f' % tuple(dados)
Compra: 1.7784, Venda: 1.7792

XML não é a resposta

Não me entenda mal, XML é uma idéia interessantíssima, pela qual sou apaixonado. Tenho dado aula de XML, escrito HTML como XML válido, publicado e consumido dados em XML, acompanhado as iniciativas de Open Data e RDF no W3C.

O problema é que, enquanto alguns mercados subutilizam XML, tornando o intercâmbio de dados muito complexo, outros exageram no uso. XML não é a panaceia da troca de dados.

Há, por exemplo, uma porção de sistemas que usam XML como arquivos de configuração. Isso torna complicado o trabalho de editar esses XML, e na maioria dos casos torna complicado o parsing disso para rodar o sistema.

Veja um breve exemplo: a busca do Twitter está disponível em três formatos, HTML, ATOM e JSON. Teste a busca a seguir nesses três formatos (veja a diferença nas URLs):

http://search.twitter.com/search?q=%40elcio (HTML)

http://search.twitter.com/search.atom?q=%40elcio (ATOM)

http://search.twitter.com/search.json?q=%40elcio (JSON)

A maneira como o Twitter publica suas buscas é inspiradoras. O formato ATOM servirá para leitores de feeds e para aqueles programadores que adoram escrever parsers XML. E para o resto do mundo, temos JSON. Veja como consumir a URL JSON e obter dados nativos no Python:

import json,urllib2
url='http://search.twitter.com/search.json?q=%40elcio'
dados=json.load(urllib2.urlopen(url))

A dica então é se perguntar se XML é necessário e, se não tiver um bom motivo para usá-lo, trabalhar com JSON, YAML ou, quem sabe, um arquivo de configuração declarando variáveis em sua própria linguagem.

Parallel Python

Embora seu computador possa ter dois, quatro, oito ou até dezesseis núcleos de processamento, o Python só usa um deles de cada vez (mesmo trabalhando com threads). Parallel Python resolve o problema. Um exemplo simples, para você entender como funciona:

ppserver = pp.Server(ppservers=())
job1 = ppserver.submit(funcao_demorada, (), (), ())
job2 = ppserver.submit(funcao_demorada, (), (), ())
print job1()+job2()

Os quatro argumentos do método submit são: a função que será executada, os argumentos passados a ela, as funções que ele pode chamar e os módulos dos quais ela depende. Veja um exemplo de como chamar com esses parâmetros:

ppserver = pp.Server(ppservers=())
job1 = ppserver.submit(funcao_demorada, (44,), 
                        (sub_funcao,), ("sys","math",))
job2 = ppserver.submit(funcao_demorada, (25,),
                        (sub_funcao,), ("sys","math",))
print job1()+job2()

Divirta-se!

Rodando comandos do sistema operacional com cache no Python

Código simples, mas que pode ser útil para alguém não ter que escrevê-lo de novo (arquivo runcached.py):

import os,time
cachepath='cache'
timeout=360
 
def runcached(cmd):
  filename=os.path.join(cachepath,str(hash(cmd)))
  if os.path.isfile(filename):
    if time.time()-os.path.getmtime(filename)<timeout:
      return open(filename).read()
  t=os.popen(cmd).read()
  open(filename,'w').write(t)
  return t

A função runcached roda comandos do sistema operacional, e faz cache do resultado por 6 minutos. Para alterar o tempo do cache, basta mudar a variável timeout. Por exemplo, para cachear por 10 horas:

import runcached
runcached.timeout=36000
r=runcached('lynx --source http://www.tableless.com.br')

Instalando o CouchDB e o Python-CouchDB no Ubuntu 8.10 (Intrepid)

Não a versão do repositório, mas a mais nova.

Só a sequência de comandos, que eu estou com pressa agora:

sudo apt-get install build-essential erlang libicu38 libicu-dev libmozjs-dev automake autoconf libtool help2man libcurl-ocaml-dev subversion python-setuptools
mkdir ~/src
cd ~/src
svn co http://svn.apache.org/repos/asf/couchdb/trunk couchdb
cd couchdb
./bootstrap && ./configure && make && sudo make install
sudo adduser --system --home /var/lib/couchdb --no-create-home --shell /bin/bash --group --gecos "CouchDB Administrator" couchdb
sudo chown -R couchdb /usr/local/var/lib/couchdb/
sudo chown -R couchdb /usr/local/var/log/couchdb/
sudo easy_install simplejson
sudo easy_install httplib2
sudo easy_install couchdb

Fuja da complexidade

Abri o OpenOffice Writer, mandei gravar uma macro, escrevi “teste”, selecionei e pintei de vermelho. Olha o código gerado:

sub Main
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "teste"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())
rem ----------------------------------------------------------------------
dispatcher.executeDispatch(document, ".uno:SelectAll", "", 0, Array())
rem ----------------------------------------------------------------------
dim args3(0) as new com.sun.star.beans.PropertyValue
args3(0).Name = "FontColor"
args3(0).Value = 16711680
dispatcher.executeDispatch(document, ".uno:FontColor", "", 0, args3())
end sub

Há muito código complexo por aí. Nesse caso, para invocar os métodos dos objetos do OpenOffice, é preciso usar um objeto dispatcher, chamando executeDispatcher, e passando o objeto, o nome do método e um array de argumentos. Que espécie de sadismo leva alguém a projetar uma solução como essa? Vale lembrar o que diz o Zen do Python:

Se uma implementação é difícil de explicar, é uma idéia ruim.

Outro exemplo interessantíssimo é o protocolo SOAP. Se você precisar construir um serviço SOAP do zero, dê uma investigada na documentação que você vai ter que ler. Compare com a documentação do protocolo XML-RPC, para ter uma idéia.

Meninos, o tio vai ensinar um segredo a vocês, a complexidade se reproduz assexuadamente. Há muito código complexo demais por aí. Se você encontrar indícios de complexidade hoje, corte antes que ela se reproduza, porque ela tende a fugir do controle. Cada vez que você deixa uma implementação complexa num componente de um sistema, você está complicando um pouquinho todos os pontos do sistema que usam aquele. Os resultados ruins são exponenciais. Por mais talentoso que você seja, se deixar a complexidade se enraizar e crescer, vai chegar um momento em que a lógica vai “jogar a toalha” e você vai começar a programar na base da tentativa e erro.

Lembre-se, então, partes simples, conectadas por interfaces simples. Complicado é errado, feio e mau, faz você entregar atrasado e com bugs. E, se precisar de inspiração, abra o Python e digite:

import this

Resolvendo equações do segundo grau com Python

Meu amigo Vicente Marçal me escreveu:

Bem, sei que és professor de Python, além de amante da linguagem e, por isso, acabei fazendo pesquisas sobre ela e estou estudando por conta, mais por hobby do que por qualquer outra coisa. Então, num tempinho livre que vc tiver, avalie esse meu pequeno script o qual disponibilizei na comunidade Viva o Linux:
http://www.vivaolinux.com.br/script/Raizes-de-Funcao-Quadratica, ele é bem simples, mas gostaria muito de sua opinião a respeito.

Eu respondi, e pedi a ele autorização para publicar minha resposta aqui. Como ele autorizou, lá vai. Vamos começar pelo arquivo, baskara.py:

# -*- encoding: utf-8 -*-
'''
Funções matemáticas para equações do segundo grau.
'''
from math import sqrt
 
def baskara(a,b,c):
  '''
  Função que fornece as raízes de uma equação do segundo grau.
  No caso de não haver raízes, retorna uma tupla vazia.
  Exemplos:
  >>> baskara(1,5,4)
  (-1.0, -4.0)
  >>> baskara(1,4,4)
  (-2.0,)
  >>> baskara(4,4,4)
  ()
  >>> baskara(0,4,2) # se a é zero, temos uma equação do primeiro grau
  (-0.5,)
  '''
  a,b,c=float(a),float(b),float(c)
  if(a==0):return (-c/b,)
  delta=b**2-4*a*c
  if delta<0:return ()
  if delta==0:return (-b/(2*a),)
  return ((-b+sqrt(delta))/(2*a),(-b-sqrt(delta))/(2*a))
 
if __name__=="__main__":
  # Se rodou o arquivo diretamente, sem importar, roda os testes.
  import doctest
  doctest.testmod()

 

E meus comentários:

Cara, para que tanto underline? O underline no python indica que algo é especial. Underlines no começo indicam algo privado, em que você não deve mexer. No começo e no fim, indicam um nome especial, criado pela linguagem. No caso de sua função, não há necessidade de underline em nada, nem no nome da função, nem nos parâmetros.

Segue anexa minha implementação. Os pontos a notar:

1. Docstring. Aquele formato de comentários que eu estou usando serve para que o Python entenda que eles são documentação. Coloque meu arquivo em algum lugar em sua máquina, rode o Python e execute:

import baskara
help(baskara)

Você vai entender.

2. Doctest. Se você reparar, na docstring da função há um trecho de exemplo que parece uma sessão do shell interativo. Está lá assim de propósito. Esperimente quebrar a função. Por exemplo, modifique a linha que calcula o delta, trocando o número 2 por 3. Em seguida execute:

python baskara.py

Ele vai rodar os testes automáticos. Você deve ver três erros.

E é isso aí, boa sorte com o Python, é uma linguagem que vale a pena estudar.

Dicas de shell: testes unitários e commit

Todas as tarefas relacionadas a contrução, teste e publicação de um desenvolvimento de software[bb] devem ser automatizadas o máximo possível. Escrever software é interar. Você escreve e testa, escreve e testa, escreve e testa dezenas, às vezes centenas de vezes por dia. As tarefas relacionadas a testar o software, de maneira especial, merecem a automatização que for possível dar a elas. Convenhamos, testar é algo muito chato. E se for complicado testar, será uma tentação irresistível para o programador entregar seu código sem testar adequadamente.

Hoje vamos construir um script de commit no subversion[bb] que, antes de enviar o código, executa todos os testes unitários. Vou trabalhar com Python[bb], mas você não deve ter dificuldades em adaptar isso para a sua linguagem de programação predileta.

A primeira coisa importante é que você entenda que todo script executado no shell tem um valor de retorno. Esse valor é retornado pelo comando, e também armazenado na variável especial $?. Veja estes exemplos:

$ echo $?
2
$ ls test
test
$ echo $?
0
$ if ls test2;then echo O arquivo existe.;fi
ls: test2: Arquivo ou diretório não encontrado
$ if ls test;then echo O arquivo existe.;fi
test
O arquivo existe.
$ if ! ls test;then echo O arquivo não existe.;fi
test
$ if ! ls test2;then echo O arquivo não existe.;fi
ls: test2: Arquivo ou diretório não encontrado
O arquivo não existe.

Os testes foram construídos usando o módulo para testes unitários unittest do Python. Cada teste está, no diretório do projeto, junto do arquivo de código que ele testa. E o nome dos arquivos de teste sempre começam com “test”. Assim, o arquivo connections.py é testado pelo testconnections.py.

Veja então nosso shell script, salvo com o nome de commit, que será usado durante todo o projeto para rodar os testes antes do commit:

#!/bin/bash
 
# Começamos com um contador de erros em zero
erros=0
 
# Encontramos cada um dos testes
for i in `find -name "test*.py"`;do
echo TESTANDO: $i
echo
 
# Se o teste falhar, incrementamos a variável erros
if ! python $i;then
erros=$(($erros + 1))
fi
 
echo
done
 
# Se os testes passaram, fazemos commit, caso contrário
# avisamos o usuário
if [ $erros == 0 ];then
# Esse $* passa os parâmetros de linha de comando recebidos para o svn.
svn ci $*
else
echo Testes falharam, commit cancelado.
fi

Tendo feito isso, e colocando esse script em /usr/local/bin, o programador vai trocar svn ci por commit, e os testes serão feitos automaticamente antes do commit. Ele também pode passar parâmetros do svn para o script:

commit -m "Criei o link espacial com saturno"

Retornando o último número (script Python)

Meu amigo DGmike publicou: Retornando o último número (script PHP)

Como eu acho interessante comparar soluções em linguagens diferentes, resolvi escrever o mesmo script em Python[bb]. Veja como ficou:

import re
def ultimoNumero(string):
    return re.findall(r"\d+",string)[-1]

Gostou?

Instalando o PSE no Ubuntu 7.10 Gutsy Gibbon

O novo Ubuntu[bb] 7.10 está maravilhoso. Até o 7.04 eu usava um hack para fazer funcionar minha placa de rede, agora ela funciona sem truques. O compiz já instalado funcionou sozinho, bem direitinho. O resto tudo também funcionou sem dor. Menos o PSE.

Por algum motivo estranho, a versão do mod_python (3.3.1) desse novo Ubuntu reclama de sei lá o que. A versão anterior (3.1.3) funcionava sem problemas. Dei um jeito aqui de colocar para funcionar. Não sei se é uma boa saída, se alguém tiver uma sugestão melhor, por favor.

Segue a receita de bolo para instalar o PSE no novo Ubuntu:

  1. Instale os pacotes necessários: sudo apt-get install apache2 libapache2-mod-python python-profiler build-essential latex2html
  2. Baixe o PSE: wget http://nick.borko.org/pse/PSE-3.0.6.tar.gz
  3. Extraia o código fonte: tar -xzvf PSE-3.0.6.tar.gz
  4. Entre na pasta: cd PSE-3.0.6
  5. Compile e instale: sudo python setup.py install
  6. Edite o arquivo de configuração do Apache: sudo gedit /etc/apache2/apache2.conf
    Acrescente ao final:
    PythonHandler pse_handler
    AddHandler python-program .pt
  7. Aqui vai o hack: sudo gedit /usr/lib/python2.5/site-packages/mod_python/importer.py
    Encontre a linha 303, que deve ser:
    return __import__(module_name, {}, {}, '*')
    E edite para ficar:
    return __import__(module_name, {}, {}) #, '*')
    Cuidado para não quebrar a identação!
  8. Reinicie o Apache: sudo invoke-rc.d apache2 restart

Pronto, deve funcionar. Aqui para mim foi só isso.

Tradutor Português-Portunhol

Falta uma semana para lo dia internacional de hablarse portuñol. Fica aqui minha contribuição ao ócio e falta do que fazer, fruto de uma tarde de feriado entediante: tradutor automático de sites português-portunhol. Você pode, por exemplo, ver este site traduzido para o portuñol[bb].

Tomara que você ache tão divertido de usar quanto eu achei construí-lo.

Acentuação em Português e Expressões Regulares Python

Ao utilizar expressões regulares em Python[bb], por padrão, seu texto é interpretado como uma seqüência de caracteres ASCII comum. Assim, caracteres acentuados são considerados sinais gráficos especiais, e não são capturados como letras. Veja este exemplo:


>>> import re
>>> print re.sub(r"\b","|","era uma criança")
|era| |uma| |crian|ç|a|

Como você pode ver, o ce-cedilha não é considerado uma letra, “quebrando” a palavra. Resolver isso é muito fácil, basta compilar a expressão regular passando a flag L, para que ela siga o locale de sua máquina, ou a flag U, para que ela trabalhe com unicode. No meu caso, em que o locale da máquina é unicode, tanto faz. Veja como funciona:


>>> import re
>>> c=re.compile(r"\b",re.U)
>>> print c.sub("|",u"era uma criança")
|era| |uma| |criança|

Só não se esqueça de trabalhar com strings unicode.

Um pouquinho mais da sintaxe do Python

Um amigo meu está fazendo faculdade, e começando a aprender a programar (com Java[bb].) Ele me mostrou semana passada um exercício que o professor passou:

  • Solicitar que o usuário informe um número inteiro que será usado como limite superior do contador.
  • O programa deverá exibir todos os números pares existentes entre 1 e o limite superior (informado via teclado pelo usuário).
  • Após a exibição dos números o programa deverá perguntar se o usuário deseja executar mais uma vez.

Por curiosidade, eu escrevi uma solução em Python[bb]:

continuar=True
while continuar:
  numero=int(raw_input("Informe o valor inicial da repeticao: "))
  print str(range(2,numero+1,2))[1:-1]
  continuar=raw_input("Continuar? (S/N) ").upper()!="N"

Update: inspirado nos comentários do Rafael Santini, uma solução com break fica mais elegante:

while 1:
  numero=int(raw_input("Informe o valor inicial da repeticao: "))
  print str(range(2,numero+1,2))[1:-1]
  if raw_input("Continuar? (S/N) ").upper()=="N":break

Python X Java X Smalltalk

Achei muito interessante este artigo comparando a sintaxe de Smalltalk com Java. Implementei os mesmos exemplos em Python, para que você possa comparar a sintaxe:

Problema: cálculo de fatorial

def factorialRecursive(n):
  if n<0:return 0
  if n==0:return 1
  return n*factorialRecursive(n-1)

Ou assim:

def factorialNonRecursive(n):
  if n<0:return 0
  return reduce(lambda a,b:a*b,[1]+range(1,n+1))

A recursividade pode parecer uma solução elegante, mas o consumo de memória é assombroso nesse caso, em qualquer linguagem. Calcular a fatorial de um número grande qualquer pode ser um problema com a recursividade. Por isso, prefira a versão não recursiva.

No novo Python 2.5 você pode fazer:

def fact(x): return (
  0 if x<0 else
  reduce(lambda a,b:a*b,[1]+range(1,x+1))
)

Aqui é difícil dizer qual é mais prática, Smalltalk ou Python. Você pode palpitar sobre qual é mais elegante, uma vez que as soluções são radicalmente diferentes, mas a escolha final é subjetiva.

Problema: imprimir os números de 1 a 10

Eu faria usando os recursos de programação funcional:

print "\n".join(map(str,range(1,11)))

Mas você pode preferir:

for i in range(1,11):
  print i

De qualquer maneira, ponto para o Python[bb] aqui.

Problema: trabalhando com Collections

l=[
  'Em Python,',
  'chamamos as',
  'collections',
  'de "listas"',
]
print "\n".join(l)

Aqui, indiscutivelmente, ponto para o Python.

Problema: mostrar os pares e ímpares entre 1 e 10

for i in range(1,11):
  print i,["is even","is odd"][i % 2]

Novamente, o Python ganha disparado.

Problema: invocar um método via Reflection

É bem fácil:

o=MyClass()
getattr(o,"showMessage")()

Aqui o páreo é duro, Python e Smalltalk correm cabeça-a-cabeça. Na minha opinição, Python ganha por um focinho.


PythonPara saber mais sobre Python recomendo o PythonBrasil.

Além disso, sou professor do Curso de Python da Visie.