¿Qué consejos generales tienes para jugar al golf en Python? Estoy buscando ideas que se puedan aplicar a problemas de código de golf y que también sean al menos algo específicas para Python (por ejemplo, "eliminar comentarios" no es una respuesta).
Por favor, publique un consejo por respuesta.

Respuestas:
Usar en
a=b=c=0lugar dea,b,c=0,0,0.Usar en
a,b,c='123'lugar dea,b,c='1','2','3'.fuente
Los condicionales pueden ser largos. En algunos casos, puede reemplazar un condicional simple con
(a,b)[condition]. Siconditiones cierto, entoncesbse devuelve.Comparar
A esto
fuente
a if a<b else bya<b and a or b(lambda(): b, lambda(): a)[a < b]()haz tu propio cortocircuito con lambdasP and A or Bcualquier A que débool(A)=False. Pero(P and [A] or [B])[0]hará el trabajo. Consulte diveintopython.net/power_of_introspection/and_or.html como referencia.Una gran cosa que hice una vez es:
en lugar de:
Los operadores de comparación de Python son geniales.
Usando que todo es comparable en Python 2, también puede evitar al
andoperador de esta manera. Por ejemplo, sia,b,cydson números enteros,puede ser acortado por un personaje para:
Esto usa que cada lista es más grande que cualquier número entero.
Si
cydson listas, esto se pone aún mejor:fuente
3>a>1<b<5[$a => $b]->[$b <= $a]:)if(a<b)+(c>d):foo()*. Unorsería+foo()if 3>a>1<b<5Si usa una función incorporada repetidamente, podría ser más eficiente en espacio darle un nuevo nombre, si usa argumentos diferentes:
fuente
Algunas veces su código Python requiere que tenga 2 niveles de sangría. Lo obvio es usar uno y dos espacios para cada nivel de sangría.
Sin embargo, Python 2 considera que los caracteres de tabulación y espacio son diferentes niveles de sangría.
Esto significa que el primer nivel de sangría puede ser un espacio y el segundo puede ser un carácter de tabulación.
Por ejemplo:
¿Dónde
\testá el carácter de tabulación?fuente
TabError: inconsistent use of tabs and spaces in indentation.Use la sustitución de cadenas y
execpara manejar palabras clave largas comolambdaesa se repiten a menudo en su código.La cadena de destino es muy a menudo
'lambda ', que tiene 7 bytes de longitud. Suponga que su fragmento de código contienenocurrencias de'lambda 'y tiene unaslongitud de bytes. Entonces:plainopción tiene unaslongitud de bytes.replaceopción tiene unas - 6n + 29longitud de bytes.%opción tiene unas - 5n + 22 + len(str(n))longitud de bytes.De una gráfica de bytes guardados
plainpara estas tres opciones, podemos ver que:exec"..."%(('lambda ',)*5)ahorra 2 bytes y es su mejor opción.exec"...".replace('`','lambda ')es su mejor opción.Para otros casos, puede indexar la siguiente tabla:
Por ejemplo, si la cadena
lambda x,y:(longitud 11) aparece 3 veces en su código, es mejor que escribaexec"..."%(('lambda x,y:',)*3).fuente
replacees enorme.=>es solo la cadena= lambda. Por ejemplo,f=>:0seríaf = lambda: 0.Use el corte extendido para seleccionar una cadena entre muchas
vs
En este caso booleano de dos cuerdas, también se puede escribir
para
A diferencia del intercalado, esto funciona para cadenas de cualquier longitud, pero puede tener problemas de precedencia de operador si, en
bcambio, es una expresión.fuente
for x in ("foo","bar","baz"): print xx. La parte de golf es el"fbboaaorz"[x::3]vs["foo","bar","baz"][x]Cómoxse deriva el valor sería otra parte de su solución de golf.Use
`n`para convertir un entero en una cadena en lugar de usarstr(n):fuente
Almacenar tablas de búsqueda como números mágicos
Supongamos que desea codificar una tabla de búsqueda booleana, como cuál de los primeros doce números en inglés contiene un
n.Luego, puede implementar esta tabla de búsqueda de forma concisa como:
con el resultado
0o1ser igualFalseaTrue.La idea es que el número mágico almacena la tabla como una cadena de bits
bin(3714)=0b111010000010, con elnenésimo dígito (desde el final) correspondiente a lanentrada de la tabla th. Accedemos a lanXX entrada por bitshifting el númeronde espacios a la derecha y tomar el último dígito&1.Este método de almacenamiento es muy eficiente. Compara con las alternativas
Puede hacer que su tabla de búsqueda almacene entradas multibit que se pueden extraer como
para extraer el bloque de cuatro bits relevante.
fuente
Contraer dos bucles numéricos en uno
Digamos que estás iterando sobre las celdas de una
m*ncuadrícula. En lugar de dosforbucles anidados , uno para la fila y una de las columnas, generalmente es más corto usar un solo bucle para iterar sobre lasm*nceldas de la cuadrícula. Puede extraer la fila y la columna de la celda dentro del bucle.Código original:
Código de golf:
En efecto, estás iterando sobre el producto cartesiano de los dos rangos, codificando el par
(i,j)comox=i*n+j. Ha guardado unarangellamada costosa y un nivel de sangría dentro del bucle. El orden de iteración no ha cambiado.Use en
//lugar de/en Python 3. Si se refiereiyjmuchas veces, puede ser más rápido asignar sus valoresi=k/n,j=k%ndentro del ciclo.fuente
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)nbucles: repl.it/EHwaitertools.productpuede ser mucho más conciso que los bucles anidados, especialmente al generar productos cartesianos.a1, a2, b1, b2son ejemplos del producto cartesiano de'ab'y'12'A menos que el siguiente token comience con
eoE. Puede eliminar el espacio después de un número.Por ejemplo:
Se convierte en:
Usar esto en declaraciones complicadas de una línea puede ahorrar bastantes caracteres.
EDITAR: como señaló @marcog,
4or afuncionará, pero noa or4ya que esto se confunde con un nombre de variable.fuente
if(i,j)==(4,4):es aún más corto y en este caso especialif i==j==4:4or afunciona, pero noa or40ortampoco funciona (0oes un prefijo para números octales).0 or xque siempre va a volverx. También podría cortar el0 or.0orSin embargo, está bien como parte de un número más largo.10 or xes equivalente a10or x.Por entero
n, puedes escribirn+1como-~nn-1como~-nporque el cambio de bit
~xes igual-1-x. Utiliza el mismo número de caracteres, pero puede cortar espacios o parees indirectamente para la precedencia del operador.Comparar:
Los operadores
~y unario-son más altas que prevalecen*,/,%, a diferencia binaria+.fuente
-~-xahorra uno contra bytes(1-x).a+b+1se puede escribir de manera más concisa comoa-~b.n-i-1es juston+~i.Una buena manera de convertir un iterable a la lista en Python 3 :
imagina que tienes algunos iterables, como
Pero necesitas una lista:
Es muy útil hacer una lista de caracteres de una cadena
fuente
*s,='abcde'y luegosbloquea mi python3 interactivo con un segfault :([*'abcde'].En lugar de
range(x), puede usar el*operador en una lista de cualquier cosa, si realmente no necesita usar el valor dei:Opuesto a
Si necesita hacer esto más de dos veces, puede asignar cualquier iterable a una variable y multiplicar esa variable por el rango que desee:
Nota : esto suele ser más largo que
exec"pass;"*8, por lo que este truco solo debe usarse cuando no es una opción.fuente
[1]*8es más corto querange(8), también puede ahorrar un espacio porquefor i in[...es legal mientrasfor i in range...que no lo es".exec"pass;"*8Es significativamente más corto.r=1,r*8es 8, y no puede iterar a través de un número. Supongo que quisiste decirr=[1]Puedes usar la vieja carita feliz alienígena para invertir las secuencias:
fuente
Desempaquetado iterable extendido ("Asignación destacada", solo Python 3)
La mejor manera de explicar esto es a través de un ejemplo:
Ya hemos visto un uso para esto: convertir un iterable en una lista en Python 3 :
Aquí hay algunos usos más.
Obtener el último elemento de una lista
En algunas situaciones, esto también se puede usar para obtener el primer elemento para guardar en los padres:
Asignación de una lista vacía y otras variables.
Eliminar el primer o el último elemento de una lista no vacía
Estos son más cortos que las alternativas
L=L[1:]yL.pop(). El resultado también se puede guardar en una lista diferente.Consejos cortesía de @grc
fuente
a=1;L=[]muchas veces. Es sorprendente que puedas guardar caracteres en algo tan sencillo como esto.a,*L=1,), pero aún ahorra un carácter :)a,*_,b=Lestablecer literales en Python2.7
Puede escribir conjuntos como este
S={1,2,3}Esto también significa que puede verificar la membresía usando en{e}&Slugar de loe in Sque guarda un carácter.fuente
ifs ya que no hay espacios (if{e}&S:)not inpor{e}-Sese trucoDurante siglos me molestó que no pudiera pensar en una forma corta de obtener el alfabeto completo. Si usa lo
rangesuficiente queR=rangevale la pena tener en su programa, entonceses más corto que el ingenuo
, pero por lo demás es más largo por un solo personaje. Me persiguió que el inteligente que requería un cierto conocimiento de los valores ascii terminara siendo más detallado que simplemente escribir todas las letras.
Hasta que vi esta respuesta para el alfabeto de mi hija . No puedo seguir el historial de edición lo suficientemente bien como para descubrir si este genio fue obra del OP o si fue una sugerencia de un comentarista, pero esta es (creo) la forma más corta de crear un iterable de las 26 letras. en el alfabeto romano
Si el caso no importa, puedes quitar otro personaje usando mayúsculas:
Uso
mapdemasiado, no sé cómo esto nunca se me ocurrió.fuente
string.lowercase: para eso está.ord('z'))? Además de ser de la misma longitud ... Además, si necesita alfanuméricos, reemplácelosstr.isalphaen la versión de @ quintopia constr.isalnum. (Pero si solo necesita un caso, la cadena completa de 36 caracteres no es más larga quefilter(str.isalnum,map(chr,range(90)))).R, mi versión es más corta que la original:'%c'*26%tuple(R(97,123))(solo 24 caracteres) si la deletrearangees tan larga como el alfabeto - la versión en mayúscula es más cortaAunque python no tiene declaraciones de cambio, puede emularlas con diccionarios. Por ejemplo, si desea un interruptor como este:
Podría usar
ifdeclaraciones, o podría usar esto:o esto:
lo cual es mejor si todas las rutas de código son funciones con los mismos parámetros.
Para admitir un valor predeterminado, haga esto:
(o esto:)
Otra ventaja de esto es que si tiene redundancias, puede agregarlas después del final del diccionario:
Y si solo desea utilizar un interruptor para devolver un valor:
Podrías hacer esto:
fuente
dict(s1=v1,s2=v2,...,sn=vn)lugar de{'s1':v1,'s2':v2,...,'sn':vn}guardar 2 * n-4 bytes y es mejor si n> = 3Cuando tiene dos valores booleanos,
ayb, si se quiere averiguar si ambosaybson verdaderas, utilizar*en lugar deand:vs
si cualquiera de los valores es falso, se evaluará como
0en esa declaración, y un valor entero solo es verdadero si no es cero.fuente
&:a=b=False,a&b+paraorsi se puede garantizara != -b|Funciona en todas las situaciones.*en lugar deand/&&guarda algunos bytes en muchos idiomas.Explotar representaciones de cadenas de Python 2
Python 2 le permite convertir un objeto
xa su representación de cadena`x`a un costo de solo 2 caracteres. Use esto para tareas que son más fáciles de hacer en la cadena del objeto que en el objeto mismo.Unir personajes
Dada una lista de caracteres
l=['a','b','c'], uno puede producir''.join(l)como`l`[2::5], lo que guarda un byte.La razón es que
`l`es"['a', 'b', 'c']"(con espacios), por lo que uno puede extraer las letras con un corte de lista, comenzando ese segundo carácter indexado a ceroay tomando cada quinto carácter desde allí. Esto no funciona para unir cadenas de caracteres múltiples o caracteres de escape representados como'\n'.Dígitos concatenados
Del mismo modo, dada una lista no vacía de dígitos como
l=[0,3,5], uno puede concatenarlos en una cadena'035'como`l`[1::3].Esto ahorra hacer algo como
map(str,l). Tenga en cuenta que deben ser de un solo dígito y no pueden tener flotantes como1.0mezclados. Además, esto falla en la lista vacía, produciendo].Verifica si hay negativos
Ahora, para una tarea sin cadenas. Suponga que tiene una lista
lde números reales y quiere probar si contiene números negativos, produciendo un Booleano.Tu puedes hacer
que comprueba si hay un signo negativo en el representante de la cadena. Este más corto que cualquiera de
Por el segundo,
min(l)<0fallaría en la lista vacía, por lo que debe cubrirse.fuente
str(l)[2::5]es 12 bytes, frente a 19 para''.join(map(str,l)). Una situación real en la que esto surgió (dondelhabía una declaración de generador, no una lista) me salvó solo un byte ... ¡que todavía vale la pena!Se puede hacer una función de una línea con lambda:
se puede convertir a (tenga en cuenta el espacio faltante
3andy10or)fuente
c=lambda a:a+[-5,10][a<3]. el y / o el truco es más útil cuando depende del comportamiento delelse:puede descartarse ya quereturndetiene la ejecución de la función, por lo que todo lo que sigue solo se ejecuta si laifcondición falla, es decir, si laelsecondición es verdadera. Porelselo tanto, se puede omitir con seguridad. (Explicado en detalles para los neófitos)c=lambda a:a-5+15*(a<3)los bucles de hasta 4 elementos pueden ser mejores para suministrar una tupla en lugar de usar el rango
vs
fuente
Techo y piso
Si alguna vez desea obtener el resultado redondeado para una división, al igual que lo haría con el
//piso, puede usarmath.ceil(3/2)para 15 o el más corto-(-3//2)para 8 bytes.fuente
n//1+1lugar de ceil pero significa ceil (n) = n + 1 pero debería funcionar para todos los valores no enterosround(x)es(x+.5)//1, +1 byte pero este último comienza con a(, y sixes una suma que consiste en una constante, puede ser útil.Usar en
+=lugar deappendyextendse puede acortar a:
B,aquí crea una tupla de un elemento que se puede usar para extenderAal igual que[B]enA+=[B].se puede acortar a:
fuente
return 0oreturn 1es equivalente areturn Falseoreturn True.-xen lugar dex*-1.--8.32en lugar de-8.32*-1. O simplemente8.32...A+=BBes atuple.Elegir uno de dos números en función de una condición
Usted ya sabe usar la selección de la lista
[x,y][b]con un valor booleanobpara la expresión ternariay if b else x. Las variablesx,yybtambién pueden ser expresiones, aunque tenga en cuenta que ambasxyyse evalúan incluso cuando no se seleccionan.Aquí hay algunas optimizaciones potenciales cuando
xyyson 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(oy-z*b), donde z = yx.También puede cambiar
xyysi puede reescribirbpara ser su negación.fuente
Use ~ para indexar desde el final de una lista
Si
Les una lista, useL[~i]para obtener eli'th elemento desde atrás.Este es el
i'th elemento del reverso deL. El complemento de bits~ies igual-i-1y, por lo tanto, corrige el error off-by-oneL[-i].fuente
PEP448 - Generalizaciones adicionales de desempaque
Con el lanzamiento de Python 3.5 , la manipulación de listas, tuplas, conjuntos y dictos se volvió más golfista.
Convertir un iterable en un conjunto / lista
Compara los pares:
¡Mucho más corto! Sin embargo, tenga en cuenta que si solo desea convertir algo en una lista y asignarlo a una variable, el desempaquetado iterativo extendido normal es más corto:
Una sintaxis similar funciona para las tuplas:
que es como desempaquetar iterable extendido, pero con el asterisco y la coma en el otro lado.
Unirse a listas / tuplas
Desempacar es un poco más corto que la concatenación si necesita agregar una lista / tupla a ambos lados:
Imprimir el contenido de múltiples listas
Esto no se limita a
print, pero definitivamente es de donde vendrá la mayor parte del kilometraje. PEP448 ahora permite el desempaque múltiple, así:Actualización de múltiples elementos del diccionario
Esto probablemente no sucederá muy a menudo, pero la sintaxis se puede usar para ahorrar en la actualización de diccionarios si está actualizando al menos tres elementos:
Esto básicamente niega cualquier necesidad de
dict.update.fuente
Cambiar
import *aimport*Si no has escuchado,
import*guarda caracteres!es solo 1 carácter más largo
import math as my puede eliminar todas las instancias dem.¡Incluso el uso de una sola vez es un ahorro!
fuente
si el valor de i es inútil:
o
fuente
for i in[0]*x:s+=input()para ahorrar otro espacio. Además, puede eliminar el espacio entre el ejecutivo y la primera comilla para obtenerexec's+=input();'*xfor i in[0]*x:s+=input()