You are currently browsing the category archive for the 'Python' category.
Palavras-chave: Python, pegadinhas, gotchas, pitfalls, listas, extends
Em Python o operador de soma e atribuição += pode ser usado na forma “a += 1” que tem o mesmo significado que a expressão “a = a + 1“.
Até aí nada de diferente. Mas a linguagem Python disponibiliza uma função própria para tratar o operador += (__iadd__) e outra para o operador de adição + (__add__). Na maioria das vezes o método __iadd__ chama __add__ e tudo fica certo. Mas não é isso que acontece com as listas.
Nos objetos do tipo list o método .__iadd__() irá chamar o método .extend() da lista. Desta forma podemos fazer coisas como:
>>> a = [1,2,3] >>> a += [4,5,6] >>> a [1, 2, 3, 4, 5, 6] >>> a.extend([7,8,9]) >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> a = [1,2,3] >>> a + [4,5,6] [1, 2, 3, 4, 5, 6]
As coisas começam a ficar complicadas quando temos uma situação que envolve strings, como no caso seguinte. Lembre-se que strings também são consideradas seqüências em Python.
>>> a = [1,2,3]
>>> a + "spam"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
>>> a += "spam"
>>> a
[1, 2, 3, 's', 'p', 'a', 'm']
>>> a.extend("eggs")
>>> a
[1, 2, 3, 's', 'p', 'a', 'm', 'e', 'g', 'g', 's']
Os exemplos acima deixam claro que é preciso tomar cuidado com esse tipo de situação em seus programas.
Alguns argumentam que esse comportamento da lista não é muito consistente e que esse “problema” deveria ser consertado. Mas existe um outro grupo que diz que esso é o comportamento correto. Até que esses grupos entrem num acordo é bom ficarmos de olho.
Palavras-chave: Python, Design Patterns, Padrões de Projeto, OOP, POO
Um Singleton é um dos padrões de projeto descrito no famoso livro “Design Patterns” escrito pela GoF (Gang of Four) e o seu funcionamento é bastante simples: uma classe é chamada de Singleton quando ela permite apenas uma única instância.
A maneira de se implementar um Singleton descrita no livro consiste em definir um método get_instance() na classe que ficará responsável por criar a primeira instância e a partir daí retorná-la sempre que for chamada.
Mas a natureza dinâmica de Python e seu sistema de meta-classes permitem que se crie uma classe chamada Singleton genérica que podemos usar como super-classe dos nossos próprios Singletons:
class Singleton(object):
def __new__(cls, *args, **kwargs):
if '_inst' not in vars(cls):
cls._inst = type.__new__(cls, *args, **kwargs)
return cls._inst
Agora, para que a sua classe se transforme em Singleton basta apenas derivá-la desta classe e não é mais necessário implementar o método get_instance(). O seu uso ficaria assim:
class MeuSingleton(Singleton): pass a = MeuSingleton() b = MeuSingleton() print a is b # imprimirá True, pois trata-se da mesma instância
Essa dica faz parte do livro Python Cookbook e foi escrita por Jürgen Hermann. No livro você poderá encontrar as explicações detalhadas sobre essa classe e mais uma série de outras dicas interessantes sobre diversos assuntos.
Palavras-chave: Python, listas, cópia, objetos
Em Python as variáveis não armazenam os objetos quando atribuímos um valor à elas. Ao invés disso uma variável em Python guarda apenas uma referência para o objeto em questão. Uma prova disto pode ser vista a seguir:
>>> a = [1,2,3] >>> b = a >>> b is a True >>> a.append(4) >>> b [1, 2, 3, 4]
Por essa razão precisamos fazer cópias dos objetos quando queremos manipular os dados de uma das variáveis sem afetar os dados da outra.
A biblioteca Python disponibiliza o módulo copy para essa tarefa, mas em casos de listas (ou qualquer outra seqüência como strings e tuplas) existe uma maneira mais simples de se fazer isso: utilizando slicing, veja:
>>> a = [1,2,3] >>> b = a[:] >>> a is b False >>> a.append(4) >>> b [1, 2, 3] >>> a [1, 2, 3, 4]
A operação de slicing retornou uma cópia idêntica da lista porque a[:] é o mesmo que a[0:len(a)]. Vale lembrar, porém, que apenas a lista é copiada e não os objetos que estão dentro dela.
Palavras-chave: Python, command prompt, prompt de comandos, prompt, DOS, Windows
Quando executamos um programa “.py” no Windows uma janela de prompt irá aparecer automaticamente para que as eventuais saídas de texto do seu programa sejam enviadas para lá.
Mas essa janela pode se tornar incoveniente quando o nosso programa já provê uma interface gráfica pois, neste caso, teríamos duas janelas abertas para a mesma aplicação.
A janela aparece porque a extensão “.py” está associada ao interpretador “X:\PythonXX\python.exe” que está configurado para abrir uma janela de prompt.
Caso você precise executar seu programa sem essa janela é melhor usar o interpretador “X:\PythonXX\pythonw.exe” que é feito justamente para esse propósito.
A extensão “.pyw” é associada à esse interpretador, portanto, basta renomear os seus arquivos .py, .pyc e .pyo para .pyw que as janelas de prompt deixarão de aparecer.
Palavras-chave: Python, dicionários, switch, case
Algumas pessoas reclamam de que Python não possui uma instrução switch/case, que permite executar trechos de código dependendo do valor de uma determinada variável.
Python realmente não disponibiliza essa funcionalidade, mas podemos simulá-la utilizando funções e dicionários. Para isso basta lembrar que funções e métodos em Python também são objetos. Veja:
def func1(): print "func1"
def func2(): print "func2"
def func_default(): print "default"
switch = {
1: func1,
2: func2,
}
for case in range(3):
try:
# chamamos a funcao aqui
switch[case]()
except KeyError, e:
# se nao existe, chamamos o default
func_default()
Quando executarmos este exemplo o resultado será:
default func1 func2
Palavras-chave: Python, listagem, cores, zebrado, zebra list
Em aplicações Web é bastante comum exibir grandes listagens em uma página. Para facilitar a leitura dessas listagens, quase sempre utilizamos do artifício de alternar as cores de fundo das linhas exibidas.
O meu amigo Ulysses, mais uma vez (estou até pensando em deixá-lo escrevendo por aqui) deu uma dica excelente para fazer isso, veja:
cores = ["#F5F5F5", "#FFFFFF"] for n, linha in enumerate(linhas): cor_fundo = cores[n % 2] # aqui vai o seu código...
Vou aproveitar também essa dica para embutir uma outra dica mais voltada para a “usabilidade”: a diferença de saturação entre uma cor e outra usada no exemplo acima deve ser pequena para tornar esse efeito efetivo.
Palavras-chave: Python, or, in, if, while, condicional, pythonico
Quem está começando no mundo do desenvolvimento Python e não conhece muito a linguagem, costuma criar cláusulas condicionais muito longas utilizando o operador “or”:
if a == "foo" or a == "bar" or a == "baz": print a
Imagine o tamanho dessa cláusula quando precisar comparar o valor de “a” com muitos outros valores. Para essas situações você pode usar o operador “in” do Python que verifica se há uma ocorrência do objeto em uma lista:
if a in ["foo", "bar", "baz"]: print a
Ficou bem mais simples e legível, não? Esta é a maneira “pythônica” de se montar esse tipo de cláusula condicional.
Essa dica foi sugerida pelo meu amigo Ulysses que me atentou para o fato de que os novatos na linguagem costumam fazer esse tipo de cláusula da forma inadequada.
Palavras-chave: Python, split, tokenizacão, análise léxica, parser, strings, quotes, aspas
O módulo re possui a conveniente função split(), que faz o mesmo que o split() dos strings, mas aceita expressões regulares como separador. Isto pode ser aproveitado para fazer um “parser de pobre” para casos simples, como por exemplo, quebrar um texto em palavras, levando em conta “strings” entre aspas:
>>> texto="lorem ipsum dolor 'hello world' 'mais texto'' assim'"
>>> print filter(None,re.split("('(?:[^']|'')*')| ", texto))
['lorem', 'ipsum', 'dolor', "'hello world'", "'mais texto'' assim'"]
O filter() é necessário para remover espaços em branco e Nones que sobram no resultado. Como bônus, strings podem conter ' escapados com ''.
Palavras-chave: testes, unittest, docstring, documentação, testes unitários, rest, docutils
Todo desenvolvedor sabe que fazer testes é superimportante e que fazer documentação também é algo que melhora a qualidade de seus produtos. Mas num primeiro momento, fazer testes é trabalhoso e documentar o nosso código também costuma ser muito chato.
E se a gente conseguisse fazer as duas coisas ao mesmo tempo e obter bons testes e boa documentação? Com o módulo doctest do Python é possível fazer isso. Veja o exemplo abaixo (que foi parcialmente tirado da documentação do módulo):
# -*- coding: utf-8 -*-
import doctest
def fatorial(valor):
"""fatorial(int) -> int
A função fatorial pode ser usada para calcular
o fatorial de um número n onde n > 0 vejam os exemplos::
>>> fatorial(15)
1307674368000L
>>> fatorial(-1)
Traceback (most recent call last):
...
ValueError: valor precisa ser > 0
>>> fatorial(15.1)
Traceback (most recent call last):
...
ValueError: valor precisa ser inteiro
"""
if valor < 0:
raise ValueError("valor precisa ser > 0")
if not isinstance(valor, (int,long)):
raise ValueError("valor precisa ser inteiro")
if valor:
return valor * fatorial(valor - 1)
return 1
if __name__ == '__main__':
doctest.testmod()
Agora, para rodar nossos testes basta executar esse exemplo:
$ python fatorial.py -v : 1 items passed all tests: 3 tests in __main__.fatorial 3 tests in 2 items. 3 passed and 0 failed. Test passed.
Além de colocar os testes dentro das docstrings também podemos usar arquivos texto convencionais para essa mesma finalidade. A documentação pode usar o formato ReST usado pelos utilitários docutils.
Palavras-chave: userdir, home, homedrive, homepath, arquivo de configuração
Frequentemente precisamos guardar preferências do usuário de nossos programas em algum arquivo de configuração. Em ambientes UNIX/Linux a prática diz que esses arquivos devem ser guardados dentro do diretório $HOME e de preferência como um arquivo (ou diretório) oculto.
Mas usar a variável de ambiente $HOME para obter o diretório não é uma solução muito portável e certamente irá falhar em outros sistemas operacionais, como o Windows.
Para esses casos o módulo os.path disponibiliza a função expanduser() que irá substituir o símbolo ~ pelo caminho completo de onde devemos guardar esses os arquivos de configuração. Veja abaixo um exemplo de uso desta função:
import os.path
print os.path.expanduser("~/.arquivorc")
Rodando esse exemplo em um ambiente UNIX/Linux iremos obter algo parecido com isso:
/home/username/.arquivorc
Já em uma máquina com Windows (XP) teremos:
C:\\Documents and Settings\\username\\.arquivorc
Algumas observações:
-
Em ambientes UNIX/Linux é possível obter o $HOME de outros usuários. Para isso basta usar expanduser(”~outro_usuario”). Isso não funcionará no Windows.
-
Não existe um padrão que diga o lugar correto para guardar arquivos de configuração no Windows. O diretório sugerido aqui é aceito mas aparentemente o mais correto seria: C:\Documents and Settings\username\Application Data\meu_programa\config.ini (lembrando sempre que “Application Data” pode ter outro nome em Windows de outros idiomas).
-
A forma 100% correta para achar esse diretório no Windows envolve a procura no “Registry” do Windows, mas isso fugiria do escopo dessa dica.
Palavras-chave: print, stdin, stdout, stderr, erro, dispositivos, entrada/saída
Quando estamos fazendo um programa que roda na linha de comando e precisamos fazer com que esse programa imprima uma mensagem de erro ou alerta, é aconselhável enviar essa mensagem para a saída de erro padrão, conhecida como STDERR.
A linguagem Python disponibiliza para o programador todos os dispositivos de entrada/saída padrão do sistema operacional dentro do módulo sys:
sys.stdin Entrada padrão (STDIN) sys.stdout Saída padrão (STDOUT) sys.stderr Saída de erros (STDERR)
O comando print envia as mensagens que serão impressas no terminal para o dispositivo sys.stdout. Neste caso, como podemos enviar mensagens para a saída de erro? De duas maneiras: usando o método .write() do dispositivo ou usando o redirecionamento do comando print. Veja os exemplos:
import sys
# .write()
# Dica: lembre-se de adicionar a quebra-de-linha no final
sys.stderr.write("ERRO: mensagem de erro.\\n")
# redirecionamento
print >>sys.stderr, "ERRO: mensagem de erro."
A sintaxe de redirecionamento é desconhecida de muitos programadores Python, mas é bastante prática e também pode ser usada para escrita de qualquer tipo de arquivo.
Palavras-chave: Unicode, utf8, SQLObject, TurboGears, erro
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 50: ordinal not in range(128)
Este erro pode ocorrer quando se tenta executar queries que envolvem caracteres Unicode (na query em si ou no resultado) usando SQLObject (o módulo de banco de dados usado no TurboGears).
A solução é forçar o SQLObject a usar UTF-8 internamente e desativar conversões desnecessárias sendo feitas por ele. Para isso modifique sua URI de conexão para algo como:
sqlobject.dburi=
“mysql://root:@localhost:3306/fliki?use_unicode=1&sqlobject_encoding=utf8“
Dependendo da versão do SQLObject pode ser necessário também adicionar o parâmetro charset=utf8 à URI.
Palavras-chave: pacote, módulo, import
Criar um módulo em Python é extremamente simples. Basta apenas criar um arquivo .py dentro de algum diretório listado em sys.path. Alguns desenvolvedores também gostariam de fazer pacotes com módulos em Python. Esses pacotes permitiriam que o programador importasse seus módulos da seguinte maneira:
import meu_pacote.meu_subpacote.modulo from outro_pacote.outro_subpacote import outro_modulo
Um pacote nada mais é do que um diretório no sistema de arquivos que possui um arquivo __init__.py dentro. Dentro do arquivo __init__.py, deve-se colocar o código de inicialização do pacote, bem como definir a variável __all__, que irá listar todos os símbolos que serão importados no comando from … import *. No caso em que o arquivo __init__.py fica vazio todos símbolos do pacote serão importados.
Considere a seguinte estrutura:
# meu_pacote/ # __init__.py -- vazio # meu_subpacote/ # __init__.py -- vazio # modulo.py -- imprime "modulo importado"
A partir do diretório atual podemos fazer:
>>> import meu_pacote.meu_subpacote.modulo modulo importado
Se os arquivos __init__.py não existissem um erro como este aconteceria:
>>> import meu_pacote.meu_subpacote.modulo Traceback (most recent call last): File "", line 1, in ? ImportError: No module named meu_pacote.meu_subpacote.modulo
Palavras-chave: debug, depuração, trace, decorators
Essa dica veio de um amigo meu (Ulysses) e foi enviada para a lista de discussões PythonBrasil.
É muito comum precisar rastrear as chamadas de funções que ocorrem dentro dos programas, para facilitar nossa vida quando precisamos encontrar onde um determinado problema está ocorrendo. Ao mesmo tempo é muito chato ficar colocando e removendo código nos métodos para imprimir informações sobre os parâmetros recebidos e valores retornados por elas.
Nesta dica fizemos uso de uma das funcionalidades que Python disponibiliza que se chama decorator. O exemplo cria um decorator que retorna uma versão “envelopada” da nossa função original, que imprime seus dados de entrada e saída. Ele também faz uso da variável __debug__ para remover esse “envelope” quando o nosso programa for executado com a opção “-O“, evitando assim qualquer eventual perda de performance no seu programa.
def debugMethod(m):
def w(*args,**kwargs):
print "DBG: CALL Classe: %s Metodo: %s args: %s kwargs: %s" % (
args[0].__class__.__name__,
m.__name__,
args[1:],
kwargs
)
r = m(*args,**kwargs)
print "DBG: RET return:", r
return r
if __debug__:
return w
return m
Para usar é supersimples:
class A(object):
@debugMethod
def teste(self, *arg, **kwargs):
return (arg, kwargs)
a = A()
a.teste("foo", "bar", baz="qux")
O resultado final fica assim:
$ python teste.py
DBG: CALL Classe: A Metodo: teste args: ('foo', 'bar')
kwargs: {'baz': 'qux'}
DBG: RET return: (('foo', 'bar'), {'baz': 'qux'})
$ python -O x.py
$
Palavras-chave: erro, debug, módulos
Se acontecer de, durante o desenvolvimento, você dar um import em um módulo Python e por alguma razão inexplicável o módulo que você importou não funciona ou funciona como se fosse uma versão antiga verifique o atributo __file__ deste módulo e veja se você realmente está importando o módulo correto.
No exemplo abaixo o módulo meu_modulo que deveria ser carregado está instalado em /usr/lib/pythonX.X/site-packages mas por alguma razão a versão que está sendo carregada não é esta. O que pode estar acontecendo?
>>> import meu_modulo >>> print meu_modulo.__file__ /home/eumesmo/meu_modulo.pyc
Acho que encontramos o problema! Existe um arquivo meu_modulo.py dentro do diretório onde eu estou que tem mais prioridade no sys.path do que o /…/site-packages.
Nem sempre o problema encontrado é tão simples de se resolver como neste exemplo, mas essa dica é igualmente útil nestes casos. Os relative imports que surgiram no Python 2.5 servem para resolver justamente esse tipo de problemas.
Palavras-chave: Python, encoding, iso-8859-1, latin-1, utf-8, unicode, DeprecationWarning
Quando você coloca algum caractere acentuado no seu programa, por exemplo “á”, um aviso é mostrado na execução:
sys:1: DeprecationWarning: Non-ASCII character ‘\xe1′ in file foo.py on line 3, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
A codificação ASCII é o padrão para códigos fonte, então é preciso avisar o Python que seus fontes usam outra. Para o português é ISO-8859-1, ou seu similar mais curto latin-1. Basta colocar um comentário especial na primeira ou segunda linha do código:
# -*- coding: latin-1 -*-
Apesar de encorajado seu uso pela documentação, os -*- são desnecessários. Exemplo funcional:
# coding: latin-1 print "á"
Sistemas e editores atuais vêm configurados com a codificação UTF-8, que abrange a maioria dos idiomas existentes. Se este for seu caso, use:
# coding: utf-8
Palavras-chave: strings, formatação, template, dicionário
Muitos programadores certamente sabem que a linguagem Python nos permite formatar strings usando os caracteres de formatação comuns à linguagem C. O que talvez poucos saibam é que existe uma “extensão” ao padrão C que faz com que o sistema de formatação de strings em Python se pareça com uma mini-linguagem de templates.
Para usar essa funcionalidade basta que, no lugar de uma tupla com valores, utilize-se um dicionário com chaves do tipo string e na “template” informe qual valor desse dicionário que será impresso:
registros = [
{ 'nome': 'Osvaldo Santana', 'linguagens': 'Python' },
{ 'nome': 'Alfredo Kojima', 'linguagens': 'C/C++/Obj-C' },
{ 'nome': 'Aurelio Jargas', 'linguagens': 'Shell' },
]
for registro in registros:
print "Nome: %(nome)-15s Linguagens: %(linguagens)s" % registro
Esse exemplo irá imprimir em:
Nome: Osvaldo Santana Linguagens: Python Nome: Alfredo Kojima Linguagens: C/C++/Obj-C Nome: Aurelio Jargas Linguagens: Shell
Palavras-chave: for, iteração, índice
O for do Python é bastante conveniente para iterar listas, descartando a necessidade de variáveis de índice auxiliares. No entanto as vezes é necessário iterar uma lista e ter o índice de cada elemento além do elemento em si. A forma óbvia é algo como:
for i in range(len(lista)): elem= lista[i] print i, "=", elem
Mas algumas vezes isto pode ser inconveniente (na construção py:for do TurboGears, por exemplo). Nestes casos podemos usar o map() para criar uma lista de tuplas de cada elemento com seu índice:
>>> lista= ["maçã", "banana", "pêra"] >>> for i, elem in map(None, range(len(lista)), lista): >>> print i, "=", elem 0 = maçã 1 = banana 2 = pêra
Atualização: Como comentado pelo Barbieri, a partir do Python 2.3 existe a função enumerate() que faz a mesma coisa:
>>> lista= ["maçã", "banana", "pêra"] >>> for i, elem in enumerate(lista): >>> print i, "=", elem 0 = maçã 1 = banana 2 = pêra
Palavras-chave: Python, mover, arquivo, diretório, shutil, link
No Python, para mover um arquivo para outro diretório basta usar o módulo shutil:
import shutil
shutil.move("este-arquivo", "/tmp")
Informe o nome do arquivo e em seguida qual o diretório de destino. O arquivo do exemplo está no diretório corrente.
Em versões mais antigas do Python como a 1.5 o método move não existia. Se este é seu caso, ou não quer carregar outro módulo somente para mover um arquivo, pode usar o próprio módulo os para isso:
import os
os.link("este-arquivo", "/tmp/este-arquivo")
os.remove("este-arquivo")
Sim é feio, mas funciona :) Primeiro ele cria um link (hardlink) entre os arquivos, depois remove o original. Note que é preciso indicar o nome do arquivo no diretório de destino.
Palavras-chave: Python, internet, http, urllib, urlopen, urlencode
O módulo urllib lhe fornece meios de acessar servidores HTTP por meios de requests GET e POST de maneira direta:
- Acessando o conteúdo da http://codare.net:
import urllib f = urllib.urlopen("http://codare.net") contents = f.read() f.close() print contents - Submetendo parâmetros (query) usando GET:
import urllib params = {"documentation": 1, "forums": 1} query = urllib.urlencode(params) url = "http://wordpress.org/search/codare?%s" % query f = urllib.urlopen(url) contents = f.read() f.close() print contents - Submetendo parâmetros usando POST:
import urllib params = {"keyword": "urllib"} query = urllib.urlencode(params) url = "http://starship.python.net/crew/theller/pyhelp.cgi" f = urllib.urlopen(url, query) contents = f.read() f.close() print contents
Com a página em mãos, você pode utilizar expressões regulares ou algum módulo específico para processar Sgml/HTML/XML para obter seus dados.
Palavras-chave: strings, otimização, concatenação
Em Python as strings são imutáveis e por essa razão, quando concatenamos duas delas usando o operador “+” um novo objeto do tipo string é criado e os objetos originais perdem as suas referências. Se não existe nenhuma outra referência para estes objetos eles serão marcados para serem eliminadas pelo coletor de lixo (garbage collector).
Quando efetuamos um número muito grande de concatenações usando esse método estamos usando de maneira ineficiente os recursos de memória e processamento da máquina simplesmente porque não estamos utilizando a estrutura de dados mais adequada para esta tarefa.
Uma maneira eficiente de fazer essa concatenação é através da utilização de listas (list()) que são estruturas mutáveis e, posteriormente, transformar essa lista de strings em uma única string, concatenando-as com o método join() do objeto str():
# jeito ineficiente
a = ""
for i in range(1000):
a += "X"
print a # 1000 x 'X'
# jeito eficiente
a = []
for i in range(1000):
a.append('X')
a = ''.join(a)
Note que a a legibilidade do código fica ligeiramente prejudicada quando usamos o método eficiente de concatenação, portanto, use-o apenas em casos onde um número muito grande de concatenações será feita.
Para programadores que fazem uso ainda mais extensivo de concatenações de strings o módulo cStringIO pode ser interessante.
Palavras-chave: HTML, escape, escapar, html_escape, htmlspecialchars, htmlentities
Funcões rápidas para escapar e desescapar caracteres especiais HTML (<, & etc)
from htmlentitydefs import codepoint2name as cp2nm, entitydefs as nm2cp
import re
def htmlescape(texto):
return "".join([cp2nm.has_key(ord(x)) and
"&%s;"%cp2nm[ord(x)] or x for x in texto])
def htmlunescape(texto):
return "".join([(x.startswith("&") and
x.endswith(";") and
nm2cp.has_key(x[1:-1]))
and nm2cp[x[1:-1]] or x
for x in re.split('(&\\\\w+;)', texto)])
Exemplo:
>>> htmlescape("a > x && y < 0")
'a > x && y < 0'
>>> htmlunescape(htmlescape("a > x && y < 0"))
'a > x && y < 0'
Palavras-chave: debug, depuração, otimização
Quando estamos desenvolvendo um programa é muito comum ter que colocar código de depuração nele para facilitar nosso trabalho. Ao mesmo tempo esse tipo de código não deveria ser executado nas mãos de nossos clientes.
Alguns programadores resolvem esse problema à sua maneira e acabam perdendo tempo para fazer isso. Em Python não é preciso criar esses mecanismos porque a linguagem já oferece duas ferramentas para lidar com isso: o comando assert e a variável __debug__. Vamos ver como usá-los:
def soma(valor):
assert valor > 0, "Valor negativo!"
soma = 0
for i in range(valor):
if __debug__:
print 'DEBUG: O valor de i:', i
soma += i
return soma
print soma(2)
print soma(-1)
Ao executar esse código teremos:
$ python x.py
DEBUG: O valor de i: 0
DEBUG: O valor de i: 1
2
Traceback (most recent call last):
File "x.py", line 11, in ?
print soma(-1)
File "x.py", line 2, in soma
assert valor > 0, "Valor negativo!"
AssertionError: Valor negativo!
Mas se executamos o mesmo programa com a opção de otimização (-O) do Python o compilador irá remover todos os comandos assert e todo o código que estiver dentro de um “if __debug__“. Como esse código é removido pelo compilador ele sequer será executado pelo interpretador. Veja:
$ python -O x.py 1 0







Comentários Recentes