Sintonia fina do IPython

Para IPython 5+, veja o post mais recente.

Quem já usou o IPython alguma vez sabe que ele é um tanto quanto “espaçoso”. Cada comando digitado gera uma nova linha, além de ele usar um prompt de entrada e saída com a contagem dos comandos digitados. Se, assim como eu, você não curte o visual do IPython padrão, este texto é para você.

Por padrão, o IPython se apresenta assim:

ipython1

Veja quantos espaços em branco. Ele é bem diferente do shell Python padrão, que é bem menos espaçoso.

Para deixá-lo mais parecido com o shell Python basicão, basta dar uma “tunadinha” nele. Em outro post, já mostrei como configurar alguns aspectos do IPython. Neste post, vou apresentar algumas configurações adicionais que podem ser feitas. Ao final dele, seu IPython vai ficar parecido com:

ipython2

Configurando o IPython

Antes de qualquer coisa é preciso criar um perfil, através do seguinte comando no shell do seu sistema operacional:

$ ipython profile create

Isso irá criar um perfil chamado de default e todas as configurações desse perfil estarão no diretório ~/.config/ipython/profile_default/ (ao menos no Ubuntu).

Feito isso, agora você pode editar o arquivo de configurações do IPython (~/.config/ipython/profile_default/ipython_config.py). Ele está repleto de linhas de código Python comentadas, mas vou me deter aqui apenas àquelas que descomentei e customizei.

Desabilitar o banner de apresentação

Toda vez que é iniciado, o IPython mostra um banner parecido com:

Python 2.7.4 (default, Sep 26 2013, 03:20:26) 
Type "copyright", "credits" or "license" for more information.

IPython 0.13.2 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

Depois de ver duas ou três vezes, já decoramos essas informações e elas não são mais necessárias. Para desabilitar a apresentação dessas informações ao iniciar o IPython, utilizei a seguinte definição:

c.TerminalIPythonApp.display_banner = False

Removendo os \n entre as entradas

Uma das coisas mais irritantes no IPython é a quantidade de espaços em branco que ele coloca na tela. Muitos desses espaços são gerados pela separação entre as entradas através de um caractere de \n. Dá pra ajeitar isso, colocando um caractere vazio como separador:

c.TerminalInteractiveShell.separate_in = ''

Removendo a confirmação de fechamento

O IPython sempre pergunta se você deseja mesmo fechá-lo ao pressionar C-d. É claro que eu quero te fechar, ou tu tá achando que pressionei Ctrl e depois d sem querer? Dá pra evitar essa chateação com:

c.TerminalInteractiveShell.confirm_exit = False

Permitindo ao IPython modificar o título do terminal

Isso pode ser bem útil pra quem costuma ficar com várias abas de terminal abertas. Habilite isso com a seguinte linha:

c.TerminalInteractiveShell.term_title = True

Customizando o prompt de saída

Por padrão, linhas que contenham saída são precedidas por Out [x]:. Isso me incomodava um pouco, então resolvi alterá-lo e deixá-lo mais parecido com o shell padrão. Você também pode fazer isso com a seguinte linha:

c.PromptManager.out_template = ''

Customizando o prompt de entrada

O prompt de entrada no IPython apresenta o texto In [x]:. Para fazer com que o prompt de entrada seja igual ao clássico >>> do shell padrão, faça:

c.PromptManager.in_template = '>>> '

Completação por tab gulosa

Para habilitar a completação em resultados de chamadas de funções, ou em elementos de sequências, basta habilitar a configuração abaixo:

c.IPCompleter.greedy = True

Atenção: comentários no arquivo advertem que pode ser um pouco perigoso habilitar a configuração acima, pois para poder completar baseando-se no resultado de uma chamada de função, o ipython terá que chamá-la.

O ipython_config.py completo

# Configuration file for ipython.
c = get_config()

# Whether to display a banner upon starting IPython.
c.TerminalIPythonApp.display_banner = False

# Remove those annoying newlines between each input
c.TerminalInteractiveShell.separate_in = ''

# Set to confirm when you try to exit IPython with an EOF (Control-D in Unix)
c.TerminalInteractiveShell.confirm_exit = False

# Enable auto setting the terminal title.
c.TerminalInteractiveShell.term_title = True

# Output prompt.
c.PromptManager.out_template = ''

# Bring back the classic Python REPL prompt.
c.PromptManager.in_template = '>>> '

# Activate greedy completion
# This will enable completion on elements of lists, results of function calls,
# etc., but can be unsafe because the code is actually evaluated on TAB.
c.IPCompleter.greedy = True

Sugestões?

Se tiver mais alguma sugestão, envie um comentário.

Anúncios

Asteriscos em chamadas de funções

Diga aí, o que o código abaixo irá produzir?

def func(a, b, c, d):
    return (a + b) / (c + d)

lista_de_argumentos = [4, 6, 2, 3]
print func(*lista_de_argumentos)

Se você sabe a resposta (que é 2), provavelmente já conhece esse uso do * (asterisco ou estrela).
Caso não tenha entendido muito bem, leia o resto do texto.

A estrela (asterisco) na chamada de funções

A função func listada acima deve receber 4 parâmetros (a, b, c e d). Quando passamos um argumento precedido de um asterisco, esse argumento (se for uma lista ou tupla) será desempacotado e cada um dos elementos será passado como um dos argumentos posicionais da função. No exemplo acima, o primeiro elemento de lista_de_argumentos será passado ao argumento a, o segundo ao elemento b, e assim por diante. No exemplo acima, a chamada de função func(*lista_de_argumentos) dá no mesmo que func(4, 6, 2, 3), pois o desempacotamento é automático. A imagem abaixo ilustra o que acontece:

Exemplo de passagem de parâmetros

Se lista_de_argumentos tivesse uma quantidade de elementos diferente da quantidade de argumentos exigidos por func, uma exceção seria disparada. Veja:

>>> lista = [4, 6, 2, 3, 10]
>>> print func(*lista)
------------------------------------------------------------------
TypeError                        Traceback (most recent call last)
 in ()
----> 1 print func(*lista)
TypeError: func() takes exactly 4 arguments (5 given)

A estrela-dupla na chamada de funções

De forma semelhante, podemos também desempacotar dicionários em chamadas de funções. Nesses dicionários, as chaves deverão ser os nomes dos argumentos e os valores serão os valores que queremos passar como argumentos. Seguindo com o exemplo da função func, poderíamos passar um dicionário com os nossos parâmetros nomeados, precedido de **:

>>> argumentos = {'d': 3, 'c': 2, 'b': 6, 'a': 4}
>>> print func(**argumentos)
2

Assim, os valores armazenados no dicionário serão desempacotados direitinho como argumentos para a função, de acordo com as chaves correspondentes a eles. Assim, 4 será o argumento a, 6 será passado como argumento para b e assim por diante.

Quando usar isso?

Esse açúcar sintático oferecido por Python é bem útil quando temos uma lista contendo os valores que deverão ser passados para uma função. Por exemplo, ao invés de fazer:

>>> lista = [6, 4, 2, 3]
>>> func(lista[0], lista[1], lista[2], lista[3])

podemos fazer:

>>> lista = [6, 4, 2, 3]
>>> func(*lista)

O uso vai surgir da necessidade. Às vezes temos uma função que retorna uma tupla de n valores e queremos passar esses valores diretamente como argumentos para outra função, que exige n parâmetros. É aí que entra o *.