Novo Blog

Novo endereço

https://blog.nilo.pro.br

sexta-feira, 3 de agosto de 2012

Python Computer e Raspberry Pi

Preparação

Segunda (30/07/12), recebi meu primeiro Raspberry Pi, comprado na Element 14. Depois de um mês de espera, recebo na caixa do correio, mas um tanto tarde na Bélgica… 21h. Na verdade, chegou perto do meio dia, mas como não estava em casa, o carteiro deixou como carta normal mesmo.
P1060883
A caixa é bem pequena, como um cartão de crédito. Na realidade, eu encontrei o computador no meio de outras cartas Open-mouthed smile!
O problema é que não tinha nenhuma loja aberta para comprar um cabo ou outro, caso precisasse. O jeito era improvisar.
Eu sabia que ia precisar de um Hub USB com alimentação, pois a USB do Pi não fornece muita energia. Sabendo que o computador estava para chegar, eu comprei um Hub USB de 4 portas, ainda no sábado, aproveitando a visita ao supermercado:
P1060882
E também cartas SD:
P1060878
Pois o Pi só dá boot pela carta SD. Comprei uma carta de 4GB e outra de 8GB, pois uma era classe 4 e a outra classe 10. Aparentemente o Pi tem problemas com cartas classe 10, mas a minha funcionou perfeitamente, mas sem ganho de performance notável.
Antes mesmo de conectar o computador, é preciso baixar o Linux e gravá-lo na carta SD. Instruções detalhadas em inglês são encontradas aqui. Se você usa Windows, precisa baixar o Win32DiskImage. Ele não tem setup, é só descompactar e executar direto. Você precisa ser administrador do computador para gravar a imagem. Eu utilizei o Raspbian, mas outras distribuições também estão disponíveis. A imagem do Raspbian tem uns 450MB e ao descompactá-la você terá o arquivo .img, necessário para o Win32DiskImage.
Gravar a imagem é bem fácil. Introduza o cartão SD no leitor do computador. Normalmente o Windows se oferece para abri-lo. Aproveite a chance para verificar se este está vazio, pois a gravação da imagem vai apagar todo o conteúdo do cartão. Com o Win32DiskImage aberto, selecione o arquivo .img com o Raspbian e ao lado verifique se o drive com a carta SD está correto. Se você tem mais de uma carta SD ou caso apareça mais de uma opção, verifique o que está fazendo, evitando assim perder seus dados. Clique no botão Write e espere a gravação ser finalizada.
Com a carta SD pronta, resta a conexão do Raspberry Pi.
P1060886
Como já estava tarde, montei uma mesa de trabalho no chão da sala, usando uma caixa de monitor e uma folha A4 para dar noção do tamanhão do Raspberry Pi. Sem medir muito, eu chuto que numa folha A4 caberiam 9 Raspberry Pis!
Esta placa contém um SoC (System on a Chip) fabricado pela Broadcom, no caso do modelo B, um BCM2835 com:
  • Processador ARM1176JZF-S (armv6k) rodando a 700 MHz
  • 256 MB de Ram
  • 2 portas USB 2.0
  • 1 porta Ethernet
  • GPU Broadcom VideoCore IV
  • Leitor de carta SD
  • Saída de vídeo HDMI
  • Saída de vídeo composto (conector RCA)
  • Saída de áudio padrão, 3.5 mm
  • Conector de entrada e saída genérico com GPIO/UART/I2C e SPI
  • Dimensões: 85.60 x 53.98 mm
  • Peso: 45g
Um verdadeiro micro sem ventilador e de baixo custo (35€ com frete).
Para conectá-lo à minha TV, emprestei o cabo do vídeo game Open-mouthed smile. Mouse e teclado eu peguei os que uso com meu notebook. Duro foi achar o cabo com o conector Micro B USB. Eu consegui um carregador de celular:
P1060884
Ficou assim:
P1060889
É preciso ter cuidado ao conectar e desconectar o Raspberry Pi. Como a placa não tem gabinete, todas as precauções contra eletricidade estática devem ser tomadas. Não se pode esquecer também de não forçar os conectores e principalmente que o Pi não tem On/Off: ligou a força ele já está ON e dando o boot!
P1060887
Até aqui tudo certo. Mas ao tentar usar o teclado, este não respondia e o Pi chegou a travar. Lembrei então que ele precisa de pelo menos 700mA para funcionar. Checando o carregador de celular que encontrei, vi que ele só fornecia 300 mA. Ele foi então substituído por um cabo USB normal ligado ao carregador de um iPhone. Depois, eu eliminei o carregador e liguei tudo no Hub alimentado. Com a fonte certa, tudo passou a funcionar corretamente.
Ao dar o boot, ou executando sudo raspi-config, você tem a tela do utilitário de configuração simplificada abaixo:
raspconfig
Como meu cartão era de 4 GB, a primeira coisa que fiz foi selecionar expand_rootfs. Esta opção aumenta o disco criado pela restauração da imagem para utilizar todo o cartão. Depois, eu configurei o teclado (configure_keyboard), troquei a senha do usuário pi (change_pass) e o fuso horário (change_timezone). Para sair é só selecionar Finish e dar boot.
O Pi não tem relógio permanente, ele usa um servidor de tempo para ajustar o relógio durante o boot. Configurar o fuso horário é importante por isso.
Esqueci de falar do acesso à Internet. Eu apenas liguei um cabo Ethernet que estava sobrando e o Pi pega um IP usando DHCP. O acesso fica muito fácil e no próximo boot ele já sincroniza o horário, pega um IP e você fica pronto para usar a Internet ou sua rede local. Eu não tenho um cartão WiFi USB, mas se for o caso, na wiki do Raspbery Pi tem a lista dos WiFi compatíveis.
Meu teste era plugar um leitor de DVD externo (USB) e assistir um vídeo antes de dormir. Instalei o VLC, usando o apt-get, mas não consegui ver vídeo algum. Tentei também com arquivos AVI, sem sucesso. Acho que nestes casos o melhor é tentar a OpenElec com o XBMC.
Entrei no X, digitando startx. Baixei o Invasores e funcionou de primeira, com som na TV!
P1060893
Fiquei surpreso ao constatar que o PyGame já vinha instalado. Mesmo um jogo simples como o Invasores teve algumas paradas. Tentei então os jogos pré-instalados e observei o mesmo problema. O X é pesado demais para o Pi.
O Browser é muito simples e não suporta HTML5, muito menos flash. Além disso… quando digo muito lento, não estou exagerando. Lembra os primeiros anos de Windows… mas roda. Instalei o Chromium, versão open source do Google Chrome, mas também é muito lento e pesado. Não podemos esquecer que um browser moderno consome muita memória e que rodar JavaScript exige um processador bom. Nem memória, nem processador sobram no Raspberry Pi para este tipo de coisa. Os drivers ainda estão sendo desenvolvidos e quase tudo roda sem otimização/aceleração da GPU. Novas versões devem melhorar esta situação.

Python Computer

Meu objetivo ao comprar o Raspberry Pi era de configurar um Linux para funcionar como estação de ensino de Python. Como o Pi de Raspberry Pi vem de Python… apareceu a oportunidade. Eu chamei meu projetinho de Python Computer. A ideia era configurar o Linux como um computador de 8 bits que ligava e caia no interpretador Basic. No caso, eu queria um Linux que ligasse e entrasse no interpretador Python. Eu já havia feito um teste usando SilverLight para executar o Python Computer em um browser. Porém, esta solução dependeria de acesso a Internet, versão do browser, plug ins, etc. Ter tudo num pequeno computador me parece mais interessante.
Para isso, o X não é realmente necessário. No Linux, a PyGame pode rodar no framebuffer. Esta configuração me pareceu mais realista que um ambiente gráfico completo no Raspberry Pi.
A primeira coisa que fiz foi mudar o tamanho da fonte de texto, pois a padrão é muito pequena para se ler na TV.
Isso pode ser feito editando o arquivo /etc/default/console-setup como root:

sudo vim /etc/default/console-setup

Na linha que contém FONTFACE escreva:

FONTFACE=”TERMINUS”

e na com FONTSIZE:

FONTSIZE=”16x32”

Salve o arquivo.

Para configurar o vim, crie o arquivo ~python/.vimrc com as seguintes linhas:


syntax on
set ts=4
set expandtab
set shiftwidth=4
set softtabstop=4
set smartindent
set number
set cindent
set nowrap
set go=+b

autocmd BufRead *.py set makeprg=python\ -c\ \"import\ py_compile,sys;\ sys.stderr=sys.stdout;\ py_compile.compile(r'%')\"
autocmd BufRead *.py set efm=%C\ %.%#,%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,%Z%[%^\ ]%\\@=%m
autocmd BufRead *.py nmap <F5> :!python %<CR>



Agora crie o usuário python:

sudo useradd –m –s /usr/bin/ipython python

E edite o inittab:

sudo vim /etc/inittab

Modifique a linha do terminal 6, no meu inittab a linha 59. De:

6:23:respawn:/sbin/getty 38400 tty6

para:

6:23:respawn:/sbin/getty 38400 tty6 –a python

Isto fará que com que o ipython seja aberto no terminal 6 durante o boot, sem precisar de login. Faça o boot e digite ALT+F6
ipythonboot
Se quiser apagar estas mensagens do login, edite o arquivo /etc/motd.
Para editar um arquivo sem sair do ipython, digite: edit nomedoarquivo.py
vim_inv
Se o arquivo não existir ele será criado. Ao voltar sair do editor, ele volta para o ipython e executa o arquivo.
O vim não é o editor mais boa pinta do pedaço, mas em modo texto não conheço outro melhor. Para quem estiver saudades dos programas da Borland, instale o joe:

sudo apt-get install joe

e no /etc/profile, adicione:

export EDITOR=/usr/bin/joe

O joe é mais amigável e usa os comandos do Wordstar/Sidekick… e ambientes Turbo da Borland.
Para rodar jogos escritos com a PyGame, modifique a linha que escolhe a quantidade (profundidade) de cores para que 16 bit colors seja escolhido.
No invasores, edite o arquivo video.py, modifique o método modo da classe Video:

self.tela = pygame.display.set_mode(dimensao, 0, 16)

Depois, é só rodar o Invasores no framebufer!
jogo2
jogo
Mesmo alterando a partição da RAM entre a CPU e a GPU para o máximo, ou seja, 128 MB/128 MB, não consegui rodar em resoluções maiores que 1024x768. Lembrando que no X o Invasores roda normalmente.
Se você gosta de usar o modo texto, não deixe de dar uma olhada no screen. Como a tela é larga, eu a dividi em duas partes. Fica muito legal usar metade para rodar algo e a outra para ler a documentação ou editar os fontes.
Uma dica para ligar e desligar o Pi é utilizar uma régua com interruptor:
P1070022
Quanto a Internet, como o Pi fica ao lado do meu notebook, configurei o compartilhamento de Internet do Windows 7 e funcionou direitinho. Desta forma, eu uso o WiFi do notebook para dar acesso ao Pi. Outra vantagem é que posso usar o WinSCP para copiar arquivos entre o notebook e o Pi e mesmo fazer sessões com SSH. Fica a foto da mesa de guerra:
P1070032

Custo

Item
Preço
Raspberry Pi
35€
Hub USB 4 portas
12€
Carta SD 4 GB
5€
Teclado
10€
Mouse
12€
Cabo HDMI
6€
Monitor
150€
Total
230€

Como eu já tinha o monitor, teclado e mouse, não saiu tão caro. Nesta lista ainda falta adicionar 12€ para uma caixinha e mais 6€ para uma fonte com cabo Micro B USB que ainda não chegaram. O hub é opcional se você ligar apenas o teclado e o mouse.

Conclusão

O Pi é muito legal, mas é um brinquedo para desenvolvedores que gostem muito de Linux. Com o tempo, os drivers ficarão mais maduros e a performance deve melhorar. Eu acredito que logo teremos um browser com suporte a HTML5 e um XBMC mais redondo. Por enquanto, usar Python no console já chamou a atenção das crianças aqui de casa, como um modo especial de programação e criação de jogos. O fato de ver um computador aberto com as luzes piscando também chamou a atenção. Outra vantagem do Pi é que não roda Facebook, Twitter ou YouTube. Para  o ensino, gostaria de medir a diferença entre usar um ambiente como o Pi em relação a interfaces ricas como o Windows.

quarta-feira, 1 de agosto de 2012

Por que UTF-8 e não ASCII para o Português? (PARTE II)

Leia no novo blog

Continuação do post, originalmente feita na lista Python-Brasil:

Vou tentar de novo, a thread já falou de 3 coisas diferentes:
1. Codificação a usar em programas Python: por que UTF-8 é altamente recomendável
2. Codificações em geral e problemas causados e resolvidos por ela
3. Um bug do Python no Windows, quando o prompt é configurado para página 65001

Vou tentar explicar para todo mundo, pois é um tópico recorrente.

Mas antes de voltar nestes tópicos, temos que voltar a arquivos.

Tentativa 2:

Para entender a codificação de caracteres, temos que entender do que se trata.
Quem programa conhece o código ASCII, que mapeia cada caractere do alfabeto latino, códigos de controle e alguns símbolos em 7 bits.
É 7 bits, por isso vai de 0 a 127. Isso funcionava bem na década de 60... quando se enxugava bit para salvar tempo de transmissão de dados e armazenamento, muito antes dos torrents e afins :-D. A internacionalização disto ainda não estava em foco, aliás, ASCII significa Código Padrão Americano para Intercâmbio de Informação. Americano, diga-se estado-unidense.

Nossos computadores hoje usam 8 bits por byte, mas nem sempre foi assim. A IBM e depois a Microsoft entre outras empresas aproveitaram o bit extra para completar 8 bits e adicionaram mais 128 caracteres, uma vez que cada bit adicionado dobra a capacidade de representação, potência de 2, etc. Esses caracteres foram usados para representar aqueles caracteres como bordas, símbolos e alguns acentos. Quem usou DOS, lembra bem disso.

Como 256 símbolos não são suficientes para representar todos os caracteres de todas as línguas, a IBM e outros fabricantes, criaram páginas de código específicas para cada país ou língua. Assim, a página de código 437 (cp437) continha símbolos de desenho e caracteres acentuados como o ç e o ñ, usados em  línguas como o francês e o espanhol, que atendem às necessidades da América do Norte e algumas línguas européias. Um exemplo de língua não atendida completamente é o português, pois na página 437 não tem ã nem õ. Esse problema foi resolvido com a página 850, que troca alguns caracteres de desenho e símbolos pouco usados por acentos de várias línguas do ocidente europeu.
Depois de muita história, voltemos a como isso muda nossos bytes.

No código ASCII, a letra A maiúscula é representada pelo número 65 em decimal ou 0x41 em hexadecimal. O B é a letra seguinte, então deram o número 66 ou 0x42.

Se você tem um arquivo com apenas duas letras AB uma após a outra, ele vai ocupar (seus dados) dois bytes no disco. O conteúdo binário dos dados do arquivo em disco são a sequência de bytes 0x41 e 0x42 (AB ou 65 e 66). É muito importante entender esta codificação antes de continuar lendo. Se você não entende que um A é guardado como o número 65, esqueça UTF-8... será preciso reler ou pedir ajuda a um amigo. Antigamente, curso de informática começava com sistema binário e tabela ASCII, hoje o primeiro programa já baixa páginas na Internet... mas a teoria de base é deixada para trás.

Tanto na página 437 quanto na 850, toda a tabela ASCII, ou seja, seus 127 caracteres foram preservados. Assim, nosso arquivo AB é mostrado do mesmo jeito em ambas as páginas. A diferença começa aparecer quando usamos os caracteres diferentes entre elas.

Agora imagine que adicionamos um Ã, usando a página 850, pois escrevemos num computador configurado para português:
ABÃ
No disco teríamos 3 bytes:
0x41 0x42 0xC3
Na página 850, o à é traduzido para o símbolo 199, ou 0xC3 em hexadecimal.
Agora, imagine que enviamos esse arquivo para um amigo americano, que abre num computador que usa a página 437. O conteúdo no disco continua o mesmo: 0x41 0x42 0xC3, mas o que ele vê na tela é:
AB
Para onde foi nosso Ã? Para lugar algum... ela estará lá, se usarmos a mesma página de código, ou seja a 850, que usamos para escrever.
Com apenas 3 bytes, já podemos ver o que pode acontecer... agora imagine com arquivos inteiros !
Como os computadores se espalharam pelo mundo, várias páginas foram criadas para o russo, grego, etc. Imagine então escrever um arquivo com partes em grego, partes em russo e chinês... uma catástrofe.

O que uma tabela de codificação faz é mapear um valor numérico para um símbolo gráfico ou caractere. Você escolhe a tabela que quer usar, mas para fazer uma tradução entre tabelas precisa saber qual a tabela usada para codificar os dados atuais e para qual tabela você quer traduzir.
Outro problema é que línguas como o chinês precisam de mais de 256 símbolos para um texto normal, uma vez que o alfabeto deles é muito maior que o nosso. Surgem então tabelas de múltiplos bytes, onde mais de um byte era usado para cada caractere. Ainda assim, você precisava saber qual tabela multibyte foi usada... repetindo a confusão. Quem já trabalhou com Windows em C++ usando MBCS sabe a dor que isso causa...

Uma das soluções para múltiplas linguas é criar um tabelaço que resolveria todos os problemas, foi criado o UNICODE. Desta forma, todas as línguas seriam representadas. O problema é que para conter todos os símbolos, vários bytes teriam que ser utilizados até para caracteres latinos.
Assim, cada letra, numa simplificação seria representada por 2 bytes (simplificação, porque 2 bytes não são suficientes, pois temos mais de 65536 caracteres no Unicode !). Continuando, nosso A em unicode é representado como 0x00 0x41 e o B como 0x00 0x42. É cada letra passa a ser representada por dois bytes e um deles é o temido 0x00 ! O Ã ficou na posição 0x00 0xC3. No disco:
ABÃ
ficaram assim:
0x00 0x41 0x00 0x42 0x00 0xC3

Agora usamos 6 bytes para 3 caracteres. Ainda nem falamos de byte order ou de BOM... isso fica para outro dia :-D

Com 6 bytes para 3 letras, logo apareceram problemas de armazenamento de dados, pois os arquivos começaram a dobrar de tamanho e a tomar 2x mais tempo para serem transmitidos... em teoria. Uma forma mais enxuta de representar estes caracteres foi desenvolvida: o UTF-8.
Usando a mesma tabela base do Unicode, mas introduzindo um esquema de troca de páginas, ABÃ em UTF-8 são escritos no disco como:
0x40 0x41 0xC3 0x83

O Ã foi traduzido como 0xC3 0x83 !
Passamos de 6 para 4 bytes, sem perder a capacidade de escrever em praticamente qualquer língua!

O que acontece no Python. Um arquivo py de apenas uma linha para imprimir ABÃ pode ser escrito como:
print "ABÃ"

No disco ele será gravado se usarmos um editor utf-8 para escrevê-lo:
0x70 0x72 0x69 0x6E 0x74 0x20 0x22 0x41 0x42 0xC3 0x83 0x22 0x0D 0x0A

São esses bytes que o Python.exe vai ler.
Em UTF-8 estes bytes seriam traduzidos para:
0x70 p
0x72 r
0x69 i
0x6E n
0x74 t
0x20 -> espaço em branco
0x22 "
0x41 A
0x42 B
0xC3 --> primeiro byte do Ã
0x83 --> segundo byte do Ã
0x22 "
0x0D --> CR
0x0A --> LF


Mas o interpretador Python não sabe disso !

C:\Users\nilo>\Python27\python.exe Desktop\test.py
  File "Desktop\test.py", line 1
SyntaxError: Non-ASCII character '\xc3' in file Desktop\test.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

Ele diz: Non-ASCII e depois \xc3 que é outra forma de dizer 0xC3
Por que? No Python 2, o arquivo foi lido como ASCII, tendo apenas  símbolos de 0 a 127. 0xC3 é 199, ou seja, fora da tabela ASCII, daí o erro.
Neste caso, para resolver temos que colocar o # coding: utf-8
O programa fica assim:

# coding: utf-8
print "ABÃ"

Que em hexa é:
0x23 0x20 0x63 0x6F 0x64 0x69 0x6E 0x67 0x3A 0x20 0x75 0x74 0x66 0x2D 0x38 0x0D 0x0A # coding: utf-8
0x70 0x72 0x69 0x6E 0x74 0x20 0x22 0x41 0x42 0xC3 0x83 0x22 0x0D 0x0A                print "ABÃ"


Veja que a segunda linha continua exatamente a mesma coisa.
Mas ao executar-mos temos:

C:\Users\nilo>\Python27\python.exe Desktop\test.py
ABÃ


Não deu erro, mas também não imprimiu o que queríamos. Vejamos o que deu errado.
Primeiro a página de código do meu console:
C:\Users\nilo>chcp
Active code page: 850


Ué... mas a página 850 suporta o Ã. Por que o Python não imprimiu corretamente?
Simplesmente porque o cabeçalho # coding: utf-8 apenas indica em que codificação você escreveu o programa. Isso faz com ele consiga ler seu código, mesmo com acentos, desde que você tenha também usado um editor de textos em UTF-8, como diz o cabeçalho. Se você usar um cabeçalho diferente da real codificação do arquivo, os bytes em disco não vão mudar e os caracteres serão traduzidos usando tabelas incorretas. Isso é muito difícil de perceber apenas olhando, por isso eu recomendo o editor Hex. Com o tempo fica claro de fazer até no PsPad.

Ainda temos que resolver o problema da saída. No Python 2, as strings não são traduzidas de uma tabela para outra. Esta ambiguidade foi corrigida, no Python 3, com o tipo byte... mas ai já é outra história. Se você quer que o Python traduza de uma tabela para outra, use o prefixo u na string, de forma a indicar que é uma string unicode, codificada no formato utf-8, como dito no cabeçalho do programa.
Como strings comuns não tem tradução de página automaticamente, a sequência 0xc3 0x83 é mostrada na tela pela tabela da cp 850, que utiliza apenas um byte por caractere. Logo, dois bytes, dois caracteres. Um para o 0xc3 e outro para 0x83.

Vejamos o programa com o u antes das aspas:
# coding: utf-8
print u"ABÃ"

No disco:
0x23 0x20 0x63 0x6F 0x64 0x69 0x6E 0x67 0x3A 0x20 0x75 0x74 0x66 0x2D 0x38 0x0D 0x0A # coding: utf-8
0x70 0x72 0x69 0x6E 0x74 0x20 0x75 0x22 0x41 0x42 0xC3 0x83 0x22 0x0D 0x0A           print u"ABÃ"

Veja que a única diferença é 0x75 (a letra u), mas o resultado é diferente:

C:\Users\nilo>\Python27\python.exe Desktop\test.py
ABÃ

Agora saiu corretamente! Por que?  Porque o Python sabe que a string é unicode e que a saída do console no meu Windows usa a cp850. Então ele converte os bytes durante a impressão para que sejam apresentados corretamente.

Por isso é importante entender a codificação do seu arquivo e a codificação do console, banco de dados, etc. Você precisa ajudar o programa a se comportar bem.

Vejamos agora o erro do cabeçalho inválido, onde declaramos UTF-8, mas nosso editor grava usando a cp1252 do Windows:
Visualmente o arquivo tem o mesmo conteúdo:
# coding: utf-8
print u"ABÃ"
Mas no disco:
0x23 0x20 0x63 0x6F 0x64 0x69 0x6E 0x67 0x3A 0x20 0x75 0x74 0x66 0x2D 0x38 0x0D 0x0A # coding: utf-8
0x70 0x72 0x69 0x6E 0x74 0x20 0x75 0x22 0x41 0x42 0xC3 0x22 0x0D 0x0A
                print u"ABÃ"

Resulta em:
C:\Users\nilo>\Python27\python.exe Desktop\test.py
  File "Desktop\test.py", line 2
    print u"ABÃ"
SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xc3 in position 0:
unexpected end of data


Por que? Bem, se você comparar a segunda linha em hexadecimal com a do exemplo anterior, verá que na cp1252, o à foi traduzido como 0xC3, ou seja, apenas um byte. Mas declaramos no cabeçalho que estaríamos usando UTF-8! O interpretador Python é um programa e confia no que declaramos. Ele lê o arquivo como se fosse UTF-8 e acha o 0xC3 que não é apenas um caractere, mas o marcador de início de troca de página. Depois de ler o 0xC3 ele espera o outro byte desta página, mas acha as aspas (0x22). 0xC3 0x22 é uma sequência inválida em UTF-8 e o interpretador explode com uma exceção de codificação.

Voltando ao início do tópico:
1. Codificação a usar em programas Python: por que UTF-8 é altamente recomendável
Por que você pode enviar seus programas para outros computadores (linux, mac, windows) e usar acentos, evitando problemas futuros. Mas só funciona se seu cabeçalho expressar a codificação real usado no arquivo. Caso contrário não funciona.

2. Codificações em geral e problemas causados e resolvidos por ela
Acho que o início da mensagem responde essa.

3. Um bug do Python no Windows, quando o prompt é configurado para página 65001
Além das páginas da IBM, a Microsoft tem também as suas. Entre elas a cp1252 e a cp 65001 para o UTF8. Se você configurar e se somente se você configurar seu console para usar a página 650001, utf-8, o resultado é o seguinte:

C:\Users\nilo>chcp 65001
Active code page: 65001

C:\Users\nilo>\Python27\python.exe Desktop\test.py
Traceback (most recent call last):
  File "Desktop\test.py", line 2, in
    print u"ABÃ"
LookupError: unknown encoding: cp65001

C:\Users\nilo>\Python32\python.exe Desktop\test.py
Fatal Python error: Py_Initialize: can't initialize sys standard streams
LookupError: unknown encoding: cp65001

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

É só neste caso, bem específico e desnecessário para o português que temos um bug aberto ainda no Python 3.3.
Não é um bug do Windows, pois funciona em Java, C# e C. É apenas a forma que o interpretador trata a cp65001 diferente de utf8.

domingo, 29 de julho de 2012

Por que UTF-8 e não ASCII para o Português? (PARTE I)

Leia no novo blog

Um outro post que fiz na Python-Brasil:

Os colegas já falaram sobre o por quê do UTF-8.

Eu gostaria apenas de lembrar que o assunto é mais complicado do que parece, por exemplo no Python 2.7:
# -*- coding: utf-8 -*-
print "Acentos: áéíóúãõç"
print u"Acentos2: áéíóúãõç"


Execute o programa acima no Windows, pode ser pelo IDLE ou pelo console:

C:\Users\nilo\Desktop>\Python27\python.exe test.py
Acentos: ├í├®├¡├│├║├º├ú├Á
Acentos2: áéíóúçãõ


Você deve ter obtido bons resultados apenas na linha do Acentos2. Se a string não é marcada com unicode, vai ser simplesmente impressa como uma sequência de bytes, sem tradução. Se tiver o u na frente, como em acentos2, o Python saca que precisa traduzir de unicode para cp850, no caso do console aqui de casa. Já no Linux, as duas linhas produzem resultados corretos!

O encoding: utf-8 informa apenas a codificação do código fonte. Ou seja, é apenas uma dica de como os caracteres deveriam estar codificados. Para que funcione corretamente, seu editor de texto tem que estar configurado para UTF-8 também. Se misturar, é desastre na certa. Eu recomendo o PSPad no Windows para editar com UTF-8. Para verificar o encoding de um arquivo que você não conhece, ou para ter certeza de qual codificação seu editor realmente utilizou, use um visualizador binário como o HxD [3]. No hex edit do PS Pad, atenção que ele mostra os caracteres em Unicode, mesmo se a codificação for UTF-8. Isso para lembrar que UTF-8 é uma representação ou forma de codificação de caracteres Unicode. O Notepad++ pode também ser usado para editar e codificar arquivos em UTF-8.
No Mac e no Linux, tente o hexdump -C arquivo
Quando o arquivo esta codificado corretamente em utf-8, você deve ter mais de um byte para os caracteres acentuados.

Por exemplo, o programa acima, criado no vim do Ubuntu:
nilo@linuxvm:~$ hexdump -C test.py
00000000  23 20 2d 2a 2d 20 63 6f  64 69 6e 67 3a 20 20 75  |# -*- coding:  u|
00000010  74 66 2d 38 20 2d 2a 2d  0a 70 72 69 6e 74 20 22  |tf-8 -*-.print "|
00000020  41 63 65 6e 74 6f 73 3a  20 c3 a1 c3 a9 c3 ad c3  |Acentos: .......|
00000030  b3 c3 ba c3 a3 c3 b5 c3  a7 22 0a 70 72 69 6e 74  |.........".print|
00000040  20 22 41 63 65 6e 74 6f  73 32 3a 20 c3 a1 c3 a9  | "Acentos2: ....|
00000050  c3 ad c3 b3 c3 ba c3 a3  c3 b5 c3 a7 22 0a 0a     |............"..|
0000005f


Um site bacana é esse aqui: http://www.utf8-chartable.de/

Uma vez resolvido o problema de codificação dos fontes, restam ainda:
* A codificação do console
* A codificação dos arquivos de dados
* Codificação do banco de dados

Tanto o Mac quanto Linux usam UTF-8 por padrão. O Windows usa a cp 1252 (GUI), compatível com iso8859_1. Cuidado também se você troca arquivos entre máquinas Windows, Linux e Mac. E nunca misture duas codificações no mesmo arquivo, pois isto gera erros difíceis de detectar e resolver.
É fácil misturar quando se faz append em um arquivo, vindo de outra máquina ou mesmo gerado em um outro programa.
O Windows em chinês, russo e outras línguas não utilizam a cp1252! Por isso UTF-8 é uma boa pedida, pois consegue codificar caracteres Unicode com um ou vários bytes, dependendo da necessidade.

O Python 3 resolve muito destes problemas, mas a documentação diz[1]:


Files opened as text files (still the default mode for open()) always use an encoding to map between strings (in memory) and bytes (on disk). Binary files (opened with a b in the mode argument) always use bytes in memory. This means that if a file is opened using an incorrect mode or encoding, I/O will likely fail loudly, instead of silently producing incorrect data. It also means that even Unix users will have to specify the correct mode (text or binary) when opening a file. There is a platform-dependent default encoding, which on Unixy platforms can be set with the LANG environment variable (and sometimes also with some other platform-specific locale-related environment variables). In many cases, but not all, the system default is UTF-8; you should never count on this default. Any application reading or writing more than pure ASCII text should probably have a way to override the encoding. There is no longer any need for using the encoding-aware streams in the codecs module.

A parte que sublinhei diz: "... o padrão do sistema é UTF-8; você não deve contar nunca com este padrão..."
Resumindo, é um assunto que merece ser estudado, pois causa problemas  "mágicos" que sempre aparecem.

Um texto que explica tudo com detalhes pode ser encontrado em [2].

[]

Nilo Menezes
[1] http://docs.python.org/release/3.0.1/whatsnew/3.0.html
[2] http://wiki.python.org.br/TudoSobrePythoneUnicode
[3] http://mh-nexus.de/en/hxd/

quarta-feira, 25 de julho de 2012

Por que aprender várias linguagens de programação?

Leia no novo blog

Outro post da lista Python-Brasil, onde se discutia qual a melhor linguagem para se aprender a programar:


Eu concordo que Python é uma ótima linguagem como primeira linguagem de programação.
Mas nem tudo é Hello World e muitas vezes o professor ou o coordenador do curso ensaiam de apresentar Java ou C++... para facilitar cursos futuros. Exemplo: apresentam um Java troncho em ICC para depois afinar num curso de OO. Outros por não conhecerem Python ou descartarem Python por ser script.

Algumas faculdades são também assombradas por fatalistas que pregam o ensino de linguagens do mercado. Quando fiz faculdade, em aprendi Pascal, C, Java, Modula, Prolog, Assembly do MIPS e outros bichos. Nenhuma destas linguagens foi ensinada diretamente, mas no contexto das disciplinas de ICC, estruturas de dados, sistemas operacionais, etc. Já na época tinha fantasma dizendo que deveríamos aprender Word e outros praguejando Prolog. O esquema era que deveríamos aprender as linguagens sozinhos, eles só nos davam um bom motivo :-D

Eu fiz faculdade depois de já estar trabalhando, depois de um curso técnico em informática... 18 anos depois eu tenho uma visão pessoal. Acredito que o melhor mesmo é aprender e ter contato com o maior número possível de linguagens na faculdade. De preferência, linguagens com paradigmas diferentes.

Python é muito boa, mas se for a única, estaremos repetindo o mesmo erro.

Eu acredito que só programar numa linguagem é como falar apenas uma língua.

Eu defendo Python como primeira linguagem por ser uma das mais fáceis de aprender.
Além disso,  a taxa de retorno do Python é excelente. Você consegue premiar o aluno, pois este fica contente em saber que consegue fazer algo útil sozinho. Com C, muitos desistem, pois o esforço inicial é grande e a impressão é que o trabalho não rende.

ICC com Java ou C++ é terrorismo :-D

terça-feira, 24 de julho de 2012

XML-Man

De todos os super-heróis que vivem na ilha de Java, o mais perigoso é o XML-Man.

XML-Man resolve tudo com a herdeira do SGML, prima do HTML. Tudo, tudo. Se fosse possível, escreveria programas Java em XML também. O poder de XML-Man é de criar ferramentas de configuração e gerenciamento que você não precisaria se não tivesse que escrever tudo em XML.


sábado, 21 de julho de 2012

Certificados e diplomas em informática

Leia no novo blog

Esta foi a resposta que dei num post na lista Python-Brasil sobre a importância de certificados.

Há alguns anos eu contratei mais de 100 profissionais de informática... desenvovedores C++, Java, testadores etc. Durante este período, eu aprendi a não confiar em diploma algum.

Eu contratei gente vinda de faculdade particular muito melhor que de faculdades federais ou estaduais, embora esta não fosse a regra, mas a exceção. Se a pessoa que contrata é a mesma que vai trabalhar com você, por exemplo seu futuro chefe, ele procura alguém que resolva os problemas dele, diploma e certificado ele deixa para o RH ver :-D. Eu conheci muita gente boa que nem faculdade tinha, mas são casos raros e não a regra. Para algumas posições de TI, faculdade é luxo... para outras é absolutamente necessário. Eu sei que para administração de redes, certificação é fundamental.

A questão de diploma/certificados aparece quando você tenta trabalhar numa empresa maior onde:

a) Alguém do RH ou empresa externa vai fazer a pré-seleção para o pessoal de TI. Neste caso, a primeira seleção é quase mecânica com um check list do CV: tem faculdade? É de informática ou engenharia? trabalha há quantos anos... etc. Normalmente o RH não arrisca passar um CV para entrevista se nem tiver encontrado alguns pré-requisitos. Algumas empresas tem mesmo cotas de qualidade e escolarização, onde uma determinada porcentagem tem que ter mestrado, doutorado ou graduação. Onde eu trabalhei, nosso cliente pedia um inventário de talentos e diplomas. Neste caso, é importante aparecer a palavra Python, seja na sua experiência, ou mesmo no nome de um curso que você fez (mais abaixo).

b) A pessoa recebe um número excessivo de CVs para a mesma vaga, na época eu recebi mais de 2200. Neste caso, ela vai fazer um pesquisa como o pessoal de RH. Normalmente se privilegia experiência nesses casos, mas sem os diplomas, depende muito. No meu caso, minha secretária era professora de inglês. Eu passava uns CVs pré-selecionados para ela, ela ligava, fazia um teste por telefone e filtrava os CVs que eu deveria chamar para entrevista, sorte minha.

Eu comecei a trabalhar cedo com informática (início dos anos 90) e até meus 28 anos eu não tinha diploma universitário. Ná época, o importante para mim era ganhar dinheiro. Consegui ótimas vagas em empresas pequenas, apenas com um diploma do curso técnico. Nunca fiz certificação alguma. Nunca trabalhei em mega-empresas, pois o salário dependia da formação e nunca era bom para mim (pagavam menos).
Depois eu me formei e fiz mestrado. Valeu muito a pena na hora de trabalhar fora, pois para ter permissão de trabalho o diploma é obrigatório (pelo menos na Bélgica). Aqui, nem de certificação ouço falar, mas um "engenheiro" passa 5 anos na faculade em tempo integral. Aqui já se sai mestre. Escrevi "engenheiro", pois aqui esta palavra praticamente substitui o nosso graduado.

Como você mesmo disse, toda forma de adquirir conhecimento é importante. Se eu morasse em SP, eu assistira o curso do Luciano, tenho certeza que o networking e os bizus de Python apareceriam, independente do meu nível de formação ou experiência. Um curso online pode ser muito bom, mas depende muito. Eu fiz uns no Cursera, uns excelentes e outros que não consegui nem chegar ao fim. Tudo depende, só de experimentar já se aprende muito.

Quanto a certificado de curso livre, sinceramente, nunca serviram para nada, na minha experiência. Se for fazer o curso, faça para aprender. O certificado só serve para o RH fazer o tal  inventário de talentos mais tarde e se para isso servir. Eu tenho maior orgulho de um curso de programação Basic I que fiz em 86... mas nunca tive oportuinidade de usá-lo, ficou como recordação mesmo.

Se eu voltasse a contratar hoje, eu daria preferência para pessoas que saibam aprender sozinhas. Seja com livros, cursos presenciais ou on-line, mas alguém que se vire para aprender um assunto. Nessa lista, vale até que aprendeu Python lendo a documentação on-line que é ótima. Mas se eu tivesse que escolher entre dois candidatos com experiência equivalente, mas um formado e outro não, o com diploma teria a vaga.

Três coisas são importantes num CV: experiência, formação superior e em alguns casos certificações.

Cursos livres eu não colocaria nem no CV. Salvo se o CV estiver muito magrinho. Se o curso foi de Python, é mais importante dizer que sabe e que ja fez X, Y e Z com a linguagem. O curso livre pode aparecer na entrevista. O networking do curso pode ajudar mais que o curso em si, mas lembre-se que isso pode ser uma faca de dois gumes, pois estas pessoas lembrarão de como você se comportou no curso, nos intervalos, etc.

Resumindo, eu faria um curso online, independente do certificado, se quisesse acelerar o aprendizado de uma linguagem/assunto. Mas não ficaria só por ai.

terça-feira, 17 de julho de 2012

De volta à Alemanha

Comecei meu estágio em Braunschweig... 10 anos depois de Munique, me deparo com problemas bem diferentes. Munique é uma cidade grande... Braunschweig tem 250 mil habitantes. A estrutura é muito boa, mas diferentemente de Munique, só com inglês você não faz tudo :-(
10 anos mais velho, aprender alemão deixa de ser tão divertido. A falta de novidades faz tudo virar rotina bem rápido. Pelo menos está chovendo menos que em Mons :-D



sábado, 28 de abril de 2012

Gênesis Informático

Como estou quase sendo obrigado a programar em Java de novo, fica a piada:

No início não havia computadores, apenas máquinas.

As máquinas existiam, mas a lógica era limitada.

O homem domou a corrente elétrica e a transformou em sinais digitais capazes de  transportar infomação.

Tudo era nulo, apenas bits 0.

Criou-se então os bits 1.

Surge a lógica.

Mas os bits 0 e 1 eram sós e o byte foi criado para agrupá-los.

Bits e bytes sem nome vagavam pelas máquinas, sem saber o que fazer. As máquinas ainda eram criadas para uma finalidade bem específica e a lógica codificada no material. Surgiam os primeiros sistemas.

O programador foi então criado e a ele foi dada a responsabilidade de organizar bits e bytes. Surgia o Caos.

Mas o programador era só e criou linguagens e compiladores para acompanhá-lo. O sistema enviou mensagens dizendo que aquilo era perigoso e que agora milhões de bits e bytes teriam que ser utilizados para fazer as coisas mais simples. A mensagem foi ignorada e surgia assim o bug.

O programador continuou proliferando código escrito em múltiplas linguagens. Quando inventou o C, o sistema enviou uma nova mensagem dizendo que já era suficiente e que o programador deveria se contentar com bits, bytes e ponteiros, todos felizes na RAM.

O C era bom e foi usado para criar o UNIX.

O diabo, invejoso, criou o Windows para atentar o programador por toda sua existência.

Novos programas foram criados a partir desses princípios básicos entre o universo de software e hardware. Um dia, o programador traiu o sistema e criou jAdao e jEva, escrenvendo-os num dialeto de C++ banido aos habitantes da ilha de Java. O sistema então castigou jAdao e jEva por terem acumulado tantos bits e bytes a ponto de usar toda a memória do sistema e os baniu para Java dizendo:

Usarás o dialeto no teu dia-a-dia.
Esquecerás o que é um bit.
Usarás um IDE lento.
Verás tudo através deste código que não conhecerá limites de tamanho, performance ou coerência.
Jamais tocarás num ponteiro.
Teus descendentes não usarão propriedades e todos os programadores terão que escrever getters e setters pelo resto de seus dias.
Teu código só entenderá XML e produzirá logs indecifráveis.
Serás atormentado por cobras e outras pedras preciosas que não sofrerão desses males, serão menores e mais ágeis, porém ainda mais lentas.
Tuas classes proliferarão e dominarão o mundo.
Este dialeto será portátil e te acompanhará por todas as máquinas que usares, sempre pendindo para fazer update.