Que dicas gerais você tem para jogar golfe no Python? Estou procurando idéias que possam ser aplicadas a problemas de código-golfe e que também sejam pelo menos um pouco específicas para Python (por exemplo, "remover comentários" não é uma resposta).
Poste uma dica por resposta.
Respostas:
Use em
a=b=c=0
vez dea,b,c=0,0,0
.Use em
a,b,c='123'
vez dea,b,c='1','2','3'
.fonte
Os condicionais podem ser longos. Em alguns casos, você pode substituir uma condicional simples por
(a,b)[condition]
. Secondition
for verdade,b
será retornado.Comparar
Para isso
fonte
a if a<b else b
ea<b and a or b
(lambda(): b, lambda(): a)[a < b]()
fazer o seu próprio curto-circuito com lambdasP and A or B
para qualquer A que derbool(A)=False
. Mas(P and [A] or [B])[0]
fará o trabalho. Consulte diveintopython.net/power_of_introspection/and_or.html para obter referência.Uma grande coisa que fiz uma vez é:
ao invés de:
Os operadores de comparação do Python são ótimos.
Usando isso tudo é comparável no Python 2, você também pode evitar o
and
operador dessa maneira. Por exemplo, sea
,b
,c
ed
são inteiros,pode ser reduzido por um caractere para:
Isso usa que toda lista é maior que qualquer número inteiro.
Se
c
ed
são listas, isso fica ainda melhor:fonte
3>a>1<b<5
[$a => $b]->[$b <= $a]
:)if(a<b)+(c>d):foo()
*
. Umor
seria+
foo()if 3>a>1<b<5
Se você estiver usando uma função interna repetidamente, pode ser mais eficiente em termos de espaço dar um novo nome a ela, se estiver usando argumentos diferentes:
fonte
Às vezes, seu código Python exige que você tenha 2 níveis de indentação. O óbvio é usar um e dois espaços para cada nível de indentação.
No entanto, o Python 2 considera os caracteres de tabulação e espaço com diferentes níveis de indentação.
Isso significa que o primeiro nível de indentação pode ser um espaço e o segundo pode ser um caractere de tabulação.
Por exemplo:
Onde
\t
está o caractere de tabulação.fonte
TabError: inconsistent use of tabs and spaces in indentation.
Use a substituição de cadeias e
exec
para lidar com palavras-chave longas comolambda
essa, são repetidas frequentemente no seu código.A cadeia de destino é muito frequentemente
'lambda '
, com 7 bytes de comprimento. Suponha que seu snippet de código contenhan
ocorrências de'lambda '
e tenhas
bytes. Então:plain
opção tems
bytes.replace
opção tems - 6n + 29
bytes.%
opção tems - 5n + 22 + len(str(n))
bytes.A partir de um gráfico de bytes salvos
plain
para essas três opções, podemos ver o seguinte:exec"..."%(('lambda ',)*5)
economiza 2 bytes e é sua melhor opção.exec"...".replace('`','lambda ')
é sua melhor opção.Para outros casos, você pode indexar a tabela abaixo:
Por exemplo, se a sequência
lambda x,y:
(comprimento 11) ocorrer 3 vezes no seu código, é melhor escreverexec"..."%(('lambda x,y:',)*3)
.fonte
replace
é enorme.=>
é apenas a string= lambda
. Por exemplo,f=>:0
seriaf = lambda: 0
.Use fatias estendidas para selecionar uma sequência de várias
vs
Nesse caso booleano de duas cordas, também é possível escrever
para
Diferentemente da intercalação, isso funciona para cadeias de caracteres de qualquer tamanho, mas pode ter problemas de precedência de operador, se
b
for uma expressão.fonte
for x in ("foo","bar","baz"): print x
x
são renderizados. A parte golfada é a"fbboaaorz"[x::3]
vs.["foo","bar","baz"][x]
Como ox
valor é derivado seria outra parte da sua solução de golfe.Use
`n`
para converter um número inteiro em uma string em vez de usarstr(n)
:fonte
Armazenar tabelas de pesquisa como números mágicos
Digamos que você deseje codificar uma tabela de pesquisa booleana, como qual dos primeiros doze números em inglês contém um
n
.Em seguida, você pode implementar esta tabela de pesquisa de forma concisa como:
com o resultado
0
ou1
sendo igualFalse
aTrue
.A idéia é que o número mágico armazene a tabela como uma cadeia de bits
bin(3714)
=0b111010000010
, com on
décimo-dígito (do final) correspondente àn
entrada da tabela-th. Nós acessar on
th entrada por bitshifting o númeron
espaços para a direita e tomar o último dígito por&1
.Este método de armazenamento é muito eficiente. Compare com as alternativas
Você pode fazer com que sua tabela de pesquisa armazene entradas multibit que podem ser extraídas como
para extrair o bloco de quatro bits relevante.
fonte
Recolher dois loops numéricos em um
Digamos que você esteja iterando sobre as células de uma
m*n
grade. Em vez de doisfor
loops aninhados , um para a linha e uma das colunas, geralmente é mais curto usar um único loop para iterar sobre asm*n
células da grade. Você pode extrair a linha e a coluna da célula dentro do loop.Código original:
Código de golfe:
Na verdade, você está iterando sobre o produto cartesiano das duas faixas, codificando o par
(i,j)
comox=i*n+j
. Você salvou umarange
chamada dispendiosa e um nível de indentação dentro do loop. A ordem da iteração é inalterada.Use em
//
vez de/
no Python 3. Se você se referiri
ej
muitas vezes, pode ser mais rápido atribuir seus valoresi=k/n
,j=k%n
dentro do loop.fonte
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
loops: repl.it/EHwaitertools.product
pode ser muito mais conciso do que loops aninhados, especialmente ao gerar produtos cartesianos.a1, a2, b1, b2
são exemplos do produto cartesiano de'ab'
e'12'
A menos que o token a seguir comece com
e
ouE
. Você pode remover o espaço após um número.Por exemplo:
Torna-se:
Usar isso em instruções complicadas de uma linha pode salvar alguns caracteres.
EDIT: como @marcog apontou,
4or a
funcionará, mas nãoa or4
como isso se confunde com o nome de uma variável.fonte
if(i,j)==(4,4):
é ainda mais curto e neste caso especialif i==j==4:
4or a
a or4
0or
também não funciona (0o
é um prefixo para números octais).0 or x
sempre retornaráx
. Poderia muito bem cortar o0 or
.0or
é bom como parte de um número mais longo.10 or x
é equivalente a10or x
.Para inteiro
n
, você pode escrevern+1
Como-~n
n-1
Como~-n
porque o bit virar
~x
é igual-1-x
. Isso usa o mesmo número de caracteres, mas pode indiretamente cortar espaços ou aparar para precedência do operador.Comparar:
Os operadores
~
e unário-
são mais elevados do que precedência*
,/
,%
, ao contrário de binário+
.fonte
-~-x
salva uma vs. byte(1-x)
.a+b+1
pode ser escrita de forma mais concisa comoa-~b
.n-i-1
é juston+~i
.Uma boa maneira de converter uma iterável para listar no Python 3 :
imagine que você tem alguma iterável, como
Mas você precisa de uma lista:
É muito útil fazer uma lista de caracteres com uma string
fonte
*s,='abcde'
e, em seguida,s
cai a minha python3 interativo com um segfault :([*'abcde']
.Em vez de
range(x)
, você pode usar o*
operador em uma lista de qualquer coisa, se realmente não precisar usar o valor dei
:em oposição a
Se você precisar fazer isso mais de duas vezes, poderá atribuir qualquer iterável a uma variável e multiplicá-la pelo intervalo desejado:
Nota : isso geralmente é mais longo que
exec"pass;"*8
, portanto, esse truque deve ser usado apenas quando isso não for uma opção.fonte
[1]*8
é menor do querange(8)
, você também economiza um espaço porquefor i in[...
é legal enquantofor i in range...
não é".exec"pass;"*8
é significativamente mais curto.r=1
,r*8
for 8, e você não poderá iterar através de um número. Eu acho que você quis dizerr=[1]
Você pode usar o bom e velho smiley alienígena para reverter as seqüências:
fonte
Descompactação iterável estendida ("Atribuição com estrela", somente Python 3)
A melhor maneira de explicar isso é através de um exemplo:
Já vimos um uso disso - transformar um iterável em uma lista no Python 3 :
Aqui estão mais alguns usos.
Obtendo o último elemento de uma lista
Em algumas situações, isso também pode ser usado para obter o primeiro elemento a ser salvo em parênteses:
Atribuindo uma lista vazia e outras variáveis
Removendo o primeiro ou o último elemento de uma lista não vazia
Estes são mais curtos que as alternativas
L=L[1:]
eL.pop()
. O resultado também pode ser salvo em uma lista diferente.Dicas cortesia de @grc
fonte
a=1;L=[]
tantas vezes. É incrível que você possa salvar caracteres em algo tão simples como esse.a,*L=1,
), mas ainda conserva um caractere :)a,*_,b=L
definir literais em Python2.7
Você pode escrever conjuntos como este
S={1,2,3}
Isso também significa que você pode verificar a associação usando, em{e}&S
vez dee in S
salvar um caractere.fonte
if
s como não há espaços (if{e}&S:
)not in
por{e}-S
esse truqueDurante anos, me incomodou o fato de eu não conseguir pensar em uma maneira curta de obter o alfabeto inteiro. Se você usar o
range
suficiente,R=range
vale a pena ter em seu programa, entãoé mais curto que o ingênuo
, mas, caso contrário, é mais longo com um único caractere. Me assombrava que o inteligente que exigia algum conhecimento de valores ascii acabasse sendo mais detalhado do que apenas digitar todas as letras.
Até que eu vi essa resposta para o alfabeto da minha filha . Não consigo acompanhar o histórico de edição o suficiente para descobrir se esse gênio foi obra do OP ou se foi uma sugestão de um comentarista, mas essa é (acredito) a maneira mais curta de criar um iterável das 26 letras no alfabeto romano.
Se maiúsculas e minúsculas não importarem, você pode retirar outro caractere usando maiúsculas:
Eu uso
map
demais, não sei como isso nunca me ocorreu.fonte
string.lowercase
- é para isso que serve.ord('z')
)? Além de ter o mesmo comprimento ... Além disso, se você precisar de alfanuméricos, substituastr.isalpha
na versão do @ quintopia porstr.isalnum
. (Mas se você só precisa de um caso, a string de 36 caráter inteiro não é mais do quefilter(str.isalnum,map(chr,range(90)))
.)R
, minha versão é mais curta que a original:'%c'*26%tuple(R(97,123))
(apenas 24 caracteres) se você soletrarrange
, é apenas enquanto o alfabeto - a versão maiúscula for mais curtaEmbora o python não tenha instruções de opção, você pode emulá-las com dicionários. Por exemplo, se você deseja uma opção como esta:
Você poderia usar
if
instruções ou poderia usar isto:ou isto:
o que é melhor se todos os caminhos de código forem funções com os mesmos parâmetros.
Para suportar um valor padrão, faça o seguinte:
(ou isto:)
Uma outra vantagem disso é que, se você tiver redundâncias, poderá adicioná-las após o final do dicionário:
E se você quiser apenas usar uma opção para retornar um valor:
Você poderia fazer isso:
fonte
dict(s1=v1,s2=v2,...,sn=vn)
em vez de{'s1':v1,'s2':v2,...,'sn':vn}
salva 2 * N-4 bytes e é melhor se n> = 3Quando você tem dois valores booleanos,
a
eb
, se você quiser descobrir se tantoa
eb
são verdadeiras, use*
em vez deand
:vs
se qualquer valor for falso, ele será avaliado como
0
nessa instrução e um valor inteiro só será verdadeiro se for diferente de zero.fonte
&
:a=b=False
,a&b
+
paraor
se você pode garantira != -b
|
funciona em todas as situações.*
em vez deand
/&&
salva alguns bytes em vários idiomas.Explorar representações de string do Python 2
O Python 2 permite converter um objeto
x
em sua representação de string`x`
a um custo de apenas 2 caracteres. Use isso para tarefas que são mais fáceis de executar na cadeia de caracteres do objeto do que no próprio objeto.Juntar personagens
Dada uma lista de caracteres
l=['a','b','c']
, pode-se produzir''.join(l)
como`l`[2::5]
, o que salva um byte.A razão é que
`l`
é"['a', 'b', 'c']"
(com espaços), para que se possa extrair as letras com uma fatia da lista, iniciando o segundo caractere indexado a zeroa
e pegando cada quinto caractere a partir daí. Isso não funciona para unir cadeias de caracteres múltiplos ou caracteres de escape representados como'\n'
.Concatenar dígitos
Da mesma forma, dada uma lista não vazia de dígitos como
l=[0,3,5]
, pode-se concatená-los em uma string'035'
como`l`[1::3]
.Isso economiza fazendo algo parecido
map(str,l)
. Observe que eles devem ter um dígito e não podem ter flutuadores1.0
misturados. Além disso, isso falha na lista vazia, produzindo]
.Verifique se há negativos
Agora, para uma tarefa não-string. Suponha que você tenha uma lista
l
de números reais e queira testar se ele contém números negativos, produzindo um booleano.Você pode fazer
que verifica se há um sinal negativo na sequência rep. Este menor que qualquer um
Para o segundo,
min(l)<0
falharia na lista vazia, então você precisa fazer hedge.fonte
str(l)[2::5]
seja 12 bytes, contra 19 para''.join(map(str,l))
. Uma situação real em que isso surgiu (ondel
estava uma declaração de gerador, não uma lista) me salvou apenas um byte ... o que ainda vale a pena!Uma função de uma linha pode ser executada com o lambda:
pode ser convertido em (observe falta de espaço
3and
e10or
)fonte
c=lambda a:a+[-5,10][a<3]
. o e / ou truque é mais útil quando você está dependendo do comportamento de curto-circuitoelse:
pode ser descartado comoreturn
interrompe a execução da função; portanto, tudo o que se segue é executado apenas se aif
condição falhar, ou seja, se aelse
condição for verdadeira. Assim,else
pode ser omitido com segurança. (Explicado em detalhes para os neófitos lá fora)c=lambda a:a-5+15*(a<3)
loops de até 4 itens podem ser melhores para fornecer uma tupla em vez de usar o range
vs
fonte
Teto e Piso
Se você quiser obter o resultado arredondado de uma divisão, da mesma forma que faria com o
//
piso, usemath.ceil(3/2)
15 ou mais curto-(-3//2)
para 8 bytes.fonte
n//1+1
em vez de ceil mas faz ceil (n) média = n + 1, mas ele deve funcionar para todos os valores não inteirosround(x)
é(x+.5)//1
, +1 byte, mas o último começa com a(
, e sex
é uma soma que consiste em uma constante, pode ser útil.Use em
+=
vez deappend
eextend
pode ser reduzido para:
B,
aqui cria uma tupla de um elemento que pode ser usada para estenderA
como[B]
emA+=[B]
.pode ser reduzido para:
fonte
return 0
oureturn 1
é equivalente areturn False
oureturn True
.-x
ao invés dex*-1
.--8.32
ao invés de-8.32*-1
. Ou apenas8.32
...A+=B
B
é atuple
.Escolhendo um dos dois números com base em uma condição
Você já sabe usar a seleção da lista
[x,y][b]
com um booleanob
para a expressão ternáriay if b else x
. As variáveisx
,y
eb
também podem ser expressões, embora note que tantox
ey
são avaliadas mesmo quando não selecionado.Aqui estão algumas otimizações em potencial quando
x
ey
são números.[0,y][b] -> y*b
[1,y][b] -> y**b
[x,1][b] -> b or x
[x,x+1][b] -> x+b
[x,x-1][b] -> x-b
[1,-1][b] -> 1|-b
[x,~x][b] -> x^-b
[x,y][b] -> x+z*b
(ouy-z*b
), onde z = yx.Você também pode alternar
x
e,y
se puder, reescreverb
para ser sua negação.fonte
Use ~ para indexar no final de uma lista
Se
L
for uma lista, useL[~i]
para obter oi
'ésimo elemento da parte de trás.Este é o
i
décimo elemento do reverso deL
. O complemento de bit~i
é igual-i-1
e, portanto, corrige o erro de um por umL[-i]
.fonte
PEP448 - Generalizações adicionais de desempacotamento
Com o lançamento do Python 3.5 , a manipulação de listas, tuplas, conjuntos e ditados ficou ainda mais complicada.
Transformando um iterável em um conjunto / lista
Compare os pares:
Muito mais curto! Observe, no entanto, que se você deseja converter algo em uma lista e atribuí-lo a uma variável, a descompactação iterável estendida normal é mais curta:
Uma sintaxe semelhante funciona para tuplas:
que é como descompactar iterável estendida, mas com o asterisco e a vírgula do outro lado.
Juntando listas / tuplas
A descompactação é um pouco menor que a concatenação se você precisar anexar uma lista / tupla aos dois lados:
Imprimir o conteúdo de várias listas
Isso não se limita a
print
, mas é definitivamente de onde virá a maior parte da milhagem. O PEP448 agora permite a descompactação múltipla, da seguinte forma:Atualizando vários itens do dicionário
Provavelmente isso não acontecerá com muita frequência, mas a sintaxe pode ser usada para economizar na atualização de dicionários se você estiver atualizando pelo menos três itens:
Isso basicamente nega qualquer necessidade
dict.update
.fonte
Mude
import *
paraimport*
Se você não ouviu,
import*
salva caracteres!tem apenas 1 caractere mais longo
import math as m
e você remove todas as instâncias dem.
Mesmo o uso de uma vez é uma poupança!
fonte
se o valor de i é inútil:
ou
fonte
for i in[0]*x:s+=input()
para economizar outro espaço. Além disso, você pode remover o espaço entre o exec ea primeira aspa para obterexec's+=input();'*x
for i in[0]*x:s+=input()