Tipps zum Golfen in Python


248

Welche allgemeinen Tipps haben Sie zum Golfen in Python? Ich bin auf der Suche nach Ideen, die sich auf Code-Golf-Probleme anwenden lassen und die zumindest etwas spezifisch für Python sind (z. B. "Kommentare entfernen" ist keine Antwort).

Bitte posten Sie einen Tipp pro Antwort.


27
Oh, ich sehe eine ganze Reihe von Fragen wie diese für jede Sprache ...
R. Martinho Fernandes

4
@Marthinho Ich stimme zu. Habe gerade ein C ++ - Äquivalent gestartet . Ich denke nicht, dass es eine schlechte Sache ist, solange wir nicht die gleichen Antworten sehen, die für viele dieser Fragetypen neu gepostet wurden.
Marcog

50
Ich liebe die Frage, aber ich muss mir immer wieder sagen: "Dies ist nur zum Spaß, nicht zum
Greg Guida

2
Sollte diese Frage nicht ein Community-Wiki-Beitrag sein?
Dorukayhan

3
@ Dorukayhan Nope; Es handelt sich um eine gültige Code-Golf- Tipp- Frage, in der Sie nach Tipps zum Kürzen des Python- Codes für CG'ing-Zwecke gefragt werden. Solche Fragen sind für die Site vollkommen gültig, und keines dieser Tags besagt ausdrücklich, dass die Frage im Gegensatz zu SO im CW-Modus gestellt werden sollte, was erfordert, dass CG-Herausforderungen im CW-Modus gestellt werden. Außerdem verdient es immer etwas, eine gute Antwort zu schreiben und solche Tipps zu finden, die weggenommen werden, wenn es sich bei der Frage um Community-Wiki (rep) handelt.
Erik der Outgolfer

Antworten:


152

Verwenden Sie a=b=c=0anstelle von a,b,c=0,0,0.

Verwenden Sie a,b,c='123'anstelle von a,b,c='1','2','3'.


2
Das ist ein

28
Beachten Sie, dass dies nicht unbedingt zum Definieren von veränderlichen Objekten funktioniert, die Sie direkt ändern. a = b = [1] unterscheidet sich tatsächlich von a = [1]; b = [1]
isaacg

6
Das Lustige am ersten Tipp ist, dass er auch in Java funktioniert.
Justin

1
@ Justin Ja, aber nur mit primitiven Typen
HyperNeutrino

11
Verwenden Sie jedoch NIEMALS a = b = c = [] oder eine Objektinstanz, da alle Variablen auf dieselbe Instanz verweisen. Das ist wahrscheinlich nicht was du willst.
PhE

146

Bedingungen können langwierig sein. In einigen Fällen können Sie eine einfache Bedingung durch ersetzen (a,b)[condition]. Wenn dies conditionzutrifft, bwird zurückgegeben.

Vergleichen Sie

if a<b:return a
else:return b

Dazu

return(b,a)[a<b]

37
Dies sind nicht genau die gleichen. Der erste wertet nur den zurückgegebenen Ausdruck aus, während der zweite immer beide auswertet. Diese machen einen Kurzschluss: a if a<b else bunda<b and a or b
Marinus

3
(lambda(): b, lambda(): a)[a < b]()Machen Sie Ihren eigenen Kurzschluss mit Lambdas
Ming-Tang

3
@marinus, sie sind nicht gleich: man denke nur P and A or Ban ein A, das gibt bool(A)=False. Aber (P and [A] or [B])[0]werde den Job machen. Siehe diveintopython.net/power_of_introspection/and_or.html als Referenz.
kgadek

6
Lambdas sind viel länger als ein bedingter Ausdruck.
user2357112

18
@ user2357112 Aber sie lassen dich so viel cooler aussehen, wenn du sie verwendest. :]
Chase Ries

117

Eine großartige Sache, die ich einmal gemacht habe, ist:

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

Anstatt von:

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

Pythons Vergleichsoperatoren rocken.


Wenn in Python 2 alles vergleichbar ist, können Sie auf anddiese Weise auch den Operator umgehen . Wenn zum Beispiel a, b, cund dganze Zahlen sind,

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

kann um ein Zeichen gekürzt werden, um:

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

Dabei ist jede Liste größer als eine ganze Zahl.

Wenn cund dsind Listen, wird dies noch besser:

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

22
Natürlich, wenn dies tatsächlich Golf wäre, wäre es3>a>1<b<5
Rafe Kettler

4
Lieben Sie die Symmetrie. Erinnert mich an den alten Perl-Golftrick, bei dem ich die Minima $ a und $ b gefunden habe: [$a => $b]->[$b <= $a]:)
Simon Whitaker

Beachten Sie, dass das zweite Beispiel (keine Listen) auch mitif(a<b)+(c>d):foo()
WorldSEnder

6
Das + sollte a sein *. Ein orwürde sein+
WorldSEnder

1
foo()if 3>a>1<b<5
Erik der Outgolfer

103

Wenn Sie eine integrierte Funktion wiederholt verwenden, ist es möglicherweise platzsparender, wenn Sie einen neuen Namen vergeben, wenn Sie andere Argumente verwenden:

r=range
for x in r(10):
 for y in r(100):print x,y

6
Allerdings wurden keine Bytes gespeichert.
user2357112

4
r = range und die anderen beiden r sind 9 Zeichen; Die doppelte Verwendung des Bereichs umfasst 10 Zeichen. In diesem Beispiel ist dies keine große Einsparung, aber es ist nur eine weitere Verwendung des Bereichs erforderlich, um eine signifikante Einsparung zu erzielen.
Frank

13
@Frank Die zusätzliche Newline ist ein weiteres Zeichen.
L3viathan

2
In der Tat sind zwei Wiederholungen zu wenig, um einen Funktionsnamen der Länge fünf zu speichern. Sie benötigen: Länge 2: 6 Wiederholungen, Länge 3: 4 Wiederholungen, Länge 4 oder 5: 3 Wiederholungen, Länge> = 6: 2 Wiederholungen. AKA (Länge-1) * (Wiederholungen-1)> 4.
Ørjan Johansen

Beachten Sie, dass dies für alle Sprachen mit erstklassigen Funktionen gilt.
Bfontaine

94

Manchmal erfordert Ihr Python-Code zwei Einrückungsstufen. Es ist naheliegend, für jede Einrückungsstufe ein und zwei Leerzeichen zu verwenden.

Python 2 betrachtet die Tabulator- und Leerzeichen jedoch als unterschiedliche Einrückungsstufen.

Dies bedeutet, dass die erste Einrückungsstufe ein Leerzeichen und die zweite ein Tabulatorzeichen sein kann.

Zum Beispiel:

if 1:
 if 1:
\tpass

Wo \tist das Tabulatorzeichen?


1
Cool, ich habe nie darüber nachgedacht!
Jules Olléon

97
Dies schlägt in python3 fehl: Sie können keine Leerzeichen und Tabulatoren mehr mischen (eine schlechte Sache für Codegolf, aber eine gute Sache in allen anderen Fällen).
Bakuriu

1
In Python 3.4 scheint dies gut zu funktionieren.
Trichoplax

3
@ Trichoplax , In Python 3.4.3 bekomme ichTabError: inconsistent use of tabs and spaces in indentation.
Ceilingcat

Als Referenz ist ein Tab 8 Leerzeichen wert.
Erik der Outgolfer

87

Verwenden Sie die Zeichenfolgensubstitution und verwenden Sie execlange Schlüsselwörter lambda, die in Ihrem Code häufig vorkommen.

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  (%)

Die Zielzeichenfolge ist sehr häufig 'lambda 'und 7 Byte lang. Angenommen, Ihr Code-Snippet enthält nVorkommen von 'lambda 'und ist sbytelang. Dann:

  • Die plainOption ist sbytelang.
  • Die replaceOption ist s - 6n + 29bytelang.
  • Die %Option ist s - 5n + 22 + len(str(n))bytelang.

Aus einer Darstellung von Bytes, dieplain für diese drei Optionen gespeichert wurden , können wir Folgendes ersehen:

  • Für n <5 Lambdas ist es besser, überhaupt nichts Besonderes zu tun.
  • Bei n = 5 werden beim Schreiben exec"..."%(('lambda ',)*5)2 Bytes gespart, und dies ist die beste Option.
  • Für n> 5 ist das Schreiben exec"...".replace('`','lambda ')die beste Option.

In anderen Fällen können Sie die folgende Tabelle indizieren:

          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)

Wenn die Zeichenfolge lambda x,y:(Länge 11) beispielsweise dreimal in Ihrem Code vorkommt, sollten Sie besser schreiben exec"..."%(('lambda x,y:',)*3).


4
dies sollte mehr Stimmen bekommen, es ist ein sehr nützlicher Tipp.
bigblind

7
Es ist äußerst selten, dass dies funktioniert. Die Kosten von replacesind riesig.
Stand

4
Wenn es funktioniert, hilft es sehr.
Undergroundmonorail

Interessant, noch nie daran gedacht!
Claudiu

Ich habe einen neuen Operator für Lambda in meiner Sprache hinzugefügt, der auf Python basiert: Ist =>nur die Zeichenfolge = lambda . Zum Beispiel f=>:0wäre f = lambda: 0.
NoOneIsHere

78

Verwenden Sie Extended Slicing, um eine Zeichenfolge aus vielen auszuwählen

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

In diesem booleschen 2-String-Fall kann man auch schreiben

b*"string"or"other_string"

zum

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

Im Gegensatz zum Interleaving funktioniert dies für Zeichenfolgen beliebiger Länge, es können jedoch Probleme mit der Operatorpriorität auftreten, wenn bes sich stattdessen um einen Ausdruck handelt.


Beachten Sie, dass das erste Beispiel genau so lang ist wiefor x in ("foo","bar","baz"): print x
Mateen Ulhaq

1
@MateenUlhaq, Das ist nur ein Beispiel dafür, wie die verschiedenen Werte von xgerendert werden. Der Golf-Teil ist der "fbboaaorz"[x::3]vs ["foo","bar","baz"][x]Wie der xWert abgeleitet wird, wäre ein weiterer Teil Ihrer Golflösung .
Gnibbler

72

Verwenden Sie `n`diese Option , um eine Ganzzahl in eine Zeichenfolge zu konvertieren, anstatt Folgendes zu verwenden str(n):

>>> n=123
>>> `n`
'123'

38
Schön, funktioniert aber nicht mit Python3.
Alexandru

2
Achtung: Funktioniert wirklich für ganze Zahlen, aber zum Beispiel nicht für Zeichenketten.
Nakilon

41
btw. `` steht für repr
Alexandru

9
Ganzzahlen, die kleiner als -2 ** 31 oder größer als 2 ** 31-1 (Longs) sind, erhalten am Ende ein 'L'.
Hallvabo

6
Dies kann auch verwendet werden, um Floats mit voller Präzision zu drucken
gnibbler

69

Speichern Sie Nachschlagetabellen als magische Zahlen

Angenommen, Sie möchten eine Boolesche Nachschlagetabelle fest codieren, z. B. welche der ersten zwölf englischen Zahlen eine enthält 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

Dann können Sie diese Nachschlagetabelle kurz und bündig implementieren als:

3714>>i&1

mit dem resultierenden 0oder 1gleich zu Falsesein True.

Die Idee ist, dass die magische Zahl die Tabelle als Bitstring bin(3714)= speichert 0b111010000010, wobei die n-te Ziffer (vom Ende) dem nEintrag in der th-Tabelle entspricht. Wir greifen auf den ndritten Eintrag zu, indem wir die Ziffernfelder nnach rechts verschieben und die letzte Ziffer um nehmen &1.

Diese Speichermethode ist sehr effizient. Vergleichen Sie mit den Alternativen

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

Sie können Ihre Nachschlagetabelle Multibit-Einträge speichern lassen, die wie folgt extrahiert werden können

 340954054>>4*n&15

um den relevanten 4-Bit-Block zu extrahieren.


Könnten wir ein Beispielergebnis für den Vier-Bit-Block haben? Haben Sie eine Regel für den n-Bit-Block verwendet?
JeromeJ

8
Verhexung kann manchmal noch kleiner sein.
Joonazan

4
Dies ist für viele Sprachen nützlich.
Cyoce

1
@Joonazan Hex ist für Zahlen über 999 999 kleiner .
Mateen Ulhaq

60

Reduzieren Sie zwei numerische Schleifen zu einer

Angenommen, Sie iterieren über die Zellen eines m*nGitters. Anstelle von zwei verschachtelten forSchleifen, eine für die Zeile und eine für die Spalte, ist es normalerweise kürzer, eine einzelne Schleife zu verwenden, um über die m*nZellen des Rasters zu iterieren . Sie können die Zeile und Spalte der Zelle in der Schleife extrahieren.

Originalcode:

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

Golf Code:

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

Tatsächlich iterieren Sie über das kartesische Produkt der beiden Bereiche und codieren das Paar (i,j)als x=i*n+j. Sie sparen sich einen teuren rangeAnruf und eine gewisse Einrückung in der Schleife. Die Reihenfolge der Iteration bleibt unverändert.

Verwenden Sie //statt /in Python 3. Wenn Sie beziehen iund jviele Male, kann es schneller sein , ihre Werte zuweisen i=k/n, j=k%ninnerhalb der Schleife.


5
Das ist fantastisch. Ich hätte nie gedacht, dass das möglich ist!
Theonlygusti

Ich habe dies in den Tipps für JavaScript gesehen. Es ist in den meisten Sprachen ein ziemlich nützlicher Trick.
Cyoce

7
Als Referenz, um dies auf 3 Schleifen zu erweitern:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007

3
Für nSchleifen: repl.it/EHwa
mbomb007

In einigen Fällen itertools.productkann dies sehr viel präziser sein als verschachtelte Schleifen, insbesondere beim Generieren kartesischer Produkte. a1, a2, b1, b2sind Beispiele für das kartesische Produkt von 'ab'und'12'
Aaron3468

54

Es sei denn, das folgende Token beginnt mit eoder E. Sie können das Leerzeichen nach einer Zahl entfernen.

Zum Beispiel:

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

Wird:

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

Wenn Sie dies in komplizierten einzeiligen Anweisungen verwenden, können einige Zeichen gespart werden.

BEARBEITEN: wie @marcog hervorhob, 4or awird funktionieren, aber nicht, a or4da dies mit einem Variablennamen verwechselt wird.


37
if(i,j)==(4,4):ist noch kürzer und in diesem Sonderfallif i==j==4:
Knabberer

3
Verwandte: 4or afunktioniert, aber nichta or4
marcog

17
0orfunktioniert auch nicht ( 0oist ein Präfix für Oktalzahlen).
Nabb

5
@Nabb Nicht, dass es sowieso darauf ankommt, da 0 or xwird immer wieder zurück x. Könnte auch das ausschneiden 0 or.
Aprıɐɔuʇǝɥʇs

5
0orist aber in Ordnung als Teil einer längeren Nummer. 10 or xist äquivalent zu 10or x.
Trichoplax

54

Für eine Ganzzahl nkönnen Sie schreiben

  • n+1 wie -~n
  • n-1 wie ~-n

weil das Bit Flip ~xgleich ist -1-x. Dies verwendet die gleiche Anzahl von Zeichen, kann jedoch indirekt Leerzeichen oder Parens aus Gründen der Operatorpriorität entfernen.

Vergleichen Sie:

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

Die Betreiber ~und einstelligen -sind höhere Priorität als *, /, %, im Gegensatz zu binären +.


11
Eine Variation dieser Trick , den ich in heute lief: -~-xspeichert ein Byte vs. (1-x).
Lynn

4
Eine andere nützliche Anwendung ist die, a+b+1die prägnanter als geschrieben werden kann a-~b.
Strigoides

Und n-i-1ist einfach n+~i.
Ruohola

51

Eine gute Möglichkeit, eine iterable in eine Liste in Python 3 zu konvertieren :

Stellen Sie sich vor, Sie haben einige iterable, wie

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

Aber du brauchst eine Liste:

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

Es ist sehr nützlich, aus einer Zeichenfolge eine Liste von Zeichen zu erstellen

s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'

1
Typisierung *s,='abcde'und dann sstürzt meinen interaktiven python3 mit einem segfault :(
daniero

@ Daniero Wow. Nur auf der interaktiven Konsole? Klingt sehr komisch. Versuchen Sie es auf einer sauberen Konsole oder melden Sie den Fehler
JBernardo

1
Mein Python 3.5 funktioniert einwandfrei.
NoOneIsHere

für i = (x ** 2 für x in Bereich (5)) ich diesen Code zurückgegeben bekommen <Generator Objekt <genexpr> bei 0x03321690>
george

7
Und wenn Sie dies in einem Ausdruck tun, können Sie es tun [*'abcde'].
Esolanging Fruit

46

Stattdessen range(x)können Sie den *Operator für eine Liste von allem verwenden, wenn Sie den Wert von nicht wirklich verwenden müssen i:

for i in[1]*8:pass

im Gegensatz zu

for i in range(8):pass

Wenn Sie dies mehr als zweimal ausführen müssen, können Sie einer Variablen eine beliebige Iterationsvariable zuweisen und diese Variable mit dem gewünschten Bereich multiplizieren:

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

Hinweis : Dies ist oft länger als exec"pass;"*8, daher sollte dieser Trick nur verwendet werden, wenn dies keine Option ist.


@proudhaskeller Ich denke, der Punkt der Zeile, die Sie entfernt haben, war: "Zusätzlich zu den offensichtlichen Zeicheneinsparungen, die Sie erzielen, weil sie [1]*8kürzer als sind range(8), können Sie auch Platz sparen, weil dies for i in[...legal ist, während dies for i in range...nicht der Fall ist."
undergroundmonorail

Oh, richtig, das habe ich nicht verstanden. Jetzt behoben
stolzer Haskeller

7
exec"pass;"*8ist deutlich kürzer.
DJMcMayhem

1
if r=1, r*8ist 8 und Sie können eine Zahl nicht durchlaufen. Ich denke, Sie meintenr=[1]
Artemis Fowl

1
@ArtemisFowl, nein, es ist in Ordnung, das Komma nach der 1 erzeugt ein Tupel, das iterabel ist.
Sasha

43

Sie können das gute alte fremde Smiley-Gesicht verwenden, um Sequenzen umzukehren:

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

38

Erweitertes iterierbares Entpacken ("Markierte Zuweisung", nur Python 3)

Dies lässt sich am besten anhand eines Beispiels erklären:

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

Wir haben bereits eine Verwendung dafür gesehen - eine iterable in eine Liste in Python 3 verwandeln :

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

Hier sind noch ein paar Anwendungen.

Das letzte Element aus einer Liste holen

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

In einigen Situationen kann dies auch verwendet werden, um das erste Element zum Speichern von Parens abzurufen:

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

Zuweisen einer leeren Liste und anderer Variablen

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

Erstes oder letztes Element einer nicht leeren Liste entfernen

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

Diese sind kürzer als die Alternativen L=L[1:]und L.pop(). Das Ergebnis kann auch in einer anderen Liste gespeichert werden.

Trinkgelder mit freundlicher Genehmigung von @grc


Beeindruckend! Ich habe a=1;L=[]so oft geschrieben. Es ist erstaunlich, dass Sie Zeichen für etwas so Unkompliziertes wie dieses speichern können.
6.

@xnor Danke an grc. Mit nur einem anderen Element ist es nicht so gut ( a,*L=1,), aber es speichert immer noch ein
Zeichen

Vergessen Sie nicht, dass Sie mita,*_,b=L
Cyoce

36

setze Literale in Python2.7

Sie können Sets wie dieses schreiben S={1,2,3}Dies bedeutet auch Sie für die Mitgliedschaft überprüfen können mit {e}&Sstatt e in Sdem speichert ein Zeichen.


4
Und dies speichert auch den Charakter in ifs, da es keine Leerzeichen gibt ( if{e}&S:)
Artyer

1
Beachten Sie, dass Sie not indurch {e}-Sdiesen Trick ersetzen können
Black Owl Kai

35

Für eine Ewigkeit störte es mich, dass ich mir keinen kurzen Weg vorstellen konnte, um das gesamte Alphabet zu bekommen. Wenn Sie rangegenug verwenden, das R=rangees wert ist, in Ihrem Programm enthalten zu sein, dann

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

ist kürzer als die naive

'abcdefghijklmnopqrstuvwxyz'

, aber sonst ist es länger von einem einzelnen Zeichen. Es verfolgte mich, dass der Kluge, der etwas Wissen über die ASCII-Werte benötigte, ausführlicher war, als nur alle Buchstaben zu tippen.

Bis ich diese Antwort für das Alphabet meiner Tochter sah . Ich kann den Bearbeitungsverlauf nicht gut genug verfolgen, um herauszufinden, ob dieses Genie das Werk des OP war oder ob es ein Vorschlag eines Kommentators war, aber dies ist (glaube ich) der kürzeste Weg, um einen iterablen der 26 Buchstaben zu erstellen im römischen Alphabet.

map(chr,range(97,123))

Wenn die Groß- / Kleinschreibung keine Rolle spielt, können Sie ein anderes Zeichen mit Großbuchstaben entfernen:

map(chr,range(65,91))

Ich benutze mapviel zu viel, ich weiß nicht, wie mir das noch nie in den Sinn gekommen ist.


4
Könnte dies in der tatsächlichen Codierung verwenden, ich fühle mich so dumm, wenn diese Dinge hardcodiert werden: ')
ToonAlfrink

37
Verwenden Sie im eigentlichen Coding string.lowercase- dafür ist es da.
Kevin S

1
Wenn Sie beide Fälle benötigen, ist der kürzeste mir bekannte Weg filter (str.isalpha, map (chr, range (256))). Es ist kaum kürzer als s = map (chr, range (256)); s + = map (str.lower, s)
Quintopia

@quintopia: Warum 256 statt 122 ( ord('z'))? Abgesehen davon, dass es die gleiche Länge hat ... Wenn Sie alphanumerische str.isalphaZeichen benötigen, ersetzen Sie in der Version von @ quintopia durch str.isalnum. (Wenn Sie jedoch nur einen Fall benötigen, ist die gesamte Zeichenfolge mit 36 ​​Zeichen nicht länger als filter(str.isalnum,map(chr,range(90))).)
Tim Pederick

2
Wenn Sie unfair sind und range as verwenden R, ist meine Version kürzer als Ihre ursprüngliche: '%c'*26%tuple(R(97,123))(nur 24 Zeichen) Wenn Sie buchstabieren range, ist sie genauso lang wie die alphabetische Großbuchstabenversion
JBernardo 21.12.17

32

Obwohl Python keine switch-Anweisungen hat, können Sie sie mit Wörterbüchern emulieren. Zum Beispiel, wenn Sie einen Schalter wie diesen wollten:

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

Sie könnten ifAnweisungen verwenden, oder Sie könnten dies verwenden:

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

oder dieses:

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

Das ist besser, wenn alle Codepfade Funktionen mit denselben Parametern sind.

So unterstützen Sie einen Standardwert:

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

(oder dieses:)

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

Ein weiterer Vorteil ist, dass Sie Redundanzen einfach nach dem Ende des Wörterbuchs hinzufügen können:

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

Und wenn Sie nur einen Schalter verwenden wollten, um einen Wert zurückzugeben:

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

Sie könnten dies einfach tun:

getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)

2
Dies ist etwas, über das ich gerne in der freien Natur nachdenken würde. Ich vermisse meine switch-Anweisungen! +1
HalosGhost

1
Obwohl Sie im ersten Beispiel kein Wörterbuch mit nummerierten Schlüsseln verwenden, sollten Sie nur eine Liste verwenden
Cyoce 13.10.16

1
Wenn Sie Zeichenfolgen als Schlüssel haben, verwenden Sie dict(s1=v1,s2=v2,...,sn=vn)anstelle von {'s1':v1,'s2':v2,...,'sn':vn}2 * n-4 Bytes und ist besser, wenn n> = 3
Black Owl Kai

31

Wenn Sie zwei boolesche Werte haben aund bherausfinden möchten, ob beide aund bwahr sind, verwenden Sie *anstelle von and:

if a and b: #7 chars

vs

if a*b: #3 chars

Wenn einer der Werte falsch ist, wird er wie 0in dieser Anweisung ausgewertet , und ein ganzzahliger Wert ist nur dann wahr, wenn er ungleich Null ist.


9
Oder Sie könnten verwenden &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs

3
Verwenden Sie +für, orwenn Sie garantieren könnena != -b
U-

2
|funktioniert in allen Situationen.
CalculatorFeline

1
*Anstelle von and/ werden &&einige Bytes in vielen Sprachen gespeichert.
Wastl

26

Exploit Python 2-Zeichenfolgendarstellungen

Mit Python 2 können Sie ein Objekt xzu `x`einem Preis von nur 2 Zeichen in seine Zeichenfolgendarstellung konvertieren . Verwenden Sie diese Option für Aufgaben, die für die Zeichenfolge des Objekts einfacher sind als für das Objekt selbst.

Verbinde Charaktere

Ausgehend von einer Liste von Zeichen l=['a','b','c']kann man ''.join(l)as erzeugen `l`[2::5], wodurch ein Byte eingespart wird.

Der Grund hierfür ist , dass `l`ist "['a', 'b', 'c']"(mit Leerzeichen), so dass man die Buchstaben mit einer Liste slice extrahieren kann, ausgehend , dass der zweite Null-indizierte Charakter a, und von dort jedes fünften Zeichen nehmen. Dies funktioniert nicht, um Zeichenfolgen mit mehreren Zeichen oder Escape-Zeichen zu verbinden, die wie dargestellt werden '\n'.

Zahlen verketten

In ähnlicher Weise eine nicht-leere Liste der Stellen gegeben wie l=[0,3,5], man sich in eine String verketten kann '035'wie `l`[1::3].

Das spart so etwas wie map(str,l). Beachten Sie, dass es sich um einzelne Ziffern handeln muss und dass keine Gleitkommazahlen wie 1.0gemischt verwendet werden dürfen ].

Auf Negative prüfen

Nun zu einer Aufgabe ohne Zeichenfolge. Angenommen, Sie haben eine Liste lvon reellen Zahlen und möchten testen, ob sie negative Zahlen enthalten, wodurch ein Boolescher Wert erzeugt wird.

Du kannst tun

'-'in`l`

Das prüft auf ein negatives Vorzeichen in der Zeichenfolge rep. Dies ist kürzer als eines von beiden

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

Zum zweiten min(l)<0würde das auf der leeren Liste scheitern, so dass man sich absichern muss.


Die Verkettung von Zeichenfolgen mit einzelnen Ziffern ist auch in Python 3 wirksam, wenn auch in geringerem Maße: str(l)[2::5]beträgt 12 Byte gegenüber 19 für ''.join(map(str,l)). Eine tatsächliche Situation, in der dies auftrat (wo les eine Generatoranweisung gab, keine Liste), hat mir nur ein Byte gespart ... das ist es immer noch wert!
Tim Pederick

25

Eine einzeilige Funktion kann mit Lambda ausgeführt werden:

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

kann konvertiert werden zu (notiere fehlendes Leerzeichen 3andund 10or)

c=lambda a:a<3and a+10or a-5

21
oder c=lambda a:a+[-5,10][a<3]. Der und / oder Trick ist nützlicher, wenn Sie vom Kurzschlussverhalten abhängig sind
Gnibbler

3
else: Kann in Ihrer Funktion gelöscht werden, wenn returndie Ausführung der Funktion gestoppt wird, sodass alles, was folgt, nur ausgeführt wird, wenn die ifBedingung fehlgeschlagen ist, auch bekannt als, wenn die elseBedingung wahr ist. Somit elsekann gefahrlos aufgehoben werden. (Ausführlich erklärt für die Neophyten da draußen)
JeromeJ

c (-10) gibt -15 zurück, während es 0 zurückgeben sollte
Anvit

oderc=lambda a:a-5+15*(a<3)
JayXon

25

Schleifen von bis zu 4 Elementen sind möglicherweise besser, um ein Tupel zu liefern, als range zu verwenden

for x in 0,1,2:

vs

for x in range(3):

24

Decke und Boden

Wenn Sie jemals das aufgerundete Ergebnis für eine Division erhalten möchten, wie Sie es //für Floor tun würden , können Sie es math.ceil(3/2)für 15 oder das viel kürzere -(-3//2)für 8 Bytes verwenden.

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

math.ceil(n)    : 12 bytes+12 for import
-(-n//1)        : 8  bytes

5
Das hat mir knapp 20 Bytes erspart, danke!
Morgan Thrapp

1
manchmal kann man weg mit n//1+1anstatt mit ceil, aber es bedeutet ceil (n) = n + 1, aber es sollte für alle nicht ganzzahligen Werte
funktionieren

round(x)ist (x+.5)//1, +1 Byte, letzteres beginnt jedoch mit a (, und wenn xes sich um eine Summe handelt, die aus einer Konstanten besteht, kann dies nützlich sein.
User202729

23

Verwenden Sie +=anstelle von appendundextend

A.append(B)  

kann gekürzt werden auf:

A+=B,

B,Hier wird ein Tupel mit einem Element erstellt, mit dem Sie die Erweiterung Awie [B]in ausführen können A+=[B].


A.extend(B)

kann gekürzt werden auf:

A+=B

5
In vielen (aber nicht allen) Fällen, return 0oder return 1entspricht return Falseoder return True.
Undergroundmonorail

5
(1) funktioniert nur, wenn Sie bereits wissen, dass die Zahl negativ ist. In diesem Fall können Sie weitere 2 Zeichen speichern, indem Sie einfach ein Minuszeichen verwenden. -xeher als x*-1. --8.32eher als -8.32*-1. Oder einfach 8.32...
Trichoplax

OP zitieren: Bitte einen Tipp pro Antwort posten.
Nyuszika7h

Beachten Sie, dass in a A+=B Bist tuple.
Erik der Outgolfer

23

Auswahl einer von zwei Zahlen basierend auf einer Bedingung

Es ist bereits bekannt , die Listenauswahl [x,y][b]mit einem Booleschen Wert bfür den ternären Ausdruck zu verwenden y if b else x. Die Variablen x, yund bkönnen auch Ausdrücke, obwohl beachten Sie, dass beide xund ywerden auch ausgewertet , wenn sie nicht ausgewählt.

Hier sind einige mögliche Optimierungen, wenn xund ysind Zahlen.

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

Sie können auch wechseln xund ywenn Sie umschreiben kann bseine Negation anstatt zu sein.


22

Verwenden Sie ~, um am Ende einer Liste zu indizieren

Wenn Les sich um eine Liste handelt, verwenden Sie L[~i]diese Option, um das i'te Element von hinten abzurufen.

Dies ist das i'te Element der Umkehrung von L. Das Bitkomplement ist ~igleich -i-1und behebt so den Fehler von Off-by-One L[-i].


21

PEP448 - Zusätzliche Verallgemeinerungen beim Auspacken

Mit der Veröffentlichung von Python 3.5 wurde die Manipulation von Listen, Tupeln, Sätzen und Dikten noch golfer.

Aus einer Iteration wird eine Menge / Liste

Vergleichen Sie die Paare:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Viel kürzer! Beachten Sie jedoch, dass das normale, erweiterte, wiederholbare Entpacken kürzer ist , wenn Sie nur etwas in eine Liste konvertieren und einer Variablen zuweisen möchten :

L=[*T]
*L,=T

Eine ähnliche Syntax funktioniert für Tupel:

T=*L,

das ist wie ausgedehntes iterables Auspacken, aber mit dem Sternchen und dem Komma auf der anderen Seite.

Listen / Tupel verbinden

Das Entpacken ist etwas kürzer als das Verketten, wenn Sie eine Liste / ein Tupel an beide Seiten anhängen müssen:

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

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

Inhalt mehrerer Listen drucken

Dies ist nicht beschränkt auf print, aber es ist definitiv, wo der größte Teil der Laufleistung herkommt. PEP448 ermöglicht jetzt das mehrfache Auspacken wie folgt:

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

Aktualisieren mehrerer Wörterbuchelemente

Dies wird wahrscheinlich nicht sehr oft vorkommen, aber die Syntax kann verwendet werden, um beim Aktualisieren von Wörterbüchern zu sparen, wenn Sie mindestens drei Elemente aktualisieren:

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

Dies negiert grundsätzlich jegliche Notwendigkeit dict.update.


6
Das sieht schlimmer aus als Perl, aber es funktioniert ...
Mega Man

20

Wechseln Sie import *zuimport*


Wenn Sie nicht gehört haben, import*speichert Zeichen!

from math import*

ist nur 1 Zeichen länger als import math as mund Sie können alle Instanzen von entfernenm.

Schon der einmalige Gebrauch spart!


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

wenn der Wert von i nutzlos ist:

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

oder

>>> exec's+=input();'*x

8
Sie können aus dem zweiten Beispiel for i in[0]*x:s+=input()einen anderen Platz machen. Sie können auch das Leerzeichen zwischen dem exec und dem ersten Anführungszeichen entfernen, um zu erhaltenexec's+=input();'*x
Justin Peel

sollte nicht die zweite Zeile sein:for i in[0]*x:s+=input()
Micsthepick

Dupe (neuere, aber bessere Stimmen)
user202729
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.