Conseils pour jouer au golf en python

248

Quels conseils généraux avez-vous pour jouer au golf en Python? Je cherche des idées qui puissent être appliquées aux problèmes de code-golf et qui soient aussi au moins quelque peu spécifiques à Python (par exemple, "supprimer les commentaires" n'est pas une réponse).

Merci de poster un pourboire par réponse.

marcog
la source
27
Oh, je peux voir toute une série de questions comme celle-ci arriver pour chaque langue ...
R. Martinho Fernandes Le
4
@Marthinho je suis d'accord. Vient de commencer un équivalent C ++ . Je ne pense cependant pas que ce soit une mauvaise chose, tant que nous ne verrons pas les mêmes réponses réaffichées dans bon nombre de ces types de questions.
Marcog
50
J'adore la question, mais je dois continuer à me dire que "c'est seulement pour le plaisir, PAS pour le code de production"
Greg Guida
2
Cette question ne devrait-elle pas être un post de wiki de communauté?
dorukayhan
3
@dorukayhan Nope; c'est une question valide sur les astuces code-golf , demandant des astuces pour raccourcir le code Python à des fins de CG'ing. De telles questions sont parfaitement valables pour le site, et aucune de ces balises ne dit explicitement que la question doit être abordée, contrairement à SO, qui nécessitait que les défis de CG soient traités. Aussi, écrire une bonne réponse, et trouver de tels conseils mérite toujours quelque chose, qui est enlevé si la question est community wiki (rep).
Erik the Outgolfer

Réponses:

152

Utilisez a=b=c=0au lieu de a,b,c=0,0,0.

Utilisez a,b,c='123'au lieu de a,b,c='1','2','3'.

marcog
la source
2
c'est bon conseil en général :)
28
Notez que cela ne fonctionnera pas nécessairement pour définir des objets mutables que vous modifierez sur place. a = b = [1] est en fait différent de a = [1]; b = [1]
isaacg le
6
La chose amusante à propos du premier conseil est que cela fonctionne également en Java.
Justin
1
@Justin Oui, mais uniquement avec des types primitifs
HyperNeutrino
11
Mais n'utilisez JAMAIS a = b = c = [] ni aucune instanciation d'objet, car toutes les variables pointeront vers la même instance. Ce n'est probablement pas ce que vous voulez.
PhE
146

Les conditions peuvent être longues. Dans certains cas, vous pouvez remplacer un simple conditionnel par (a,b)[condition]. Si conditionest vrai, alors best retourné.

Comparer

if a<b:return a
else:return b

Pour ça

return(b,a)[a<b]
marcog
la source
37
Ce ne sont pas exactement les mêmes. Le premier évalue uniquement l'expression renvoyée, tandis que le second évalue toujours les deux. Ceux-ci font court-circuit: a if a<b else beta<b and a or b
marinus
3
(lambda(): b, lambda(): a)[a < b]()faites votre propre court-circuit avec lambdas
Ming-Tang
3
@marinus, ils ne sont pas égaux: il suffit de considérer P and A or Bpour tout A qui donne bool(A)=False. Mais (P and [A] or [B])[0]fera le travail. Voir diveintopython.net/power_of_introspection/and_or.html pour référence.
kgadek
6
Les lambda sont bien plus longs qu'une expression conditionnelle.
user2357112
18
@ user2357112 Mais ils vous rendent beaucoup plus cool lorsque vous les utilisez. :]
Chase Ries
117

Une bonne chose que j'ai faite une fois est:

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

au lieu de:

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

Les opérateurs de comparaison de Python basculent.


En utilisant tout ce qui est comparable dans Python 2, vous pouvez également éviter l' andopérateur de cette façon. Par exemple, si a, b, cet dsont des nombres entiers,

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

peut être raccourci d'un caractère à:

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

Cela utilise que chaque liste est plus grande que n'importe quel entier.

Si cet dsont des listes, cela devient encore meilleur:

if a<b<c>d:foo()
Juan
la source
22
Bien sûr, si cela était réellement joué au golf, ce serait3>a>1<b<5
Rafe Kettler
4
J'adore la symétrie. Cela me rappelle le vieux tour de Perl pour trouver le minimum de $ a et $ b: [$a => $b]->[$b <= $a]:)
Simon Whitaker
Notez que le deuxième exemple (pas de listes) peut également être fait avecif(a<b)+(c>d):foo()
WorldSEnder
6
Le + devrait être un *. An orserait+
WorldSEnder
1
foo()if 3>a>1<b<5
Erik l'Outgolfer
103

Si vous utilisez une fonction intégrée à plusieurs reprises, il pourrait être plus efficace de lui attribuer un nouveau nom si vous utilisez des arguments différents:

r=range
for x in r(10):
 for y in r(100):print x,y
marcog
la source
6
N'a pas réellement sauvegardé les octets, cependant.
user2357112
4
r = plage et les deux autres r sont 9 caractères; utiliser deux fois la plage est de 10 caractères. Ce n'est pas une économie énorme, mais il suffirait d'une utilisation supplémentaire de la plage pour réaliser une économie significative.
Frank
13
@Frank La nouvelle ligne supplémentaire est un autre personnage.
L3viathan
2
En effet, deux répétitions sont trop peu pour économiser sur un nom de fonction de longueur cinq. Vous avez besoin de: longueur 2: 6 reps, longueur 3: 4 reps, longueur 4 ou 5: 3 reps, longueur> = 6: 2 reps. AKA (longueur-1) * (reps-1)> 4.
Ørjan Johansen
Notez que ceci est applicable à toutes les langues avec des fonctions de première classe.
bfontaine le
94

Parfois, votre code Python nécessite 2 niveaux d’indentation. La chose évidente à faire est d'utiliser un et deux espaces pour chaque niveau d'indentation.

Cependant, Python 2 considère que les caractères de tabulation et d'espace sont des niveaux d'indentation différents.

Cela signifie que le premier niveau d'indentation peut être d'un espace et le second peut être un caractère de tabulation.

Par exemple:

if 1:
 if 1:
\tpass

\test le caractère de tabulation.

JPvdMerwe
la source
1
Cool, je n'ai jamais pensé à celui-ci!
Jules Olléon
97
Cela échoue dans python3: vous ne pouvez plus mélanger les espaces et les onglets (une mauvaise chose pour codegolf, mais une bonne chose dans tous les autres cas).
Bakuriu
1
En python 3.4, cela semble bien fonctionner.
Trichoplax
3
@trichoplax , en python 3.4.3 Je reçoisTabError: inconsistent use of tabs and spaces in indentation.
ceilingcat
Pour référence, un onglet vaut 8 espaces.
Erik l'Outgolfer
87

Utilisez la substitution de chaîne et execles mots-clés longs lambdasont souvent répétés dans votre code.

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 chaîne cible est très souvent 'lambda 'longue de 7 octets. Supposons que votre extrait de code contienne des noccurrences de 'lambda 'et qu'il sdure longtemps. Ensuite:

  • L' plainoption est soctets longs.
  • L' replaceoption est s - 6n + 29octets longs.
  • L' %option est s - 5n + 22 + len(str(n))octets longs.

À partir d'un tracé d' octets enregistrésplain pour ces trois options, nous pouvons voir que:

  • Pour n <5 lambdas, il est préférable de ne rien faire d’extraordinaire.
  • Pour n = 5 , l'écriture exec"..."%(('lambda ',)*5)enregistre 2 octets et constitue votre meilleure option.
  • Pour n> 5 , l'écriture exec"...".replace('`','lambda ')est votre meilleure option.

Pour les autres cas, vous pouvez indexer le tableau ci-dessous:

          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)

Par exemple, si la chaîne lambda x,y:(longueur 11) apparaît 3 fois dans votre code, vous feriez mieux d'écrire exec"..."%(('lambda x,y:',)*3).

Ming-Tang
la source
4
cela devrait obtenir plus de votes, c'est un conseil très utile.
bigblind
7
c'est extrêmement rare que cela fonctionne. le coût de replaceest énorme.
Boothby
4
Quand cela fonctionne, cependant, cela aide beaucoup.
undergroundmonorail
Intéressant, jamais même pensé à cela!
Claudiu
J'ai ajouté un nouvel opérateur pour lambda dans ma langue basé sur python: =>c'est juste la chaîne = lambda . Par exemple, f=>:0serait f = lambda: 0.
NoOneIsHere
78

Utilisez le découpage étendu pour sélectionner une chaîne parmi plusieurs

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

contre

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

Dans ce cas booléen à deux cordes, on peut aussi écrire

b*"string"or"other_string"

pour

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

Contrairement à l'entrelacement, cela fonctionne pour les chaînes de n'importe quelle longueur, mais peut avoir des problèmes de priorité d'opérateur s'il bs'agit plutôt d'une expression.

gnibbler
la source
Notez que le premier exemple a exactement la même longueur quefor x in ("foo","bar","baz"): print x
Mateen Ulhaq le
1
@MateenUlhaq, Ce n'est qu'un exemple de la manière dont les différentes valeurs de xsont rendues. La partie jouée au golf est le "fbboaaorz"[x::3]vs. ["foo","bar","baz"][x]Comment la xvaleur est dérivée serait une autre partie de votre solution de golf.
Gnibbler
72

Utilisez `n`pour convertir un entier en chaîne au lieu de str(n):

>>> n=123
>>> `n`
'123'
marcog
la source
38
Bien, mais ne fonctionne pas avec Python3.
Alexandru
2
Attention: fonctionne vraiment pour les entiers, mais pas pour les chaînes, par exemple.
Nakilon
41
btw. `` est l'abréviation de repr
Alexandru le
9
Les entiers inférieurs à -2 ** 31 ou supérieurs à 2 ** 31-1 (Longs) sont marqués d'un "L" à la fin.
hallvabo
6
Cela peut également être utilisé pour imprimer des flotteurs à la précision
parfaite
69

Stocker les tables de consultation sous forme de nombres magiques

Supposons que vous vouliez coder en dur une table de recherche booléenne, par exemple, lequel des douze premiers nombres anglais contient 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

Ensuite, vous pouvez implémenter cette table de recherche de manière concise en tant que:

3714>>i&1

avec le résultat 0ou 1étant égal à Falseà True.

L'idée est que le nombre magique stocke la table sous la forme d'une chaîne de bits bin(3714)= 0b111010000010, avec le ntroisième chiffre (à partir de la fin) correspondant à la troisième nentrée de la table. On accède à la ne entrée en décalant un peu le nombre d’ nespaces à droite et en prenant le dernier chiffre par&1 .

Cette méthode de stockage est très efficace. Comparer aux alternatives

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

Vous pouvez avoir vos entrées multibits de magasin de table de recherche qui peuvent être extraites comme

 340954054>>4*n&15

extraire le bloc de quatre bits correspondant.

Xnor
la source
Pourrions-nous avoir un exemple de résultat pour le bloc de quatre bits? Avez-vous utilisé une règle pour le bloc n-bit?
JeromeJ
8
Hex peut parfois être encore plus petit.
Joonazan
4
Ceci est utile pour beaucoup de langues.
Cyoce
1
@Joonazan Hex est plus petit pour les nombres supérieurs à 999 999 .
Mateen Ulhaq
60

Réduire deux boucles numériques en une

Supposons que vous parcouriez les cellules d'une m*ngrille. Au lieu de deux forboucles imbriquées , une pour la ligne et une des colonnes, il est généralement plus court d'utiliser une seule boucle pour parcourir les m*ncellules de la grille. Vous pouvez extraire la ligne et la colonne de la cellule à l'intérieur de la boucle.

Code d'origine:

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

Code de golf:

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

En effet, vous itérer sur le produit cartésien des deux plages, codant pour la paire (i,j)comme x=i*n+j. Vous avez économisé un rangeappel coûteux et un niveau d'indentation dans la boucle. L'ordre des itérations est inchangé.

Utilisez //plutôt que /dans Python 3. Si vous vous référez ài et jplusieurs fois, il peut être plus rapide d’affecter leurs valeurs i=k/n, j=k%nà l’intérieur de la boucle.

Xnor
la source
5
C'est génial. Je n'avais jamais réalisé que c'était possible!
theonlygusti
J'ai vu cela dans les astuces pour JavaScript. C'est un truc très utile dans la plupart des langues.
Cyoce
7
Pour référence, pour étendre cela à 3 boucles:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007
3
Pour les nboucles: repl.it/EHwa
mbomb007
Dans certains cas, cela itertools.productpeut être beaucoup plus concis que des boucles imbriquées, en particulier lors de la génération de produits cartésiens. a1, a2, b1, b2sont des exemples du produit cartésien de 'ab'et'12'
Aaron3468
54

Sauf si le jeton suivant commence par e ou E. Vous pouvez supprimer l'espace après un numéro.

Par exemple:

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

Devient:

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

L'utilisation de ceci dans des instructions compliquées d'une ligne peut sauver un nombre considérable de caractères.

EDIT: comme @marcog l’a souligné, 4or acela fonctionnera, mais pas a or4parce que cela est confondu avec un nom de variable.

JPvdMerwe
la source
37
if(i,j)==(4,4):est encore plus court et dans ce cas particulierif i==j==4:
gnibbler
3
Connexes: 4or afonctionne, mais pasa or4
Marcog
17
0orégalement ne fonctionne pas ( 0oest un préfixe pour les nombres octaux).
Nabb
5
@Nabb Pas que ça compte quand même, car 0 or xon va toujours y retourner x. Pourriez aussi bien couper le 0 or.
Jeudi
5
0orest bien dans le cadre d'un nombre plus long cependant. 10 or xest équivalent à 10or x.
Trichoplax
54

Pour un entier n, vous pouvez écrire

  • n+1 comme -~n
  • n-1 comme ~-n

parce que le bit bascule ~xest égal -1-x. Ceci utilise le même nombre de caractères, mais peut indirectement couper des espaces ou des parenthèses pour la priorité des opérateurs.

Comparer:

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

Les opérateurs ~et unaire -sont plus élevés que la priorité *, /, %, à la différence binaire +.

Xnor
la source
11
Une variante de cette astuce que j'ai rencontrée aujourd'hui: -~-xenregistre un octet contre (1-x).
Lynn
4
Une autre application utile est que vous a+b+1pouvez écrire de manière plus concise a-~b.
Strigoides
Et n-i-1est juste n+~i.
Ruohola
51

Un bon moyen de convertir une liste itérable en une liste sur Python 3 :

imaginez que vous en ayez un, comme

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

Mais vous avez besoin d'une liste:

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

C'est très utile de faire une liste de caractères d'une chaîne

s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
JBernardo
la source
1
taper *s,='abcde'puis sécraser mon python3 interactif avec un segfault :(
daniero
@daniero Wow. Seulement sur la console interactive? Cela semble très bizarre. Essayez-le sur une console
vierge
1
Mon Python 3.5 fonctionne bien.
NoOneIsHere
pour i = (x ** 2 pour x dans la plage (5)) je reçois ce code renvoyé <objet générateur <genexpr> à 0x03321690>
george
7
Et si vous faites cela dans une expression, vous pouvez le faire [*'abcde'].
Esolanging Fruit
46

Au lieu de range(x), vous pouvez utiliser l' *opérateur sur une liste de tout, si vous n'avez pas réellement besoin d'utiliser la valeur de i:

for i in[1]*8:pass

par opposition à

for i in range(8):pass

Si vous devez le faire plus de deux fois, vous pouvez affecter n'importe quelle variable à une variable et multiplier cette variable par la plage souhaitée:

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

Note : c'est souvent plus long que exec"pass;"*8ça, donc cette astuce ne devrait être utilisée que quand ce n'est pas une option.

blazer
la source
@proudhaskeller Je pense que le point de la ligne que vous avez supprimé était "En plus des économies de personnage évidentes que vous obtenez parce que [1]*8est plus court que range(8), vous obtenez également de gagner un espace parce que for i in[...c'est légal tant que ça for i in range...ne l'est pas".
undergroundmonorail
oh, d'accord, je n'ai pas compris ça. réparé maintenant
fier haskeller
7
exec"pass;"*8est nettement plus courte.
DJMcMayhem
1
si r=1, r*8est 8, et vous ne pouvez pas parcourir un nombre. Je suppose que tu voulais direr=[1]
Artemis Fowl
1
@ArtemisFowl, non, ça va comme ça, la virgule après le 1 crée un tuple qui est itérable.
Sasha
43

Vous pouvez utiliser le bon vieux smiley extraterrestre pour inverser les séquences:

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

Déballage itératif étendu ("Affectation étoilée", Python 3 uniquement)

La meilleure façon de l'expliquer consiste à utiliser un exemple:

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

Nous avons déjà vu une utilisation pour cela: transformer une liste itérable en une liste dans Python 3 :

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

Voici quelques utilisations supplémentaires.

Obtenir le dernier élément d'une liste

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

Dans certaines situations, cela peut également être utilisé pour obtenir le premier élément à économiser sur les parenthèses:

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

Assigner une liste vide et d'autres variables

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

Supprimer le premier ou le dernier élément d'une liste non vide

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

Celles-ci sont plus courtes que les alternatives L=L[1:]et L.pop(). Le résultat peut également être enregistré dans une liste différente.

Astuces courtoisie de @grc

Sp3000
la source
Hou la la! J'ai écrit a=1;L=[]tellement de fois. Il est étonnant que vous puissiez enregistrer des caractères sur quelque chose d'aussi simple que cela.
xnor
@xnor C'est grâce à grc. Avec un seul autre élément, ce n'est pas aussi bon ( a,*L=1,), mais cela sauve toujours un caractère :)
Sp3000
n'oubliez pas que vous pouvez également obtenir le premier et le dernier élément d'une liste aveca,*_,b=L
Cyoce 3/03/16
36

définir des littéraux en Python2.7

Vous pouvez écrire des ensembles comme celui-ci. S={1,2,3}Cela signifie également que vous pouvez vérifier l’appartenance à la {e}&Splace de celle e in Squi enregistre un caractère.

gnibbler
la source
4
Et cela sauve aussi le caractère en ifs car il n'y a pas d'espaces ( if{e}&S:)
Artyer
1
Notez que vous pouvez remplacer not inpar {e}-Sce tour
Black Owl Kai
35

Pendant des siècles, cela me dérangeait de ne pas pouvoir trouver un moyen rapide d’obtenir l’alphabet complet. Si vous en utilisez rangesuffisamment R=rangedans votre programme, alors

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

est plus court que le naïf

'abcdefghijklmnopqrstuvwxyz'

, mais sinon c'est plus long d'un seul personnage. Cela me hantait que l'intelligent qui nécessitait une connaissance des valeurs ascii finissait par être plus bavard que simplement taper toutes les lettres.

Jusqu'à ce que je voie cette réponse pour l'alphabet de ma fille . Je ne peux pas suivre suffisamment l'historique de montage pour savoir si ce génie était l'oeuvre de l'OP ou s'il s'agissait d'une suggestion de la part d'un commentateur, mais c'est (je crois) le moyen le plus rapide de créer un éditable des 26 lettres. dans l'alphabet romain.

map(chr,range(97,123))

Si l'affaire n'a pas d'importance, vous pouvez supprimer un autre personnage en utilisant des majuscules:

map(chr,range(65,91))

J'utilise mapbeaucoup trop, je ne sais pas comment cela ne m'est jamais arrivé.

métro monorail
la source
4
Je pourrais me sentir si bête de coder ces choses en dur: ')
ToonAlfrink
37
En codage réel, utilisez string.lowercase- c’est pour cela qu’il est.
Kevin S
1
si vous avez besoin des deux cas, le moyen le plus rapide que je connaisse est le filtre (str.isalpha, map (chr, range (256))). C'est à peine plus court que s = map (chr, range (256)); s + = map (str.lower, s)
quintopia
@quintopia: Pourquoi 256 au lieu de 122 ( ord('z'))? En plus de la même longueur ... De plus, si vous avez besoin de caractères alphanumériques, remplacez-le str.isalphadans la version de @ quintopia par str.isalnum. (Mais si vous n'avez besoin que d'une casse, la chaîne entière de 36 caractères ne dépasse pas filter(str.isalnum,map(chr,range(90))).)
Tim Pederick
2
Si vous voulez être injuste et utiliser range as R, ma version est plus courte que la version originale: '%c'*26%tuple(R(97,123))(seulement 24 caractères) si vous l'orthographiez, rangeelle est aussi longue que l'alphabet - la version majuscule est plus courte
JBernardo
32

Bien que python ne possède pas d'instructions switch, vous pouvez les émuler avec des dictionnaires. Par exemple, si vous vouliez un commutateur comme celui-ci:

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

Vous pouvez utiliser des ifdéclarations, ou ceci:

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

ou ca:

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

ce qui est mieux si tous les chemins de code sont des fonctions avec les mêmes paramètres.

Pour prendre en charge une valeur par défaut, procédez comme suit:

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

(ou ca:)

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

Un autre avantage est que si vous avez des redondances, vous pouvez simplement les ajouter après la fin du dictionnaire:

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

Et si vous vouliez simplement utiliser un commutateur pour renvoyer une valeur:

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

Vous pouvez simplement faire ceci:

getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)
Justin
la source
2
C’est quelque chose que j’envisagerais profondément d’utiliser à l’état sauvage. Je manque tellement mes déclarations de commutateur! +1
HalosGhost
1
Bien qu'au lieu d'utiliser un dictionnaire avec des clés numérotées dans le premier exemple, vous devriez simplement utiliser une liste
Cyoce
1
Si vous avez des chaînes comme clés, utilisez dict(s1=v1,s2=v2,...,sn=vn)au lieu de {'s1':v1,'s2':v2,...,'sn':vn}sauvegarder 2 * n-4 octets et vaut mieux si n> = 3
Black Owl Kai
31

Lorsque vous avez deux valeurs booléennes aet b, si vous voulez savoir si les deux aet bsont vraies, utilisez *plutôt and:

if a and b: #7 chars

contre

if a*b: #3 chars

si l'une des valeurs est false, elle sera évaluée comme 0dans cette instruction et une valeur entière n'est vraie que si elle est différente de zéro.

Justin
la source
9
Ou vous pouvez utiliser &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs
3
utilisation + pour orsi vous pouvez garantira != -b
undergroundmonorail
2
| fonctionne dans toutes les situations.
CalculatriceFeline
1
*à la place de and/ &&enregistre quelques octets dans de nombreuses langues.
wastl
26

Exploiter les représentations de chaîne Python 2

Python 2 vous permet de convertir un objet xen représentation de chaîne`x` pour un coût de 2 caractères seulement. Utilisez cette option pour les tâches plus faciles à effectuer sur la chaîne de l'objet que sur l'objet lui-même.

Rejoindre des personnages

Avec une liste de caractères l=['a','b','c'], on peut produire en ''.join(l)tant que `l`[2::5], ce qui enregistre un octet.

La raison est que `l`est "['a', 'b', 'c']"(avec des espaces), on peut donc extraire les lettres avec une tranche de liste, en commençant que le second caractère zéro indexé a, et en prenant chaque cinquième caractère à partir de là. Cela ne fonctionne pas pour joindre des chaînes multi-caractères ou des caractères d'échappement représentés comme '\n'.

Concaténer les chiffres

De même, étant donné une liste de chiffres non vide l=[0,3,5], vous pouvez les concaténer dans une chaîne en '035'tant que `l`[1::3].

Cela évite de faire quelque chose comme map(str,l) . Notez qu'il doit s'agir de chiffres simples et que les flottants ne peuvent pas être 1.0mélangés. Cela échoue également sur la liste vide ].

Vérifier les négatifs

Maintenant, pour une tâche non-chaîne. Supposons que vous ayez une listel de nombres réels et que vous souhaitiez vérifier si elle contient des nombres négatifs, produisant ainsi un booléen.

Tu peux faire

'-'in`l`

qui vérifie la présence d’un signe négatif dans la chaîne rep. Ce plus court que l'un des

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

Pour le second, min(l)<0échouerait sur la liste vide, vous devez donc vous couvrir.

Xnor
la source
La concaténation du découpage de chaîne à un chiffre est également efficace dans Python 3, bien que moins; str(l)[2::5]vaut 12 octets, contre 19 pour ''.join(map(str,l)). Une situation réelle où cela est arrivé (où létait une déclaration de générateur, pas une liste) m'a sauvé juste un octet ... qui en vaut toujours la peine!
Tim Pederick
25

Une fonction d'une ligne peut être réalisée avec lambda:

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

peut être converti en (notez l'espace manquant 3andet 10or)

c=lambda a:a<3and a+10or a-5
Alexandru
la source
21
ou c=lambda a:a+[-5,10][a<3]. l'astuce et / ou l'astuce est plus utile lorsque vous
dépendez du
3
Dans votre fonction, else: peut être supprimé en tant returnqu'arrêt de l'exécution de la fonction. Ainsi, tout ce qui suit n'est exécuté que si la ifcondition a échoué, autrement dit si la elsecondition est vraie. Ainsi, elsepeut être omis en toute sécurité. (Expliqué en détail pour les néophytes)
JeromeJ
c (-10) renvoie -15 alors qu'il devrait renvoyer 0
Anvit
ouc=lambda a:a-5+15*(a<3)
JayXon
25

les boucles allant jusqu’à 4 éléments peuvent être mieux pour fournir un tuple au lieu d’utiliser une plage

for x in 0,1,2:

contre

for x in range(3):
gnibbler
la source
24

Ceil et sol

Si vous souhaitez obtenir le résultat arrondi pour une division, comme vous le feriez //pour le sol, vous pouvez utiliser math.ceil(3/2)15 ou le nombre beaucoup plus court -(-3//2)pour 8 octets.

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
la source
5
Cela m'a sauvé près de 20 octets, merci!
Morgan Thrapp
1
Parfois, vous pouvez vous en tirer au n//1+1lieu de ceil, mais cela signifie que ceil (n) = n + 1, mais cela devrait fonctionner pour toutes les valeurs non entières
fejfo
round(x)est (x+.5)//1, +1 octet mais celui-ci commence par un (, et si xest une somme consistant en une constante, il peut être utile.
user202729
23

Utiliser +=au lieu de appendetextend

A.append(B)  

peut être réduit à:

A+=B,

B,crée ici un tuple à un élément qui peut être utilisé pour s'étendre Acomme [B]dans A+=[B].


A.extend(B)

peut être réduit à:

A+=B
Codeur
la source
5
Dans beaucoup de cas (mais pas tous), return 0ou return 1est équivalent à return Falseou return True.
undergroundmonorail
5
(1) ne fonctionne que si vous savez déjà que le nombre est négatif, auquel cas vous pouvez enregistrer 2 caractères supplémentaires en utilisant simplement un signe moins. -xplutôt que x*-1. --8.32plutôt que -8.32*-1. Ou tout simplement 8.32...
trichoplax
Citation du PO: Merci de poster un pourboire par réponse.
Nyuszika7h
Notez que dans A+=B Best un tuple.
Erik the Outgolfer
23

Choisir l'un des deux nombres en fonction d'une condition

Vous savez déjà utiliser la sélection de liste [x,y][b]avec un booléen bpour l'expression ternaire y if b else x. Les variables x, yet bpeuvent également être des expressions, même si elles sont évaluées xet ysont évaluées même si elles ne sont pas sélectionnées.

Voici quelques optimisations possibles quand xet ysont des nombres.

  • [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(ou y-z*b), où z = yx.

Vous pouvez également basculer xet ysi vous pouvez réécrire bpour être sa négation à la place.

Xnor
la source
22

Utilisez ~ pour indexer à partir du dos d'une liste

Si Lest une liste, utilisez L[~i]pour obtenir le iième élément à l'arrière.

C'est le iième élément de l'inverse de L. Le complément de bit ~iest égal à -i-1, et corrige donc l'erreur de décalage par un L[-i].

Xnor
la source
21

PEP448 - Généralisations de supplémentaires

Avec la sortie de Python 3.5 , la manipulation de listes, de tuples, de décors et de dict est devenue encore plus golfeuse.

Transformer un itérable en un ensemble / une liste

Comparez les paires:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Plus court! Notez cependant que si vous souhaitez simplement convertir quelque chose en liste et l'affecter à une variable, la décompression itérative étendue normale est plus courte:

L=[*T]
*L,=T

Une syntaxe similaire fonctionne pour les tuples:

T=*L,

ce qui ressemble à un décompression itérative prolongée, mais avec l'astérisque et une virgule de l'autre côté.

Rejoindre des listes / tuples

La décompression est légèrement plus courte que la concaténation si vous devez ajouter une liste / un nuplet aux deux côtés:

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

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

Imprimer le contenu de plusieurs listes

Ce n’est pas limité à print, mais c’est bien d’où viendra la plus grande partie du kilométrage parcouru. PEP448 permet maintenant le décompactage multiple, comme suit:

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

Mise à jour de plusieurs éléments du dictionnaire

Cela n'arrivera probablement pas très souvent, mais la syntaxe peut être utilisée pour économiser sur la mise à jour de dictionnaires si vous mettez à jour au moins trois éléments:

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

Cela annule fondamentalement tout besoin de dict.update.

Sp3000
la source
6
Cela semble pire que Perl, mais cela fonctionne ...
Mega Man
20

Changer import *enimport*


Si vous ne l'avez pas entendu, import*sauve des caractères!

from math import*

est seulement 1 caractère plus long que import math as m et vous arrivez à supprimer toutes les instances dem.

Même une utilisation ponctuelle est un économiseur!

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

si la valeur de i est inutile:

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

ou

>>> exec's+=input();'*x
Gmunkhbaatarmn
la source
8
Vous pouvez créer le deuxième exemple for i in[0]*x:s+=input()pour économiser un autre espace. En outre, vous pouvez supprimer l'espace entre l'exec et le premier guillemet à obtenirexec's+=input();'*x
Justin Peel le
La deuxième ligne ne devrait pas être:for i in[0]*x:s+=input()
micsthepick
Dupe (plus récent mais plus invectif)
user202729