Wskazówki dotyczące gry w golfa w języku Python


248

Jakie masz ogólne wskazówki na temat gry w golfa w Pythonie? Szukam pomysłów, które można zastosować do problemów związanych z golfem i które są przynajmniej w pewnym stopniu specyficzne dla Pythona (np. „Usuń komentarze” nie jest odpowiedzią).

Proszę zamieścić jedną wskazówkę na odpowiedź.


27
Och, widzę cały zestaw pytań, takich jak to, nadchodzących dla każdego języka ...
R. Martinho Fernandes

4
@Marthinho Zgadzam się. Właśnie uruchomiłem odpowiednik C ++ . Nie sądzę jednak, aby było to złe, o ile nie widzimy tych samych odpowiedzi w odpowiedzi na wiele z tych typów pytań.
marcog

50
Uwielbiam to pytanie, ale muszę sobie powtarzać: „To TYLKO dla zabawy, NIE dla kodu produkcyjnego”
Greg Guida,

2
Czy to pytanie nie powinno być postem wiki społeczności?
dorukayhan

3
@dorukayhan Nope; jest to ważne pytanie ze wskazówkami do gry w golfa , z prośbą o wskazówki dotyczące skrócenia kodu Pythona do celów CG. Takie pytania są całkowicie poprawne dla witryny i żaden z tych tagów nie mówi wprost, że pytanie powinno być CW, w odróżnieniu od SO, które wymagało CW. Również napisanie dobrej odpowiedzi i znalezienie takich wskazówek zawsze zasługuje na coś, co jest odbierane, jeśli pytanie jest społeczności wiki (rep).
Erik the Outgolfer,

Odpowiedzi:


152

Użyj a=b=c=0zamiast a,b,c=0,0,0.

Użyj a,b,c='123'zamiast a,b,c='1','2','3'.


2
to ogólnie dobra wskazówka :)

28
Zauważ, że niekoniecznie zadziała to w przypadku definiowania obiektów, które można modyfikować w miejscu. a = b = [1] faktycznie różni się od a = [1]; b = [1]
isaacg

6
Zabawne jest to, że pierwsza wskazówka polega na tym, że działa ona również w Javie.
Justin

1
@Justin Tak, ale tylko z prymitywnymi typami
HyperNeutrino

11
Ale NIGDY nie używaj a = b = c = [] ani żadnej instancji obiektu, ponieważ wszystkie zmienne będą wskazywały na to samo wystąpienie. Prawdopodobnie nie tego chcesz.
PhE

146

Warunki warunkowe mogą być długie. W niektórych przypadkach możesz zamienić prosty warunek na (a,b)[condition]. Jeśli conditionjest prawdą, to bjest zwracane.

Porównać

if a<b:return a
else:return b

Do tego

return(b,a)[a<b]

37
To nie są dokładnie takie same. Pierwszy ocenia tylko zwracane wyrażenie, a drugi zawsze ocenia oba. Te zwierają: a if a<b else bia<b and a or b
marinus

3
(lambda(): b, lambda(): a)[a < b]()zrób własne zwarcie z lambdas
Ming-Tang

3
@ marinus, nie są one równe: po prostu rozważ P and A or Bkażde A, które daje bool(A)=False. Ale (P and [A] or [B])[0]wykona zadanie. Zobacz diveintopython.net/power_of_introspection/and_or.html w celach informacyjnych.
kgadek

6
Jagnięta są znacznie dłuższe niż wyrażenie warunkowe.
user2357112,

18
@ user2357112 Ale sprawiają, że wyglądasz o wiele fajniej, gdy ich używasz. :]
Chase Ries

117

Świetną rzeczą, którą kiedyś zrobiłem, jest:

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

zamiast:

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

Operatory porównania Pythona działają jak skała.


Używając tego, że wszystko jest porównywalne w Pythonie 2, możesz w andten sposób uniknąć operatora. Na przykład, jeśli a, b, ci dsą liczbami całkowitymi,

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

można skrócić o jedną postać do:

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

Dzięki temu każda lista jest większa niż dowolna liczba całkowita.

Jeśli ci dsą listami, staje się to jeszcze lepsze:

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

22
Oczywiście, gdyby tak naprawdę grał w golfa, byłby to3>a>1<b<5
Rafe Kettler

4
Uwielbiam symetrię. Przypomina mi starą sztuczkę golfową Perla dotyczącą znalezienia min $ a i $ b: [$a => $b]->[$b <= $a]:)
Simon Whitaker

Zauważ, że drugi przykład (bez list) można również zrobić zif(a<b)+(c>d):foo()
WorldSEnder

6
Znak + powinien być *. orByłoby+
WorldSEnder

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

103

Jeśli wielokrotnie używasz wbudowanej funkcji, nadanie jej nowej nazwy może być bardziej zajmujące miejsce, jeśli używasz różnych argumentów:

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

6
Jednak tak naprawdę nie zapisał żadnych bajtów.
user2357112,

4
r = zasięg, a pozostałe dwa r to 9 znaków; dwukrotne użycie zakresu to 10 znaków. Nie jest to duża oszczędność w tym przykładzie, ale wystarczy jeszcze jedno użycie zakresu, aby zobaczyć znaczącą oszczędność.
Frank

13
@Frank Dodatkowa nowa linia to kolejny znak.
L3viathan

2
Rzeczywiście, dwa powtórzenia to za mało, aby zaoszczędzić na nazwie funkcji o długości pięciu. Potrzebujesz: długość 2: 6 powtórzeń, długość 3: 4 powtórzeń, długość 4 lub 5: 3 powtórzeń, długość> = 6: 2 powtórzeń. AKA (długość-1) * (powtórzenia-1)> 4.
Ørjan Johansen

Uwaga: dotyczy to wszystkich języków z pierwszorzędnymi funkcjami.
bfontaine

94

Czasami kod Pythona wymaga 2 poziomów wcięcia. Oczywistą rzeczą do zrobienia jest użycie jednej i dwóch spacji dla każdego poziomu wcięcia.

Jednak Python 2 uważa znaki tabulacji i spacji za różne poziomy wcięcia.

Oznacza to, że pierwszy poziom wcięcia może mieć jedną spację, a drugi może być znakiem tabulacji.

Na przykład:

if 1:
 if 1:
\tpass

Gdzie \tjest znak tabulacji.


1
Fajnie, nigdy o tym nie myślałem!
Jules Olléon

97
To się nie udaje w python3: nie można już mieszać spacji i tabulatorów (zła rzecz dla codegolfa, ale dobra rzecz we wszystkich innych przypadkach).
Bakuriu

1
W Pythonie 3.4 wydaje się, że działa dobrze.
trichoplax

3
@trichoplax , w python 3.4.3 otrzymujęTabError: inconsistent use of tabs and spaces in indentation.
ceilingcat

Dla porównania, karta jest warta 8 spacji.
Erik the Outgolfer

87

Używaj podstawiania ciągów, execaby radzić sobie z długimi słowami kluczowymi, lambdaktóre są często powtarzane w kodzie.

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

Łańcuch docelowy ma bardzo często 'lambda 'długość 7 bajtów. Załóżmy, że fragment kodu zawiera nwystąpień 'lambda 'i jest sbajtów. Następnie:

  • plainOpcja jest sbajtów.
  • replaceOpcja jest s - 6n + 29bajtów.
  • %Opcja jest s - 5n + 22 + len(str(n))bajtów.

Z wykresu bajtów zapisanychplain dla tych trzech opcji możemy zobaczyć, że:

  • Dla n <5 lambdów lepiej nie robić nic wymyślnego.
  • Dla n = 5 zapisywanie exec"..."%(('lambda ',)*5)oszczędza 2 bajty i jest najlepszą opcją.
  • Dla n> 5 pisanie exec"...".replace('`','lambda ')jest najlepszą opcją.

W innych przypadkach możesz zindeksować poniższą tabelę:

          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)

Na przykład, jeśli ciąg lambda x,y:(długość 11) występuje w kodzie 3 razy, lepiej pisać exec"..."%(('lambda x,y:',)*3).


4
to powinno uzyskać więcej głosów, to bardzo przydatna wskazówka.
bigblind

7
to niezwykle rzadkie, że to działa. koszt replacejest ogromny.
stoisko

4
Kiedy jednak działa, bardzo pomaga.
undergroundmonorail

Ciekawe, nawet o tym nie pomyślałem!
Claudiu

Dodałem nowy operator dla lambda w moim języku oparty na python: =>to tylko ciąg = lambda . Na przykład f=>:0byłoby f = lambda: 0.
NoOneIsHere

78

Użyj rozszerzonego krojenia, aby wybrać jeden ciąg z wielu

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

W tym logicznym dwuczęściowym przypadku można również pisać

b*"string"or"other_string"

dla

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

W przeciwieństwie do przeplatania, działa to na ciągi dowolnej długości, ale może mieć problemy z pierwszeństwem operatora, jeśli bzamiast tego jest wyrażeniem.


Zauważ, że pierwszy przykład ma dokładnie taką samą długość jakfor x in ("foo","bar","baz"): print x
Mateen Ulhaq

1
@MateenUlhaq, To tylko przykład, w jaki sposób xrenderowane są różne wartości . Część golfowa jest "fbboaaorz"[x::3]vs ["foo","bar","baz"][x]Sposób obliczania xwartości byłby kolejną częścią twojego rozwiązania golfowego.
gnibbler

72

Służy `n`do konwersji liczby całkowitej na ciąg zamiast używaniastr(n) :

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

38
Fajnie, ale nie działa z Python3.
Alexandru

2
Uwaga: naprawdę działa dla liczb całkowitych, ale nie dla ciągów znaków, na przykład.
Nakilon

41
btw. `` skrót od repr
Alexandru

9
Liczby całkowite mniejsze niż -2 ** 31 lub większe niż 2 ** 31-1 (Longs) otrzymują na końcu „L”.
hallvabo

6
Może to również służyć do drukowania pływaków z pełną precyzją
gnibbler

69

Przechowuj tabele odnośników jako magiczne liczby

Załóżmy, że chcesz na stałe zakodować boolowską tablicę wyszukiwania, na przykład, która z pierwszych dwunastu angielskich liczb zawiera 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

Następnie możesz zwięźle zaimplementować tę tabelę wyszukiwania:

3714>>i&1

z wynikającymi 0lub 1jest równa Falsesię True.

Chodzi o to, że magiczna liczba przechowuje tabelę jako ciąg bitów bin(3714)= 0b111010000010, przy czym n-ta cyfra (od końca) odpowiada nth pozycji tablicy. Dostęp do ntego wpisu uzyskujemy poprzez przesunięcie bitów nw prawo spacji numerycznych i zabranie ostatniej cyfry o &1.

Ta metoda przechowywania jest bardzo wydajna. Porównaj z alternatywami

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

Możesz mieć swoje wpisy multibitowe w tabeli odnośników, które można wyodrębnić

 340954054>>4*n&15

aby wyodrębnić odpowiedni czterobitowy blok.


Czy możemy otrzymać przykładowy wynik dla czterobitowego bloku? Czy używałeś reguły dla bloku n-bitowego?
JeromeJ

8
Hex może czasami być jeszcze mniejszy.
Joonazan

4
Jest to przydatne w wielu językach.
Cyoce

1
@Joonazan Hex jest mniejszy dla numerów powyżej 999 999 .
Mateen Ulhaq,

60

Zwiń dwie pętle numeryczne w jedną

Powiedzmy, że iterujesz po komórkach m*nsiatki. Zamiast dwóch zagnieżdżonych forpętli, jednej dla wiersza i jednej kolumny, zwykle krótsze jest użycie pojedynczej pętli do iteracji po m*nkomórkach siatki. Możesz wyodrębnić wiersz i kolumnę komórki wewnątrz pętli.

Oryginalny kod:

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

Kod do gry w golfa:

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

W efekcie iterujesz nad iloczynem kartezjańskim dwóch zakresów, kodując parę (i,j)jako x=i*n+j. Zapisałeś kosztowne rangepołączenie i poziom wcięcia w pętli. Kolejność iteracji pozostaje niezmieniona.

Użyj //zamiast /w Pythonie 3. Jeżeli dotyczą ii jwiele razy, może być szybciej przypisać ich wartości i=k/n, j=k%nwewnątrz pętli.


5
To jest niesamowite. Nigdy nie zdawałem sobie sprawy, że to możliwe!
theonlygusti

Widziałem to w poradnikach do JavaScript. To bardzo przydatna sztuczka w większości języków.
Cyoce

7
Dla odniesienia, aby rozszerzyć to na 3 pętle:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007

3
W przypadku npętli: repl.it/EHwa
mbomb007

W niektórych przypadkach itertools.productmogą być znacznie bardziej zwięzłe niż pętle zagnieżdżone, szczególnie podczas generowania produktów kartezjańskich. a1, a2, b1, b2są przykładami kartezjańskiego produktu 'ab'i'12'
Aaron3468

54

Chyba że następujący token zaczyna się od elub E. Możesz usunąć spację po numerze.

Na przykład:

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

Staje się:

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

Używanie tego w skomplikowanych instrukcjach jednowierszowych może zaoszczędzić sporo znaków.

EDYCJA: jak wskazał @marcog, 4or abędzie działać, ale nie, a or4ponieważ jest to mylone z nazwą zmiennej.


37
if(i,j)==(4,4):jest jeszcze krótszy, aw tym szczególnym przypadkuif i==j==4:
gnibbler 28.01.11

3
Powiązane: 4or adziała, ale niea or4
marcog

17
0orteż nie działa ( 0ojest prefiksem liczb ósemkowych).
Nabb

5
@Nabb I tak nie ma to znaczenia, ponieważ 0 or xzawsze wróci x. Równie dobrze można wyciąć 0 or.
6ıʇǝɥʇuʎs

5
0orjest w porządku, jako część dłuższej liczby. 10 or xjest równoważne z 10or x.
trichoplax

53

W przypadku liczb całkowitych nmożesz pisać

  • n+1 tak jak -~n
  • n-1 tak jak ~-n

ponieważ bit flip ~xjest równy -1-x. Używa tej samej liczby znaków, ale może pośrednio wycinać spacje lub pareny dla pierwszeństwa operatora.

Porównać:

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

Operatorzy ~i jednoskładnikowa -jest wyższy priorytet niż *, /, %w przeciwieństwie do binarnego +.


11
Odmianą tej sztuczki wpadłem na dziś: -~-xoszczędza jeden bajt Vs. (1-x).
Lynn

4
Inną przydatną aplikacją jest to, że a+b+1można ją bardziej zwięźle napisać jako a-~b.
Strigoides,

I n-i-1jest po prostu n+~i.
ruohola

51

Dobry sposób na przekonwertowanie iterowalnej listy na Python 3 :

wyobraź sobie, że masz jakieś iterowalne

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

Ale potrzebujesz listy:

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

Bardzo przydatne jest utworzenie listy znaków z łańcucha

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

1
pisanie, *s,='abcde'a następnie szawiesza moje interaktywne python3 z segfault :(
daniero

@daniero Wow. Tylko na interaktywnej konsoli? Brzmi bardzo dziwnie. Wypróbuj go na czystej konsoli lub zgłoś błąd
JBernardo,

1
Mój Python 3.5 działa dobrze.
NoOneIsHere

dla i = (x ** 2 dla x w zakresie (5)) Otrzymuję ten kod zwrócony <obiekt generatora <genexpr> o 0x03321690>
george

7
A jeśli robisz to w wyrażeniu, możesz to zrobić [*'abcde'].
Esolanging Fruit

46

Zamiast range(x) możesz użyć *operatora na liście czegokolwiek, jeśli tak naprawdę nie musisz używać wartości i:

for i in[1]*8:pass

w przeciwieństwie do

for i in range(8):pass

Jeśli musisz to zrobić więcej niż dwa razy, możesz przypisać dowolną iterowalną zmienną i pomnożyć tę zmienną przez żądany zakres:

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

Uwaga : często jest on dłuższy niż exec"pass;"*8, więc tej sztuczki należy używać tylko wtedy, gdy nie jest to możliwe.


@proudhaskeller Myślę, że celem linii, którą usunąłeś, było to, że „Oprócz oczywistych oszczędności postaci, które otrzymujesz, ponieważ [1]*8są one krótsze niż range(8), możesz także zaoszczędzić miejsce, ponieważ for i in[...jest to legalne, podczas gdy for i in range...nie jest”.
undergroundmonorail

och, racja, nie zrozumiałem tego. naprawione teraz
dumny haskeller

7
exec"pass;"*8jest znacznie krótszy.
DJMcMayhem

1
jeśli r=1, r*8wynosi 8, i nie można iterować przez liczbę. Chyba miałeś na myślir=[1]
Artemis Fowl

1
@ArtemisFowl, nie jest w porządku, przecinek przecinek po 1 tworzy krotkę, którą można iterować.
sasha

43

Możesz użyć starej dobrej obcej buźki do odwrócenia sekwencji:

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

38

Rozszerzone iterowalne rozpakowywanie („ gwiazdką”, tylko Python 3)

Najlepszym sposobem na wyjaśnienie tego jest przykład:

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

Widzieliśmy już zastosowanie tego - przekształcenie iterowalnej listy w Python 3 :

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

Oto kilka innych zastosowań.

Pobieranie ostatniego elementu z listy

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

W niektórych sytuacjach można tego również użyć do uzyskania pierwszego elementu zapisanego na parens:

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

Przypisywanie pustej listy i innych zmiennych

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

Usuwanie pierwszego lub ostatniego elementu niepustej listy

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

Są one krótsze niż alternatywy L=L[1:]i L.pop(). Wynik można również zapisać na innej liście.

Porady dzięki uprzejmości @grc


Łał! Pisałem a=1;L=[]tyle razy. To niesamowite, że możesz zapisywać znaki na czymś tak prostym jak to.
xnor

@xnor To dzięki dzięki grc. Tylko z jednym innym elementem nie jest tak dobry ( a,*L=1,), ale wciąż oszczędza jeden znak :)
Sp3000

nie zapomnij, że możesz uzyskać zarówno pierwszy, jak i ostatni element listy za pomocąa,*_,b=L
Cyoce

36

ustaw literały w Python2.7

Możesz pisać takie zestawy. S={1,2,3}Oznacza to również, że możesz sprawdzić członkostwo, używając, {e}&Szamiast e in Sktórego zapisujesz jedną postać.


4
I to również zapisuje postać ifs, ponieważ nie ma spacji ( if{e}&S:)
Artyer

1
Pamiętaj, że możesz zastąpić not ingo {e}-Stą sztuczką
Black Owl Kai

35

Przez wieki martwiło mnie, że nie mogę wymyślić krótkiego sposobu na zdobycie całego alfabetu. Jeśli wykorzystasz rangewystarczającą ilość, którą R=rangewarto mieć w swoim programie, to

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

jest krótszy niż naiwny

'abcdefghijklmnopqrstuvwxyz'

, ale poza tym jest dłuższy o jedną postać. Prześladowało mnie to, że ta mądra, która wymagała pewnej wiedzy o wartościach ascii, okazała się bardziej gadatliwa niż tylko pisanie wszystkich liter.

Dopóki nie zobaczyłem odpowiedź dla Alfabet mojej córki . Nie mogę śledzić historii edycji wystarczająco dobrze, aby dowiedzieć się, czy ten geniusz był dziełem OP, czy też sugestią komentatora, ale jest to (jak sądzę) najkrótsza droga do stworzenia iterowalnej z 26 liter alfabetem rzymskim.

map(chr,range(97,123))

Jeśli wielkość liter nie ma znaczenia, możesz usunąć inną postać, używając wielkich liter:

map(chr,range(65,91))

Używam mapzdecydowanie za dużo, nie wiem, jak mi się to nigdy nie zdarzyło.


4
Mogę użyć tego w prawdziwym kodowaniu, czuję się tak głupio, kiedy programuję te rzeczy: ')
ToonAlfrink

37
W rzeczywistym kodowaniu używaj string.lowercase- po to jest.
Kevin S

1
jeśli potrzebujesz obu przypadków, najkrótszym sposobem jaki znam jest filtr (str. isalpha, map (chr, range (256))). Jest tylko nieco krótszy niż s = mapa (chr, zasięg (256)); s + = mapa (str. Dolna, s)
kwintopia

@quintopia: Dlaczego 256 zamiast 122 ( ord('z'))? Oprócz tego, że ma taką samą długość ... Jeśli potrzebujesz alfanumerycznych, zamień str.isalphaw wersji @ quintopia na str.isalnum. (Ale jeśli potrzebujesz tylko jednego przypadku, cały ciąg 36 znaków nie jest dłuższy niż filter(str.isalnum,map(chr,range(90))).)
Tim Pederick

2
Jeśli będziesz niesprawiedliwy i użyjesz zakresu jako R, moja wersja jest krótsza niż oryginalna: '%c'*26%tuple(R(97,123))(tylko 24 znaki), jeśli przeliterujesz range, jest ona tak długa, jak alfabet - wersja z dużymi literami jest krótsza
JBernardo

32

Chociaż python nie ma instrukcji switch, możesz emulować je za pomocą słowników. Na przykład, jeśli chcesz taki przełącznik:

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

Możesz użyć ifinstrukcji lub możesz użyć tego:

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

albo to:

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

co jest lepsze, jeśli wszystkie ścieżki kodu są funkcjami o tych samych parametrach.

Aby wesprzeć wartość domyślną:

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

(albo to:)

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

Inną zaletą tego jest to, że jeśli masz zwolnienia, możesz je dodać po zakończeniu słownika:

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

A jeśli chcesz użyć przełącznika do zwrócenia wartości:

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

Możesz po prostu to zrobić:

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

2
Jest to coś, co głęboko rozważałbym użycie na wolności. Tęsknię za moimi oświadczeniami zamiany! +1
HalosGhost,

1
Chociaż zamiast używać słownika z numerowanymi klawiszami w pierwszym przykładzie, powinieneś po prostu użyć listy
Cyoce

1
Jeśli masz ciągi jako klucze, użycie dict(s1=v1,s2=v2,...,sn=vn)zamiast {'s1':v1,'s2':v2,...,'sn':vn}zapisuje 2 * n-4 bajtów i lepiej, jeśli n> = 3
Black Owl Kai

31

Kiedy masz dwie wartości logicznych, aa bjeśli chcesz dowiedzieć się, czy oba ai bsą prawdziwe, użyj *zamiast and:

if a and b: #7 chars

vs

if a*b: #3 chars

jeśli którakolwiek z wartości jest fałszywa, zostanie obliczona jak 0w tej instrukcji, a wartość całkowita jest prawdziwa tylko wtedy, gdy jest niezerowa.


9
Albo można użyć &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs

3
używać +dla orjeśli można zagwarantowaća != -b
undergroundmonorail

2
|działa we wszystkich sytuacjach.
CalculatorFeline

1
*zamiast and/ &&zapisuje niektóre bajty w wielu językach.
wastl

26

Wykorzystaj ciągi znaków w języku Python 2

Python 2 pozwala przekonwertować obiekt xna jego reprezentację ciągu`x` ciągu kosztem tylko 2 znaków. Użyj tego do zadań, które łatwiej wykonać na łańcuchu obiektu niż na samym obiekcie.

Dołącz do postaci

Biorąc pod uwagę listę znaków l=['a','b','c'], można utworzyć ''.join(l)as `l`[2::5], co oszczędza bajt.

Powodem jest to, że `l`jest "['a', 'b', 'c']"(ze spacjami), więc można wyodrębnić litery z plasterka listy, zaczynając że drugie zero-indeksowane charakter a, biorąc co piąty znak stamtąd. Nie działa to w przypadku łączenia ciągów wieloznakowych lub znaków zastępczych przedstawionych jako'\n' .

Połącz cyfry

Podobnie, biorąc pod uwagę niepustą listę cyfr, takich jak l=[0,3,5], można połączyć je w ciąg znaków '035'jako`l`[1::3] .

To oszczędza robienie czegoś takiego map(str,l). Zauważ, że muszą być one jednocyfrowe i nie mogą mieć liczb zmiennoprzecinkowych, takich jak 1.0pomieszane. Ponadto nie powiodło się to na pustej liście, powodując powstanie] .

Sprawdź negatywne

Teraz dla zadania nieciągłego. Załóżmy, że masz listę lliczb rzeczywistych i chcesz sprawdzić, czy zawiera ona liczby ujemne, co daje wartość logiczną.

Możesz to zrobić

'-'in`l`

który sprawdza znak ujemny w rep. To krócej niż którykolwiek z nich

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

Po drugie, min(l)<0nie powiedzie się na pustej liście, więc musisz się zabezpieczyć.


Łączenie cięć ciągów jednocyfrowych jest również skuteczne w Pythonie 3, chociaż mniej: str(l)[2::5]wynosi 12 bajtów w porównaniu z 19 dla ''.join(map(str,l)). Rzeczywista sytuacja, w której to się wydarzyło (gdzie lbyła instrukcja generatora, a nie lista) zaoszczędziła mi tylko jeden bajt ... co wciąż jest tego warte!
Tim Pederick,

25

Jednowierszową funkcję można wykonać za pomocą lambda:

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

można przekonwertować na (zwróć uwagę na brak miejsca 3andi 10or)

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

21
lub c=lambda a:a+[-5,10][a<3]. sztuczka i / lub trik jest bardziej przydatna, gdy
zależysz od

3
W Twojej funkcji else: można ją usunąć, ponieważ returnzatrzymuje wykonywanie funkcji, więc wszystko, co następuje, jest wykonywane tylko wtedy, gdy ifwarunek się nie powiedzie, czyli jeśli elsewarunek jest prawdziwy. W ten sposób elsemożna bezpiecznie pominąć. (Wyjaśnione szczegółowo dla neofitów na zewnątrz)
JeromeJ

c (-10) zwraca -15, podczas gdy powinno zwrócić 0
Anvit

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

25

Pętle składające się z maksymalnie 4 przedmiotów mogą być lepsze niż kratka

for x in 0,1,2:

vs

for x in range(3):

24

Sufit i podłoga

Jeśli kiedykolwiek chcesz uzyskać zaokrąglony wynik dla podziału, podobnie jak w //przypadku podłogi, możesz użyć math.ceil(3/2)dla 15 lub znacznie krótszego -(-3//2)dla 8 bajtów.

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
To właśnie zaoszczędziło mi blisko 20 bajtów, dziękuję!
Morgan Thrapp,

1
czasami można uciec n//1+1zamiast ceil, ale to znaczy ceil (n) = n + 1, ale powinno działać dla wszystkich wartości niecałkowitych
fejfo

round(x)to (x+.5)//1+1 bajt, ale ten ostatni zaczyna się od a (, a jeśli xsuma składająca się ze stałej może być użyteczna.
user202729,

23

Użyj +=zamiast appendiextend

A.append(B)  

można skrócić do:

A+=B,

B,tutaj tworzy krotkę jednoelementową, której można użyć do rozszerzenia Atak jak [B]w A+=[B].


A.extend(B)

można skrócić do:

A+=B

5
W wielu (ale nie wszystkich) przypadkach return 0lub return 1jest równoważne z return Falselub return True.
metro

5
(1) działa tylko wtedy, gdy wiesz, że liczba jest ujemna, w którym to przypadku możesz zapisać kolejne 2 znaki, po prostu używając znaku minus. -xraczej niż x*-1. --8.32raczej niż -8.32*-1. Lub po prostu 8.32...
trichoplax

Cytując OP: Proszę zamieścić jedną wskazówkę na odpowiedź.
nyuszika7h

Zauważ, że in A+=B Bto tuple.
Erik the Outgolfer,

23

Wybór jednej z dwóch liczb na podstawie warunku

Wiesz już, że możesz używać wyboru listy [x,y][b]z wartością logiczną bdla wyrażenia trójskładnikowego y if b else x. Zmienne x, yi bmoże być także wyrażenia, choć pamiętać, że zarówno xi yoceniane są nawet wtedy, gdy nie wybrano.

Oto kilka potencjalnych optymalizacje kiedy xi ysą liczbami.

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

Możesz także przełączyć xi yjeśli możesz przepisać, baby być jego zaprzeczeniem.


22

Użyj ~, aby zindeksować z tyłu listy

Jeśli Ljest to lista, użyj, L[~i]aby uzyskać ten iczwarty element z tyłu.

To jest iczwarty element na odwrocie L. Uzupełnienie bitu ~ijest równe -i-1, a więc naprawia błąd off-by-one z L[-i].


21

PEP448 - Dodatkowe uogólnienia dotyczące rozpakowywania

Wraz z wydaniem Python 3.5 manipulowanie listami, krotkami, setami i dyktami stało się bardziej golfowe.

Przekształcanie iterowalnego zestawu / listy

Porównaj pary:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Znacznie krócej! Pamiętaj jednak, że jeśli chcesz po prostu przekonwertować coś na listę i przypisać ją do zmiennej, normalne rozszerzone iterowalne rozpakowywanie jest krótsze:

L=[*T]
*L,=T

Podobna składnia działa dla krotek:

T=*L,

co jest jak rozszerzone iterowalne rozpakowywanie, ale z gwiazdką i przecinkiem po drugiej stronie.

Łączenie list / krotek

Rozpakowanie jest nieco krótsze niż konkatenacja, jeśli musisz dołączyć listę / krotkę po obu stronach:

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

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

Drukowanie zawartości wielu list

Nie jest to ograniczone do print, ale zdecydowanie jest to, skąd będzie pochodzić większość przebiegów. PEP448 pozwala teraz na wielokrotne rozpakowywanie, tak jak:

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

Aktualizowanie wielu pozycji słownika

Prawdopodobnie nie zdarza się to często, ale można użyć składni, aby zaoszczędzić na aktualizowaniu słowników, jeśli aktualizujesz co najmniej trzy elementy:

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

Zasadniczo neguje to jakąkolwiek potrzebę dict.update.


6
Wygląda to gorzej niż Perl, ale działa ...
Mega Man

20

Zmień import *naimport*


Jeśli nie słyszałeś, import*zapisuje znaki!

from math import*

jest tylko 1 znak dłuższy niż import math as mi możesz usunąć wszystkie wystąpieniam.

Nawet jednorazowe użycie to oszczędność!


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

jeśli wartość i jest bezużyteczna:

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

lub

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

8
Możesz zrobić drugi przykład, for i in[0]*x:s+=input()aby zaoszczędzić kolejne miejsce. Możesz także usunąć spację między exec a pierwszym znakiem cudzysłowu, aby uzyskaćexec's+=input();'*x
Justin Peel,

druga linia nie powinna być:for i in[0]*x:s+=input()
micsthepick

Dupe (nowsze, ale więcej pozytywnych opinii)
user202729
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.