Consejos para jugar golf en Python

248

¿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.

marcog
fuente
27
Oh, puedo ver un conjunto completo de preguntas como esta para cada idioma ...
R. Martinho Fernandes
44
@Marthinho, estoy de acuerdo. Acabo de comenzar un equivalente de C ++ . Sin embargo, no creo que sea algo malo, siempre y cuando no veamos las mismas respuestas publicadas en muchos de estos tipos de preguntas.
marcog
50
Me encanta la pregunta, pero tengo que seguir diciéndome "esto es SOLO por diversión, NO por el código de producción"
Greg Guida
2
¿No debería ser esta pregunta una publicación de wiki comunitaria?
dorukayhan
3
@dorukayhan Nope; es una pregunta válida de consejos de código de golf , que pide consejos sobre acortar el código de Python para fines de CG. Dichas preguntas son perfectamente válidas para el sitio, y ninguna de estas etiquetas dice explícitamente que la pregunta debe ser CW'd, a diferencia de SO, que requiere que los desafíos de CG sean CW'd. Además, escribir una buena respuesta y encontrar estos consejos siempre merece algo, que se elimina si la pregunta es community wiki (rep).
Erik the Outgolfer

Respuestas:

152

Usar en a=b=c=0lugar de a,b,c=0,0,0.

Usar en a,b,c='123'lugar de a,b,c='1','2','3'.

marcog
fuente
2
eso es un buen consejo en general :)
28
Tenga en cuenta que esto no necesariamente funcionará para definir objetos mutables que modificará en el lugar. a = b = [1] es realmente diferente de a = [1]; b = [1]
isaacg
66
Lo curioso del primer consejo es que también funciona en Java.
Justin
1
@Justin Sí, pero solo con tipos primitivos
HyperNeutrino
11
Pero NUNCA use a = b = c = [] o cualquier instancia de objeto ya que todas las variables apuntarán a la misma instancia. Eso probablemente no sea lo que quieres.
PhE
146

Los condicionales pueden ser largos. En algunos casos, puede reemplazar un condicional simple con (a,b)[condition]. Si conditiones cierto, entonces bse devuelve.

Comparar

if a<b:return a
else:return b

A esto

return(b,a)[a<b]
marcog
fuente
37
Estos no son exactamente lo mismo. El primero evalúa solo la expresión que se devuelve, mientras que el segundo siempre los evalúa a ambos. Estos hacen cortocircuito: a if a<b else bya<b and a or b
marinus
3
(lambda(): b, lambda(): a)[a < b]()haz tu propio cortocircuito con lambdas
Ming-Tang
3
@marinus, no son iguales: solo considera P 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.
kgadek
66
Las lambdas son mucho más largas que una expresión condicional.
user2357112
18
@ user2357112 Pero te hacen ver mucho mejor cuando los usas. :]
Chase Ries
117

Una gran cosa que hice una vez es:

if 3 > a > 1 < b < 5: foo()

en lugar de:

if a > 1 and b > 1 and 3 > a and 5 > b: foo()

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, si a, b, cy dson números enteros,

if a<b and c>d:foo()

puede ser acortado por un personaje para:

if a<b<[]>c>d:foo()

Esto usa que cada lista es más grande que cualquier número entero.

Si cy dson listas, esto se pone aún mejor:

if a<b<c>d:foo()
Juan
fuente
22
Por supuesto, si esto fuera realmente golfizado sería3>a>1<b<5
Rafe Kettler
44
Amo la simetría. Me recuerda el viejo truco de golf de Perl para encontrar el mínimo de $ a y $ b: [$a => $b]->[$b <= $a]:)
Simon Whitaker
Tenga en cuenta que el segundo ejemplo (sin listas) también se puede hacer conif(a<b)+(c>d):foo()
WorldSEnder
66
El + debería ser a *. Un orsería+
WorldSEnder
1
foo()if 3>a>1<b<5
Erik the Outgolfer
103

Si usa una función incorporada repetidamente, podría ser más eficiente en espacio darle un nuevo nombre, si usa argumentos diferentes:

r=range
for x in r(10):
 for y in r(100):print x,y
marcog
fuente
66
Sin embargo, en realidad no guardó ningún byte.
user2357112
44
r = rango y las otras dos r son 9 caracteres; usar el rango dos veces es de 10 caracteres. No es un gran ahorro en este ejemplo, pero todo lo que necesitaría es un uso más del rango para ver un ahorro significativo.
Frank
13
@Frank La nueva línea adicional es otro personaje.
L3viathan
2
De hecho, dos repeticiones son demasiado pequeñas para guardar un nombre de cinco funciones de longitud. Necesita: longitud 2: 6 repeticiones, longitud 3: 4 repeticiones, longitud 4 o 5: 3 repeticiones, longitud> = 6: 2 repeticiones. AKA (longitud-1) * (repeticiones-1)> 4.
Ørjan Johansen
Tenga en cuenta que esto es aplicable a todos los idiomas con funciones de primera clase.
bfontaine
94

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:

if 1:
 if 1:
\tpass

¿Dónde \testá el carácter de tabulación?

JPvdMerwe
fuente
1
¡Genial, nunca pensé en este!
Jules Olléon
97
Esto falla en python3: ya no puedes mezclar espacios y pestañas (algo malo para codegolf, pero algo bueno en todos los demás casos).
Bakuriu
1
En Python 3.4 esto parece funcionar bien.
trichoplax
3
@trichoplax , en python 3.4.3 obtengoTabError: inconsistent use of tabs and spaces in indentation.
ceilingcat el
Como referencia, una pestaña vale 8 espacios.
Erik the Outgolfer
87

Use la sustitución de cadenas y execpara manejar palabras clave largas como lambdaesa se repiten a menudo en su código.

a=lambda b:lambda c:lambda d:lambda e:lambda f:0   # 48 bytes  (plain)
exec"a=`b:`c:`d:`e:`f:0".replace('`','lambda ')    # 47 bytes  (replace)
exec"a=%sb:%sc:%sd:%se:%sf:0"%(('lambda ',)*5)     # 46 bytes  (%)

La cadena de destino es muy a menudo 'lambda ', que tiene 7 bytes de longitud. Suponga que su fragmento de código contiene nocurrencias de 'lambda 'y tiene una slongitud de bytes. Entonces:

  • La plainopción tiene una slongitud de bytes.
  • La replaceopción tiene una s - 6n + 29longitud de bytes.
  • La %opción tiene una s - 5n + 22 + len(str(n))longitud de bytes.

De una gráfica de bytes guardadosplain para estas tres opciones, podemos ver que:

  • Para n <5 lambdas, es mejor que no hagas nada elegante.
  • Para n = 5 , escribir exec"..."%(('lambda ',)*5)ahorra 2 bytes y es su mejor opción.
  • Para n> 5 , escribir exec"...".replace('`','lambda ')es su mejor opción.

Para otros casos, puede indexar la siguiente tabla:

          1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 (occurences)
       +---------------------------------------------------------
     3 |  -  -  -  -  -  -  -  -  -  -  -  -  -  -  r  r  r  r  r  
     4 |  -  -  -  -  -  -  -  -  -  r  r  r  r  r  r  r  r  r  r  
     5 |  -  -  -  -  -  -  -  r  r  r  r  r  r  r  r  r  r  r  r  
     6 |  -  -  -  -  -  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
     7 |  -  -  -  -  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
     8 |  -  -  -  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
     9 |  -  -  -  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
    10 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
    11 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
    12 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r = replace
    13 |  -  -  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r   % = string %
    14 |  -  %  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r   - = do nothing
    15 |  -  %  %  %  %  r  r  r  r  r  r  r  r  r  r  r  r  r  r  
  (length)

Por ejemplo, si la cadena lambda x,y:(longitud 11) aparece 3 veces en su código, es mejor que escriba exec"..."%(('lambda x,y:',)*3).

Ming-Tang
fuente
44
esto debería obtener más votos, es un consejo muy útil.
bigblind
77
Es extremadamente raro que esto funcione. El costo de replacees enorme.
boothby
44
Sin embargo, cuando funciona, ayuda mucho.
undergroundmonorail
Interesante, ¡nunca pensé en esto!
Claudiu
Agregué un nuevo operador para lambda en mi lenguaje basado en python: =>es solo la cadena = lambda . Por ejemplo, f=>:0sería f = lambda: 0.
NoOneIsHere
78

Use el corte extendido para seleccionar una cadena entre muchas

>>> for x in 0,1,2:print"fbboaaorz"[x::3]
... 
foo
bar
baz

vs

>>> for x in 0,1,2:print["foo","bar","baz"][x]
... 
foo
bar
baz

En este caso booleano de dos cuerdas, también se puede escribir

b*"string"or"other_string"

para

["other_string","string"][b]

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.

gnibbler
fuente
Tenga en cuenta que el primer ejemplo tiene exactamente la misma longitud quefor x in ("foo","bar","baz"): print x
Mateen Ulhaq
1
@MateenUlhaq, eso es solo un ejemplo de cómo se representan los diferentes valores de x. La parte de golf es el "fbboaaorz"[x::3]vs ["foo","bar","baz"][x]Cómo xse deriva el valor sería otra parte de su solución de golf.
gnibbler
72

Use `n`para convertir un entero en una cadena en lugar de usar str(n):

>>> n=123
>>> `n`
'123'
marcog
fuente
38
Agradable, pero no funciona con Python3.
Alexandru
2
Atención: realmente funciona para enteros, pero no para cadenas, por ejemplo.
Nakilon
41
por cierto. `` es la abreviatura de repr
Alexandru
99
Los enteros menores que -2 ** 31 o mayores que 2 ** 31-1 (Longs) obtienen una 'L' añadida al final.
hallvabo
66
Esto también se puede usar para imprimir carrozas con total precisión
gnibbler
69

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.

0: False
1: True
2: False
3: False
4: False
5: False
6: False
7: True
8: False
9: True
10:True
11:True
12:False

Luego, puede implementar esta tabla de búsqueda de forma concisa como:

3714>>i&1

con el resultado 0o 1ser igual Falsea True.

La idea es que el número mágico almacena la tabla como una cadena de bits bin(3714)= 0b111010000010, con el nenésimo dígito (desde el final) correspondiente a la nentrada de la tabla th. Accedemos a la nXX entrada por bitshifting el número nde espacios a la derecha y tomar el último dígito &1.

Este método de almacenamiento es muy eficiente. Compara con las alternativas

n in[1,7,9,10,11]
'0111010000010'[n]>'0'

Puede hacer que su tabla de búsqueda almacene entradas multibit que se pueden extraer como

 340954054>>4*n&15

para extraer el bloque de cuatro bits relevante.

xnor
fuente
¿Podríamos tener un resultado de ejemplo para el bloque de cuatro bits? ¿Usó una regla para el bloque de n bits?
JeromeJ
8
El maleficio a veces puede ser incluso más pequeño.
Joonazan
44
Esto es útil para muchos idiomas.
Cyoce
1
@Joonazan Hex es más pequeño para números superiores a 999 999 .
Mateen Ulhaq
60

Contraer dos bucles numéricos en uno

Digamos que estás iterando sobre las celdas de una m*ncuadrícula. En lugar de dos forbucles anidados , uno para la fila y una de las columnas, generalmente es más corto usar un solo bucle para iterar sobre las m*nceldas de la cuadrícula. Puede extraer la fila y la columna de la celda dentro del bucle.

Código original:

for i in range(m):
 for j in range(n):
  do_stuff(i,j)

Código de golf:

for k in range(m*n):
  do_stuff(k/n,k%n)

En efecto, estás iterando sobre el producto cartesiano de los dos rangos, codificando el par (i,j)como x=i*n+j. Ha guardado una rangellamada 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 refiere iy jmuchas veces, puede ser más rápido asignar sus valores i=k/n, j=k%ndentro del ciclo.

xnor
fuente
55
Esto es asombroso ¡Nunca me había dado cuenta de que esto era posible!
theonlygusti
Vi esto en los consejos para JavaScript. Es un truco bastante útil en la mayoría de los idiomas.
Cyoce
77
Como referencia, para extender esto a 3 bucles:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007
3
Para nbucles: repl.it/EHwa
mbomb007
En algunos casos, itertools.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'
Aaron3468
54

A menos que el siguiente token comience con eo E. Puede eliminar el espacio después de un número.

Por ejemplo:

if i==4 and j==4:
    pass

Se convierte en:

if i==4and j==4:
    pass

Usar esto en declaraciones complicadas de una línea puede ahorrar bastantes caracteres.

EDITAR: como señaló @marcog, 4or afuncionará, pero no a or4ya que esto se confunde con un nombre de variable.

JPvdMerwe
fuente
37
if(i,j)==(4,4):es aún más corto y en este caso especialif i==j==4:
gnibbler
3
Relacionado: 4or afunciona, pero noa or4
marcog
17
0ortampoco funciona ( 0oes un prefijo para números octales).
Nabb
55
@Nabb No es que importe de todos modos, ya 0 or xque siempre va a volver x. También podría cortar el 0 or.
Aprıʇǝɥʇuʎs
55
0orSin embargo, está bien como parte de un número más largo. 10 or xes equivalente a 10or x.
trichoplax
54

Por entero n, puedes escribir

  • n+1 como -~n
  • n-1 como ~-n

porque 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:

while n-1:  #Same as while n!=1 
while~-n:

c/(n-1)
c/~-n

or f(n)+1
or-~f(n) 

(n-1)/10+(n-1)%10
~-n/10+~-n%10

Los operadores ~y unario -son más altas que prevalecen *, /, %, a diferencia binaria +.

xnor
fuente
11
Una variante de este truco me encontré hoy: -~-xahorra uno contra bytes (1-x).
Lynn
44
Otra aplicación útil es que a+b+1se puede escribir de manera más concisa como a-~b.
Strigoides
Y n-i-1es justo n+~i.
Ruohola
51

Una buena manera de convertir un iterable a la lista en Python 3 :

imagina que tienes algunos iterables, como

i = (1,2,3,4)
i = range(4)
i = (x**2 for x in range(5))

Pero necesitas una lista:

x=list(i)  #the default way
*x,=i      #using starred assignment -> 4 char fewer

Es muy útil hacer una lista de caracteres de una cadena

s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
JBernardo
fuente
1
escribiendo *s,='abcde'y luego sbloquea mi python3 interactivo con un segfault :(
daniero
@daniero Wow. ¿Solo en la consola interactiva? Suena muy raro Probarlo en una consola limpia o informar del fallo
JBernardo
1
Mi Python 3.5 funciona bien.
NoOneIsHere
para i = (x ** 2 para x en el rango (5)) Me devuelve este código <objeto generador <genexpr> en 0x03321690>
george
77
Y si estás haciendo esto en una expresión, puedes hacerlo [*'abcde'].
Esolanging Fruit
46

En lugar de range(x), puede usar el *operador en una lista de cualquier cosa, si realmente no necesita usar el valor de i:

for i in[1]*8:pass

Opuesto a

for i in range(8):pass

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:

r=1,
for i in r*8:pass
for i in r*1000:pass

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.

Chaqueta de sport
fuente
@proudhaskeller Creo que el punto de la línea que eliminó fue que "Además de los ahorros obvios de caracteres que obtiene porque [1]*8es más corto que range(8), también puede ahorrar un espacio porque for i in[...es legal mientras for i in range...que no lo es".
undergroundmonorail
oh, cierto, no entendí eso. arreglado ahora
orgulloso Haskeller
77
exec"pass;"*8Es significativamente más corto.
DJMcMayhem
1
si r=1, r*8es 8, y no puede iterar a través de un número. Supongo que quisiste decirr=[1]
Artemis Fowl
1
@ArtemisFowl, no, está bien como está, la coma después del 1 crea una tupla que es iterable.
Sasha
43

Puedes usar la vieja carita feliz alienígena para invertir las secuencias:

[1, 2, 3, 4][::-1] # => [4, 3, 2, 1]
Strigoides
fuente
38

Desempaquetado iterable extendido ("Asignación destacada", solo Python 3)

La mejor manera de explicar esto es a través de un ejemplo:

>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4

Ya hemos visto un uso para esto: convertir un iterable en una lista en Python 3 :

a=list(range(10))
*a,=range(10)

Aquí hay algunos usos más.

Obtener el último elemento de una lista

a=L[-1]
*_,a=L

En algunas situaciones, esto también se puede usar para obtener el primer elemento para guardar en los padres:

a=(L+[1])[0]
a,*_=L+[1]

Asignación de una lista vacía y otras variables.

a=1;b=2;c=[]
a,b,*c=1,2

Eliminar el primer o el último elemento de una lista no vacía

_,*L=L
*L,_=L

Estos son más cortos que las alternativas L=L[1:]y L.pop(). El resultado también se puede guardar en una lista diferente.

Consejos cortesía de @grc

Sp3000
fuente
¡Guauu! He escrito a=1;L=[]muchas veces. Es sorprendente que puedas guardar caracteres en algo tan sencillo como esto.
xnor
@xnor Eso es gracias a grc. Con solo otro elemento no es tan bueno ( a,*L=1,), pero aún ahorra un carácter :)
Sp3000
no olvides que también puedes obtener el primer y el último elemento de una lista cona,*_,b=L
Cyoce
36

establecer 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 lo e in Sque guarda un carácter.

gnibbler
fuente
44
Y esto también salva al personaje en ifs ya que no hay espacios ( if{e}&S:)
Artyer
1
Tenga en cuenta que puede reemplazar not inpor {e}-Sese truco
Black Owl Kai el
35

Durante siglos me molestó que no pudiera pensar en una forma corta de obtener el alfabeto completo. Si usa lo rangesuficiente que R=rangevale la pena tener en su programa, entonces

[chr(i+97)for i in R(26)]

es más corto que el ingenuo

'abcdefghijklmnopqrstuvwxyz'

, 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

map(chr,range(97,123))

Si el caso no importa, puedes quitar otro personaje usando mayúsculas:

map(chr,range(65,91))

Uso mapdemasiado, no sé cómo esto nunca se me ocurrió.

metro subterráneo
fuente
44
Podría usar esto en la codificación real, me siento tan estúpido al codificar estas cosas: ')
ToonAlfrink
37
En la codificación real, use string.lowercase: para eso está.
Kevin S
1
si necesita ambos casos, la forma más corta que conozco es filter (str.isalpha, map (chr, range (256))). Es apenas más corto que s = map (chr, range (256)); s + = map (str.lower, s)
quintopia
@quintopia: ¿Por qué 256 en lugar de 122 ( ord('z'))? Además de ser de la misma longitud ... Además, si necesita alfanuméricos, reemplácelos str.isalphaen la versión de @ quintopia con str.isalnum. (Pero si solo necesita un caso, la cadena completa de 36 caracteres no es más larga que filter(str.isalnum,map(chr,range(90)))).
Tim Pederick
2
Si va a ser injusto y usar el rango como R, mi versión es más corta que la original: '%c'*26%tuple(R(97,123))(solo 24 caracteres) si la deletrea rangees tan larga como el alfabeto - la versión en mayúscula es más corta
JBernardo
32

Aunque python no tiene declaraciones de cambio, puede emularlas con diccionarios. Por ejemplo, si desea un interruptor como este:

switch (a):
    case 1:
        runThisCode()
        break
    case 2:
        runThisOtherCode()
        break
    case 3:
        runThisOtherOtherCode()
        break

Podría usar ifdeclaraciones, o podría usar esto:

exec{1:"runThisCode()",2:"runThisOtherCode()",3:"runThisOtherOtherCode()"}[a]

o esto:

{1:runThisCode,2:runThisOtherCode,3:runThisOtherOtherCode}[a]()

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:

exec{1:"runThisCode()"}.get(a,"defaultCode()")

(o esto:)

­­{1:runThisCode}.get(a,defaultCode)()

Otra ventaja de esto es que si tiene redundancias, puede agregarlas después del final del diccionario:

exec{'key1':'code','key2':'code'}[key]+';codeThatWillAlwaysExecute'

Y si solo desea utilizar un interruptor para devolver un valor:

def getValue(key):
    if key=='blah':return 1
    if key=='foo':return 2
    if key=='bar':return 3
    return 4

Podrías hacer esto:

getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)
Justin
fuente
2
Esto es algo que consideraría utilizar en la naturaleza. ¡Echo de menos mis declaraciones de cambio! +1
HalosGhost
1
Aunque en lugar de usar un diccionario con teclas numeradas en el primer ejemplo, solo debe usar una lista
Cyoce
1
Si tiene cadenas como teclas, usar en 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> = 3
Black Owl Kai
31

Cuando tiene dos valores booleanos, ay b, si se quiere averiguar si ambos ay bson verdaderas, utilizar *en lugar de and:

if a and b: #7 chars

vs

if a*b: #3 chars

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.

Justin
fuente
99
O puede utilizar &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs
3
utilizar +para orsi se puede garantizara != -b
undergroundmonorail
2
|Funciona en todas las situaciones.
CalculatorFeline
1
*en lugar de and/ &&guarda algunos bytes en muchos idiomas.
wastl
26

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 cero ay 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 como 1.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

'-'in`l`

que comprueba si hay un signo negativo en el representante de la cadena. Este más corto que cualquiera de

any(x<0for x in l)
min(l+[0])<0   

Por el segundo, min(l)<0fallaría en la lista vacía, por lo que debe cubrirse.

xnor
fuente
La segmentación de cadenas de un solo dígito también es efectiva en Python 3, aunque menos: str(l)[2::5]es 12 bytes, frente a 19 para ''.join(map(str,l)). Una situación real en la que esto surgió (donde lhabía una declaración de generador, no una lista) me salvó solo un byte ... ¡que todavía vale la pena!
Tim Pederick
25

Se puede hacer una función de una línea con lambda:

def c(a):
  if a < 3: return a+10
  else: return a-5

se puede convertir a (tenga en cuenta el espacio faltante 3andy 10or)

c=lambda a:a<3and a+10or a-5
Alexandru
fuente
21
o c=lambda a:a+[-5,10][a<3]. el y / o el truco es más útil cuando depende del comportamiento del
circuito corto
3
En su función, else: puede descartarse ya que returndetiene la ejecución de la función, por lo que todo lo que sigue solo se ejecuta si la ifcondición falla, es decir, si la elsecondición es verdadera. Por elselo tanto, se puede omitir con seguridad. (Explicado en detalles para los neófitos)
JeromeJ
c (-10) devuelve -15 mientras que debería devolver 0
Anvit
oc=lambda a:a-5+15*(a<3)
JayXon
25

los bucles de hasta 4 elementos pueden ser mejores para suministrar una tupla en lugar de usar el rango

for x in 0,1,2:

vs

for x in range(3):
gnibbler
fuente
24

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 usar math.ceil(3/2)para 15 o el más corto -(-3//2)para 8 bytes.

math.floor(n)   : 13 bytes+12 for import
n//1            : 4  bytes

math.ceil(n)    : 12 bytes+12 for import
-(-n//1)        : 8  bytes
Juan Cortés
fuente
55
Esto me ahorró cerca de 20 bytes, ¡gracias!
Morgan Thrapp
1
a veces puede salirse con la suya en n//1+1lugar de ceil pero significa ceil (n) = n + 1 pero debería funcionar para todos los valores no enteros
fejfo
round(x)es (x+.5)//1, +1 byte pero este último comienza con a (, y si xes una suma que consiste en una constante, puede ser útil.
user202729
23

Usar en +=lugar de appendyextend

A.append(B)  

se puede acortar a:

A+=B,

B,aquí crea una tupla de un elemento que se puede usar para extender Aal igual que [B]en A+=[B].


A.extend(B)

se puede acortar a:

A+=B
Coding man
fuente
55
En muchos (pero no en todos) los casos, return 0o return 1es equivalente a return Falseo return True.
undergroundmonorail
55
(1) solo funciona si ya sabe que el número es negativo, en cuyo caso puede guardar otros 2 caracteres simplemente usando un signo menos. -xen lugar de x*-1. --8.32en lugar de -8.32*-1. O simplemente 8.32...
trichoplax
Citando el OP: publique un consejo por respuesta.
nyuszika7h
Tenga en cuenta que en A+=B Bes a tuple.
Erik the Outgolfer
23

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 booleano bpara la expresión ternaria y if b else x. Las variables x, yy btambién pueden ser expresiones, aunque tenga en cuenta que ambas xy yse evalúan incluso cuando no se seleccionan.

Aquí hay algunas optimizaciones potenciales cuando xy yson 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(o y-z*b), donde z = yx.

También puede cambiar xy ysi puede reescribir bpara ser su negación.

xnor
fuente
22

Use ~ para indexar desde el final de una lista

Si Les una lista, use L[~i]para obtener el i'th elemento desde atrás.

Este es el i'th elemento del reverso de L. El complemento de bits ~ies igual -i-1y, por lo tanto, corrige el error off-by-one L[-i].

xnor
fuente
21

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:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

¡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:

L=[*T]
*L,=T

Una sintaxis similar funciona para las tuplas:

T=*L,

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:

[1]+T+[2]
[1,*T,2]

(1,)+T+(2,)
(1,*T,2)

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í:

>>> T = (1, 2, 3)
>>> L = [4, 5, 6]
>>> print(*T,*L)
1 2 3 4 5 6

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:

d[0]=1;d[1]=3;d[2]=5
d={**d,0:1,1:3,2:5}

Esto básicamente niega cualquier necesidad de dict.update.

Sp3000
fuente
66
Esto se ve peor que Perl, pero funciona ...
Mega Man
20

Cambiar import *aimport*


Si no has escuchado, import*guarda caracteres!

from math import*

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!

Timtech
fuente
19
>>> for i in range(x):s+=input()

si el valor de i es inútil:

>>> for i in[0]*x:s+=input()

o

>>> exec's+=input();'*x
gmunkhbaatarmn
fuente
8
Puede hacer el segundo ejemplo 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();'*x
Justin Peel
la segunda línea no debería ser:for i in[0]*x:s+=input()
micsthepick
Dupe (más reciente pero con más votos a favor)
user202729