Eu uso algumas regras simples para decidir entre usar classes ou funções, em python:
- se existe necessidade de manter estado: classes;
- caso contrário: funções;
- para agrupar informação relacionada, tuples ou namedtuples.
Eu uso algumas regras simples para decidir entre usar classes ou funções, em python:
Algumas configurações pouco comuns mas muito úteis.
Num ambiente X ter teclas e rato rápidos… mas não demais.
xset m 1
xset r rate 220 80
A segunda faz-me bastante falta, e é um efeito que não se consegue obter em Windows (excepto eventualmente se se usarem truques não triviais).
Cores para ecrãs de texto: letras verdes em fundo preto.
Costumava usar um simples green/black (testar=> xterm -fg green -bg black
), mas os novos ecrãs de LED IPS têm um contraste muito maior, o que torna o “green” muito mais brilhante do que estava habituado.
Após alguma pesquisa, o chamado “kelly green” (fonte: wikipedia) provou ser o melhor verde para este tipo de painéis de alto contraste.
xterm -fg #4CBB17 -bg black
Fontes mono-espaçadas para terminais e desenvolvimento: DejaVu Sans Mono Book.
Atenção à semelhança entre alguns caracteres. Ver se os seguintes são suficientemente diferentes para serem facilmente distinguidos:
i1lI O0
Em particular gosto que o zero tenha algo no meio (risco, ponto) e que o “l” pequeno faça uma curvinha pelo menos em baixo.
A fonte “DejaVu Sans Mono Book” tem representações suficientemente diferentes. Outras boas alternativas:
Bom exemplo:
Mau exemplo:
Problema: precisamos de executar uma acção sujeita a limites temporais, não mais que n
execuções por segundo são permitidas. Chamemos a isto throttle.
Como boa prática a função de throttle deve estar separada da acção f a executar. Uma abordagem funcional é perfeita: f = throttle(count, timeframe, f)
, tal que a função retornada por throttle()
tenha o mesmo inteface que f
.
Isto é precisamente o que fazem os decoradores em python.
Eis a minha implementação desta funcionalidade.
import datetime
def throttle(count, timeframe): # timeframe in seconds
def work(fn):
# state is lasttimemarker, remaining count
state = [datetime.datetime.now(), count]
def __work(*args, **kwargs):
elapsed = datetime.datetime.now() - state[0]
ntimeframes = int(elapsed.total_seconds() // timeframe)
if ntimeframes > 0: ## just an optimization
state[1] += count * ntimeframes
state[0] += datetime.timedelta(seconds=timeframe) * ntimeframes
if state[1] <= 0:
wait_time = timeframe - elapsed.total_seconds() % timeframe
time.sleep(wait_time)
return __work(*args, **kwargs)
state[1] -= 1
rv = fn(*args, **kwargs)
return rv
return __work
return work
####
import time
# exec 3 times on each 5 seconds timeframe
@throttle(3, 5)
def printtime():
print time.ctime(time.time())
for i in range(10): printtime()
Sat Jun 28 17:16:08 2014
Sat Jun 28 17:16:08 2014
Sat Jun 28 17:16:08 2014
Sat Jun 28 17:16:13 2014
Sat Jun 28 17:16:13 2014
Sat Jun 28 17:16:13 2014
Sat Jun 28 17:16:18 2014
Sat Jun 28 17:16:18 2014
Sat Jun 28 17:16:18 2014
Sat Jun 28 17:16:23 2014
Uma idiossincrasia comum em python é iterar com ciclos for
.
xs = "a b c d".split()
for x in xs:
print x
a
b
c
d
Mas por vezes é necessário ter um contador associado. A solução mais imediata é manter um contador à parte e incrementá-lo dentro do loop. Por vezes é necessário trocar o for
por um while
.
Felizmente existe uma construção nativa que permite associar uma contagem a qualquer iterador: enumerate.
xs = "a b c d".split()
for i,x in enumerate(xs):
print i,x
0 a
1 b
2 c
3 d
O enumerate é a aplicação de uma técnica comum em linguagens funcionais: transformar uma lista de valores (escalares) numa lista de tuples, juntando a informação adicional no outro membro do tuple.
Repare-se que o enumerate corresponde à aplicação de duas funções do módulo itertools
.
import itertools
xs = "a b c d".split()
for i,x in itertools.izip(itertools.count(), xs):
print i,x
0 a
1 b
2 c
3 d
Um objecto de dados só tem estado, não tem comportamento. Ou traduzindo para python: são instâncias de classes sem métodos, apenas com variáveis.
Formas de definir classes de dados.
É a solução clássica e mais explícita:
class P:
def __init__(self, sln, dll=None, aspnet=None):
self.sln = sln
self.dll = dll
self.aspnet = aspnet
Compacta, python voodoo.
class P:
def __init__(self, sln, dll=None, aspnet=None): self.__dict__.update(locals())
Falta remover o self
do próprio dicionário.
class P:
def __init__(self, sln, dll=None, aspnet=None): self.__dict__.update(locals()); del self.self
Continuando no exemplo acima, mas desta vez sem defaults.
from collections import namedtuple
P = namedtuple("P", "sln dll aspnet".split())
p = P("xpto.sln", "xpto.dll", None)
print p
# recuperando a solucao classica
class Pc:
def __init__(self, sln, dll=None, aspnet=None):
self.sln = sln
self.dll = dll
self.aspnet = aspnet
def __str__(self): return str([self.sln, self.dll, self.aspnet])
p = Pc("xpto.sln", "xpto.dll", None)
print p
Tem como resultado:
P(sln='xpto.sln', dll='xpto.dll', aspnet=None)
['xpto.sln', 'xpto.dll', None]
Resumindo:
namedtuple
fornece uma forma simples e legível de definir objectos de dados simples;Ao longo de 15 anos na área do desenvolvimento de software, sobretudo no mundo das telcos, eis o cenário que pinto sobre o estado de arte nacional.
A estratégia de TI empresarial está sujeita aos fornecedores tecnológicos.
O desenvolvimento nacional é pouco ambicioso e simples: a maior parte dos projectos desenvolvidos de raiz são uma implementação básica – ainda que por vezes massiva e/ou complicada – de um modelo source-process-dump. E.g. boa parte das aplicações web.
As necessidades de software mais exigente, do ponto de vista de complexidade, são normalmente supridas por soluções 3rd party.
A tecnologia escolhida tem pouco impacto no projecto e é irrelevante para a organização: mesmo que outras linguagens e plataformas melhorassem 10x a produtividade no desenvolvimento e deploy, esse tempo seria diluído nas ineficiências gerais do projecto.
A falta de qualidade do código é suprida via testes, ou seja, prática de code-and-fix.
As práticas de código mais comuns baseiam-se em excesso de programação imperativa mal estruturada com abuso de copy paste. Há evidência baseada em estudos que estes factores não melhoram com a experiência.