Python'da golf için ipuçları


248

Python'da golf oynamak için hangi genel ipuçlarınız var? Kod-golf problemlerine uygulanabilecek ve en azından Python'a özgü olan fikirler arıyorum (örneğin, "yorumları kaldır" bir cevap değildir).

Lütfen cevap başına bir ipucu gönderin.


27
Her dil için bir tane bunun gibi bir takım soruları görebiliyorum ...
R. Martinho Fernandes

4
@Marthinho Katılıyorum. C ++ eşdeğerini yeni başlattım . Yine de, bu soru türlerinin çoğunda aynı cevapları tekrarlayan cevapları görmediğimiz sürece, bunun kötü bir şey olduğunu düşünmüyorum.
marcog

50
Soruyu seviyorum ama kendime "Bu SADECE eğlenmek için üretim kodu DEĞİL" "
demeye

2
Bu soru bir topluluk wiki yazısı olmamalıdır mı?
dorukayhan

3
@dorukayhan Hayır; CG'ing amaçları için python kodunu kısaltmak için ipuçlarını isteyen geçerli bir kod-golf ipucu sorusu . Bu tür sorular site için mükemmel şekilde geçerlidir ve bu etiketlerden hiçbiri açıkça, sorunun SO'nun CW'd olmasını gerektiren SO'nun aksine olması gerektiğini açıkça söylemez. Ayrıca, iyi bir cevap yazmak ve bu tür ipuçlarını bulmak her zaman bir şeyi hak eder, eğer soru topluluk wiki ise (rep).
Outgolfer Erik

Yanıtlar:


152

Yerine a=b=c=0kullanın a,b,c=0,0,0.

Yerine a,b,c='123'kullanın a,b,c='1','2','3'.


2
Bu genel olarak güzel bir ipucu :)

28
Bunun, yerinde değiştireceğiniz değişken nesnelerin tanımlanması için mutlaka çalışmayacağına dikkat edin. a = b = [1] aslında a = [1] 'den farklı; b = [1]
isaacg 09.03

6
İlk ipucuyla ilgili komik olan şey, Java'da da çalışması.
Justin,

1
@Justin Evet, ancak yalnızca ilkel türleriyle
HyperNeutrino 12:15

11
Ancak, ASLA a = b = c = [] veya herhangi bir nesneyi kullanmayın, çünkü tüm değişkenler aynı örneği gösterecektir. Muhtemelen istediğin bu değildir.
PhE,

146

Şartlı maddeler uzun olabilir. Bazı durumlarda, basit bir koşullu ile değiştirebilirsiniz (a,b)[condition]. Eğer conditiondoğruysa, o bzaman iade edilir.

Karşılaştırmak

if a<b:return a
else:return b

Buna

return(b,a)[a<b]

37
Bunlar tamamen aynı değil. Birincisi, yalnızca döndürülen ifadeyi, ikincisi her zaman ikisini de değerlendirir. : Bu olanlar kısa devre yapmak a if a<b else bvea<b and a or b
mannus

3
(lambda(): b, lambda(): a)[a < b]()lambdas ile kendi kısa devrenizi yapın
Ming-Tang

3
@ marinus, eşit değiller: sadece P and A or Bveren A'yı düşünün bool(A)=False. Ama (P and [A] or [B])[0]işi yapacak. Referans için diveintopython.net/power_of_introspection/and_or.html adresine bakın .
kgadek

6
Lambdalar şartlı bir ifadeden çok daha uzundur.
user2357112

18
@ user2357112 Ama kullandığınızda çok daha havalı görünmenizi sağlar. :]
Chase,

117

Bir zamanlar yaptığım harika bir şey:

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

onun yerine:

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

Python'un karşılaştırma operatörleri rock.


Python 2'de her şeyin karşılaştırılabilir olduğunu kullanarak, andoperatörü bu şekilde önleyebilirsiniz . Örneğin, eğer a, b, cve dtam sayılardır,

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

bir karakterle kısaltılabilir:

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

Bu, her listenin herhangi bir tam sayıdan daha büyük olduğunu kullanır.

Eğer cve dlisteler ise, bu daha da iyi olur:

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

22
Tabii ki bu gerçekten golf olsaydı, olurdu3>a>1<b<5
Rafe Kettler,

4
Simetriyi seviyorum. Bana $ a ve $ b: min bulmak için eski Perl golf hilesini hatırlatıyor: [$a => $b]->[$b <= $a]:)
Simon Whitaker

İkinci örneğin (liste yok) de yapılabileceğini unutmayınif(a<b)+(c>d):foo()
WorldSEnder

6
+ Bir olmalıdır *. Bir orolur+
WorldSEnder

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

103

Yerleşik bir işlevi tekrar tekrar kullanıyorsanız, farklı argümanlar kullanıyorsanız, yeni bir ad vermek daha az yer kaplar:

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

6
Aslında, herhangi bir bayt kaydetmedi.
user2357112

4
r = aralık ve diğer iki r, 9 karakterdir; aralığın iki kez kullanılması 10 karakterdir. Bu örnekte büyük bir tasarruf değil, tek gereken, önemli bir tasarruf sağlamak için bir aralık daha kullanılmasıdır.
Frank

13
@Frank Eklenen yeni satır başka bir karakterdir.
L3viathan

2
Nitekim, iki tekrar uzunluğu beş işlev adına kaydetmek için çok az. İhtiyacınız olan: uzunluk 2: 6 tekrar, uzunluk 3: 4 tekrar, uzunluk 4 veya 5: 3 tekrar, uzunluk> = 6: 2 tekrar. AKA (uzunluk-1) * (reps-1)> 4.
Ørjan Johansen

Bunun birinci sınıf işlevlere sahip tüm diller için geçerli olduğunu unutmayın.
bfontaine

94

Bazen Python kodunuz 2 girinti seviyesine sahip olmanızı gerektirir. Yapılacak belirgin şey, her girinti seviyesi için bir ve iki boşluk kullanmaktır.

Ancak, Python 2, sekme ve boşluk karakterlerini farklı girinti seviyeleri olarak kabul eder.

Bu, ilk girinti seviyesinin bir boşluk, ikincisi bir sekme karakteri olabileceği anlamına gelir.

Örneğin:

if 1:
 if 1:
\tpass

\tSekme karakteri nerede .


1
Güzel, bunu hiç düşünmedim!
Jules Olléon

97
Bu python3'te başarısız olur: boşluk ve sekmeleri daha fazla karıştıramazsınız (codegolf için kötü bir şey değil, diğer tüm durumlarda iyi bir şey).
Bakuriu

1
Python 3.4'da bunun iyi çalıştığı görülmektedir.
trichoplax

3
@trichoplax , Python olarak 3.4.3 AnladımTabError: inconsistent use of tabs and spaces in indentation.
ceilingcat

Başvuru için, bir sekme 8 boşluk değerindedir.
Outgolfer Erik,

87

Dize değiştirme kullanın ve bu execgibi uzun anahtar kelimelerle baş etmek lambdaiçin kodunuzda sık sık tekrarlayın.

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

Hedef dize çok sık 'lambda ', 7 bayt uzunluğunda. Kod pasajınızın noluşumlarını içerdiğini 'lambda 've sbayt uzunluğunda olduğunu varsayalım . Sonra:

  • plainseçenektirs bayt uzunluğunda.
  • replaceseçenektirs - 6n + 29 bayt uzunluğunda.
  • %Seçenektirs - 5n + 22 + len(str(n)) bayt uzunluğunda.

Kaydedilmiş bir bayt arsadanplain bu üç seçenek için, bunu görebilirsiniz:

  • For n <5 lambda'lar, hiç fantezi bir şey yapmıyorum daha iyi.
  • İçin n = 5 , yazmaexec"..."%(('lambda ',)*5) 2 bayt kazandırır ve en iyi seçenektir.
  • İçin n> 5 , yazı exec"...".replace('`','lambda ')sizin en iyi seçenektir.

Diğer durumlar için aşağıdaki tabloyu indeksleyebilirsiniz:

          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)

Örneğin, dize lambda x,y:(uzunluk 11) kodunuzda 3 kez meydana gelirse, yazmamanız daha iyi olur exec"..."%(('lambda x,y:',)*3).


4
bu daha fazla oy almalı, çok faydalı bir ipucu.
bigblind

7
öyle aşırı çalıştığını nadir. maliyeti replaceçok büyük.
stand

4
İşe yaradığı halde çok yardımcı oluyor.
undergroundmonorail

İlginç, bundan asla haberim bile olmadı!
Claudiu

Dilimde lambda için yeni bir operatör ekledim: python: =>bu sadece bir dizedir = lambda . Örneğin, f=>:0olurdu f = lambda: 0.
NoOneIsHere

78

Birçok dilden bir dize seçmek için genişletilmiş dilimleme kullanın

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

Bu iki Boolean durumda, bir de yazabilirsiniz

b*"string"or"other_string"

için

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

Birleştirmeden farklı olarak, bu, herhangi bir uzunlukta dizeler için işe yarar, ancak bbunun yerine bir ifade ise operatör öncelikli sorunlara sahip olabilir .


İlk örneğin, aynı uzunluktaki olduğuna dikkat edinfor x in ("foo","bar","baz"): print x
Mateen Ulhaq

1
@MateenUlhaq, Farklı değerlerin nasıl oluşturulduğuna sadece bir örnek x. Golf sahası "fbboaaorz"[x::3]vs vs ["foo","bar","baz"][x]Nasıl xdeğer elde edilir golf çözümünüzün başka bir parçası olacaktır.
gnibbler

72

`n`Bir tamsayıyı kullanmak yerine bir dizgeye dönüştürmek için kullanın str(n):

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

38
Güzel, ama Python3 ile çalışmıyor.
Alexandru

2
Dikkat: örneğin tamsayılar için işe yarar ancak dizgiler için işe yaramaz.
Nakilon,

41
Btw. `` Repr için kısa
Alexandru

9
-2 ** 31'den küçük veya 2 ** 31-1'den (Longs) daha büyük tamsayılar, sonunda 'L' yaprağını alır.
hallvabo

6
Bu, yüzdürme tam olarak yazdırmak için de kullanılabilir
gnibbler

69

Arama tablolarını sihirli sayılar olarak saklayın

İlk on iki ingilizce numarasının hangisinde olduğu gibi bir Boolean arama tablosunu kodlamak istediğinizi varsayalım 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

Ardından, bu arama tablosunu tam olarak aşağıdaki gibi uygulayabilirsiniz:

3714>>i&1

ile sonuçlanan 0veya 1ona eşit Falseolmak True.

Fikri sihirli sayısı Bit dizisi olarak tablo depolar olmasıdır bin(3714)= 0b111010000010ile, nkarşılık gelen (sonundan) inci basamak ninci tablosu girdisi. Biz erişmek nsayı bitshifting tarafından inci girişi nsağa boşluklar ve son rakam alınıp &1.

Bu depolama yöntemi çok etkilidir. Alternatiflerle karşılaştır

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

Arama tablonuzun ayıklanabilecek çok bitli girişleri saklamasını sağlayabilirsiniz.

 340954054>>4*n&15

ilgili dört bitlik bloğu çıkartmak için.


Dört bitlik blok için örnek bir sonuç alabilir miyiz? N-bit bloğu için bir kural kullandınız mı?
JeromeJ

8
Hex bazen daha küçük olabilir.
Joonazan,

4
Bu, birçok dil için kullanışlıdır.
30’da Cyoce

1
@Joonazan Hex, 999 999'un üzerindeki numaralar için daha küçüktür .
Mateen Ulhaq

60

İki sayısal döngüyü bir daraltın

Diyelim ki bir m*nızgaranın hücreleri üzerinde yineleniyorsunuz . İki iç içe fordöngü yerine , biri satır için ve sütunlardan biri için m*n, ızgara hücreleri üzerinde yineleme yapmak için tek bir döngü kullanmak genellikle daha kısadır . Döngünün içindeki hücrenin satırını ve sütununu çıkarabilirsiniz.

Orijinal kod:

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

Golf kodu:

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

Sonuç olarak, size çiftini kodlayan iki aralıkları Kartezyen ürün üzerinde yineleme ediyoruz (i,j)olarak x=i*n+j. Pahalı bir rangearama ve döngü içinde bir girinti düzeyi kurtardınız . Yineleme sırası değişmez.

Kullanım //yerine /sen başvurursanız Python 3'te ive jbirçok kez, onların değerlerini atamak için hızlı olabilir i=k/n, j=k%ndöngü içinde.


5
Bu harika. Bunun mümkün olduğunu asla anlamadım!
theonlygusti

Bunu JavaScript ipuçlarında gördüm. Çoğu dilde oldukça faydalı bir numaradır.
Cyoce

7
Başvuru için, bunu 3 döngüye uzatmak için:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007

3
İçin ndöngüler: repl.it/EHwa
mbomb007

Bazı durumlarda, itertools.productözellikle kartezyen ürünler üretirken, iç içe geçmiş halkalardan çok daha özlü olabilir. a1, a2, b1, b2kartezyen çarpım örnekleridir 'ab've'12'
Aaron3468

54

Aşağıdaki simge eveya ile başlamazsa E. Bir sayının ardından boşluğu kaldırabilirsiniz.

Örneğin:

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

Oluyor:

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

Bunu karmaşık bir satır ifadesinde kullanmak epeyce karakter kazandırabilir.

EDIT: @ marcog'un belirttiği gibi 4or a, çalışacak, ancak a or4değişken bir isimle karıştırıldığı için çalışmayacaktır.


37
if(i,j)==(4,4):daha kısa ve bu özel durumda dahaif i==j==4:
gnibbler

3
İlgili: 4or açalışır, ancak değila or4
marcog

17
0orAyrıca çalışmıyor ( 0osekizlik sayılar için bir ön ek).
Nabb

5
@ Nabb Zaten önemli değil, çünkü 0 or xdaima geri dönecek x. Belki de kesebilir 0 or.
12'de

5
0ordaha uzun bir sayının parçası olarak iyi. 10 or xeşittir 10or x.
trichoplax

53

Tamsayı niçin yazabilirsiniz

  • n+1 gibi -~n
  • n-1 gibi ~-n

çünkü bit çevirme ~xeşittir -1-x. Bu, aynı sayıda karakteri kullanır, ancak operatör önceliği için dolaylı olarak boşlukları veya pareleri kesebilir.

Karşılaştırmak:

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

Operatörler ~ve tekli -daha yüksek önceliğe *, /, %ikili sistemin aksine, +.


11
Bugüne koştu Bu hile bir varyasyonu: -~-xtek baytlık ve kaydeder (1-x).
Lynn,

4
Yararlı bir başka uygulama ise, a+b+1daha kısa bir şekilde olduğu gibi yazılabilmesidir a-~b.
Strigoides

Ve n-i-1sadece n+~i.
ruohola

51

Yinelemeli bir listeyi Python 3'te listelemek için güzel bir yol :

hayal edebileceğin bir şey olduğunu hayal et

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

Fakat bir listeye ihtiyacınız var:

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

Bir dizgeden bir karakter listesi yapmak çok yararlıdır.

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

1
yazarak *s,='abcde've sonra sbenim interaktif python3 bir segfault ile çöküyor :(
daniero

@daniero Wow. Sadece etkileşimli konsolda mı? Kulağa çok garip geliyor. Temiz bir konsolda deneyin veya hatayı
bildirin

1
Python 3.5'im iyi çalışıyor.
NoOneIsHere

i = (x ** 2 aralığında x (5)) bu kod <jeneratör nesne <genexpr> 0x03321690 de> geri almak
George

7
Ve bunu bir ifadeyle yapıyorsanız, yapabilirsiniz [*'abcde'].
Esolanging Fruit,

46

Bunun yerine range(x), gerçekte aşağıdakileri kullanmanız *gerekmiyorsa, işleci herhangi bir şeyin listesinde kullanabilirsiniz i:

for i in[1]*8:pass

aksine

for i in range(8):pass

Bunu iki defadan fazla yapmanız gerekirse, bir değişkene yinelenebilir herhangi bir şey atayabilir ve bu değişkeni istediğiniz aralık ile çarpabilirsiniz:

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

Not : Bu genellikle daha uzun exec"pass;"*8, bu hile sadece bir seçenek olmadığı zaman kullanılmalıdır.


@ proudhaskeller Sanırım kaldırdığınız çizginin amacı, "Aldığınız bariz karakter tasarruflarına ek olarak, çünkü [1]*8kısa olduğundan range(8), bir yerden tasarruf edersiniz, çünkü for i in[...yasal olmadığı için yasaldır for i in range..." dır.
undergroundmonorail

oh, doğru, anlamadım. şimdi düzeltildi
gururlu haskeller

7
exec"pass;"*8önemli ölçüde daha kısa.
DJMcMayhem

1
eğer r=1, r*88 ise ve bir sayı ile yinelenemezsiniz. Sanırım demek r=[1]
istedin

1
@ ArtemisFowl, hayır, tamam olduğu gibi, 1'den sonraki virgül yinelenebilir olan bir demet oluşturur.
sasha

43

Sıraları tersine çevirmek için eski güzel gülen yüzünü kullanabilirsiniz:

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

38

Genişletilmiş yinelenebilir açma ("Yıldızlı atama", yalnızca Python 3)

Bunu açıklamanın en iyi yolu bir örnek:

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

Bunun için bir kullanım gördük - yinelemeyi Python 3'te bir listeye dönüştürmek :

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

İşte birkaç kullanım daha.

Listeden son elemanı alma

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

Bazı durumlarda, bu aynı zamanda ebeveynlerden tasarruf sağlayan ilk öğeyi almak için de kullanılabilir:

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

Boş bir liste ve diğer değişkenleri atama

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

Boş olmayan bir listenin ilk veya son öğesini kaldırma

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

Bunlar alternatiflerden daha kısa L=L[1:]ve L.pop(). Sonuç farklı bir listeye de kaydedilebilir.

@Grc'nin izniyle


Vaov! Çok a=1;L=[]defa yazdım . Karakterleri bu kadar basit bir şeye kaydedebilmeniz şaşırtıcı.
xnor

@xnor Bu, birisinin grc'ye teşekkür etmesini sağlar Sadece bir diğer element ile o kadar iyi değil ( a,*L=1,), ama yine de bir char kaydeder :)
Sp3000

Unutma, bir listenin hem ilk hem de son elemanını alabilirsina,*_,b=L
Cyoce

36

hazır bilgi Python2.7 ayarlamak

Bu gibi kümeler yazabilirsiniz. S={1,2,3}Bu, üyeliği kontrol etmek {e}&Syerine, e in Sbir karakterden tasarruf edebileceğiniz anlamına da gelir .


4
Ve bu da ifboşluk if{e}&S:
bırakmadığından

1
Değiştirmek unutmayın not intarafından {e}-So hile ile
Siyah Baykuş Kai

35

Yıllar boyunca, tüm alfabeyi elde etmek için kısa bir yol düşünememesi beni rahatsız etti. Eğer kullanırsanız rangeyeterli olduğunu R=range, ardından programda olan değerdir

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

naiften daha kısa

'abcdefghijklmnopqrstuvwxyz'

, ancak aksi takdirde, tek bir karakterle daha uzun. Bazı ascii değerleri bilgisini gerektiren zekice olanın, sadece tüm harfleri yazmaktan daha ayrıntılı olduğu sonucuna vardım.

Kızımın Alfabesi için bu cevabı görene kadar . Bu dahinin OP'nin işi olup olmadığını ya da bir yorum yapan tarafından bir öneri olup olmadığını anlamak için düzenleme geçmişini yeterince takip edemiyorum, ancak bu 26 harften oluşan bir yineleme oluşturmanın en kısa yoludur (inanıyorum). Roma alfabesinde.

map(chr,range(97,123))

Eğer durum önemli değilse, büyük harf kullanarak başka bir karakteri çıkarabilirsiniz:

map(chr,range(65,91))

Kullandığım mapyolu çok fazla, ben bu hiç aklıma gelmedi bilmiyorum.


4
Bunu gerçek kodlamada kullanabilir, bu gibi şeyler kodlarken çok aptal hissediyorum: ')
ToonAlfrink

37
Gerçek kodlamada, kullan string.lowercase- bunun için orada.
Kevin S

1
Her iki durumda da, bildiğim en kısa yol filtre (str.isalpha, harita (chr, aralık (256))). S = eşlemden (chr, aralık (256)) çok az kısa; s + = eşlem (str.lower, s)
quintopia

@quintopia: Neden 122 ( ord('z')) yerine 256 ? Aynı uzunlukta olması dışında ... Ayrıca, alfanümerik maddelere ihtiyacınız varsa, str.isalpha@ quintopia versiyonunu ile değiştirin str.isalnum. (Ancak yalnızca bir davaya ihtiyacınız olursa, tüm 36 karakterli dize bundan daha uzun değildir filter(str.isalnum,map(chr,range(90))).)
Tim Pederick

2
Eğer haksızlık edecekseniz ve menzili şu şekilde kullanacaksanız R, '%c'*26%tuple(R(97,123))range
sürümüm

32

Python'un anahtar ifadeleri olmamasına rağmen, bunları sözlüklerle taklit edebilirsiniz. Örneğin, böyle bir geçiş yapmak istiyorsanız:

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

ifİfadeleri kullanabilir veya bunu kullanabilirsiniz:

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

veya bu:

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

tüm kod yolları aynı parametrelerle çalışıyorsa bu daha iyidir.

Varsayılan bir değeri desteklemek için şunu yapın:

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

(veya bu:)

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

Bunun bir başka avantajı da fazlalıklarınız varsa, bunları sözlüğün bitiminden sonra ekleyebilmenizdir:

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

Ve sadece bir değeri döndürmek için bir anahtar kullanmak istiyorsanız:

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

Bunu sadece yapabilirsin:

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

2
Bu, vahşi doğada kullanmayı derinden düşüneceğim bir şey. Anahtar deyimlerimi özlüyorum! +1
HalosGhost 19:14

1
Her ne kadar ilk örnekte numaralı tuşlara sahip bir sözlük kullanmak yerine, sadece bir listeyi kullanmalısınız
Cyoce

1
Anahtar olarak dizeleriniz varsa, dict(s1=v1,s2=v2,...,sn=vn)yerine {'s1':v1,'s2':v2,...,'sn':vn}2 * n-4 bayt kaydeder ve n> = 3
Black Owl Kai

31

İki boolean değerlere sahip, zaman ave bhem olmadığını öğrenmek istiyorsanız, ave bdoğru kullanmak *yerine and:

if a and b: #7 chars

vs

if a*b: #3 chars

Değerlerden herhangi biri yanlışsa, bu ifadedeki gibi değerlendirilir 0ve bir tamsayı değeri yalnızca sıfır değilse doğrudur.


9
Yoksa kullanabilirsiniz &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs

3
kullanmak +için orsize garanti edemez eğera != -b
undergroundmonorail

2
|her durumda çalışır.
Hesap MakinesiFeline

1
*bunun yerine and/ &&birçok baytta bazı baytları kaydeder.
Wastl

26

Expt Python 2 string gösterimleri

Python 2, bir nesneyi yalnızca 2 karakter pahasına xdize olarak temsil etmenize olanak sağlar `x`. Bunu, nesnenin dizesinde nesnenin kendisinden daha kolay yapılan işler için kullanın.

Karakterleri birleştir

Karakterlerin bir listesini Verilen l=['a','b','c']bir üretebilir ''.join(l)olarak `l`[2::5]bir bayt kazandırır.

Bunun nedeni ise `l`bir "['a', 'b', 'c']"tane ikinci sıfır endeksli karakter olduğunu başlayarak liste dilim harfleri ayıklamak, böylece (boşluklu) ave oradan her beşinci karakter alarak. Bu, çok karakterli dizelere katılmak veya benzeri şekilde gösterilen karakterlerden kaçmak için çalışmaz '\n'.

Rakamları birleştir

Benzer şekilde, boş olmayan bir basamak listesi göz önüne alındığında l=[0,3,5], bunlardan biri dize '035'olarak birleştirilebilir `l`[1::3].

Bu gibi bir şey yaparak kaydeder map(str,l). Tek basamaklı olmaları gerektiğini ve birbirine 1.0karıştırılmış gibi kayan noktalara sahip olamayacaklarına dikkat edin . Ayrıca, bu boş listede hata veriyor ].

Negatifleri kontrol et

Şimdi, string olmayan bir görev için. lGerçek sayıların bir listeniz olduğunu ve herhangi bir negatif sayı içerip içermediğini test etmek istediğinizi varsayalım .

Yapabilirsin

'-'in`l`

hangi dize rep bir negatif işareti arar. Bu ikisinden de kısa

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

İkincisi, min(l)<0boş listede başarısız olur, bu yüzden riskten korunmanız gerekir.


Tek basamaklı dize dilimlemeyi birleştirmek, Python 3'te daha az da olsa etkilidir: str(l)[2::5]12 bayt, 19'a karşılık ''.join(map(str,l)). Bunun ortaya çıktığı asıl durum ( lbir jeneratör ifadesi, liste değil) beni sadece bir bayt kurtardı ... ki buna hala değer!
Tim Pederick

25

Lambda ile tek satırlık bir fonksiyon yapılabilir:

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

dönüştürülebilir (eksik alanı not edin 3andve 10or)

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

21
veya c=lambda a:a+[-5,10][a<3]. ve / veya püf noktası, kısa devre davranışına bağlı olduğunuzda daha kullanışlıdır
gnibbler

3
Fonksiyonunuzda, fonksiyonun çalışmasını else: durdurarak düşürülebilir return, böylece izleyen her şey sadece ifkoşul başarısız olursa, aka elsekoşul doğruysa gerçekleştirilir. Böylece elsegüvenle atlanabilir. (Oradaki
neofitlerin

c (-10), 0 döndürürken -15
değerini

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

25

4 öğeye kadar olan halkalar, aralık kullanmak yerine bir demet sağlamak için daha iyi olabilir

for x in 0,1,2:

vs

for x in range(3):

24

Tavan ve Döşeme

Herhangi bir bölünme için yuvarlama sonucu elde etmek istiyorsanız, //taban için yaptığınız gibi , math.ceil(3/2)15 veya -(-3//2)8 bayt için daha kısa kullanabilirsiniz .

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
Bu beni 20 bayta yakın kurtardı, teşekkür ederim!
Morgan Thrapp

1
bazen n//1+1
tavan yerine kaçabilirsin

round(x)bir (x+.5)//1+ 1 bayt ancak ile ikinci başlar, (ve eğer xsabit oluşan bir toplamı olan yararlı olabilir.
user202729

23

Yerine +=kullanın appendveextend

A.append(B)  

kısaltılabilir:

A+=B,

B,Burada uzatmak için kullanılabilecek bir tek eleman tuple oluşturur Agibi [B]içinde A+=[B].


A.extend(B)

kısaltılabilir:

A+=B

5
Birçok olarak (ama hepsi değil) olgular, return 0ya return 1eşdeğerdir return Falseya return True.
undergroundmonorail

5
(1) sadece sayının negatif olduğunu zaten biliyorsanız çalışır, bu durumda eksi işaretini kullanarak 2 karakter daha kaydedebilirsiniz. -xyerine x*-1. --8.32yerine -8.32*-1. Ya da sadece 8.32...
trichoplax

OP'den alıntı: Lütfen cevap başına bir ipucu gönderin.
nyuszika7h

Ki dikkat A+=B Bbir olduğunu tuple.
Outgolfer Erik,

23

Bir koşula göre iki sayılardan birini seçme

Sen zaten biliyor listeleri seçim kullanmak için [x,y][b]bir BooleANDile büçlü ifadesi için y if b else x. Değişkenler x, yve bayrıca, ifadeler olabilir nota rağmen her iki xvey hatta değerlendirilir seçili değilken.

İşte rakam xve ne zaman bazı potansiyel optimizasyonlar y.

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

Ayrıca değiştirebilir xve bunun yerine olumsuzlama olarak yyeniden yazabilirsiniz b.


22

Bir listenin arkasından dizine almak için ~ kullanın

Eğer Lbir liste ise, 'elementi arkadan L[~i]almak için kullanın i.

Bu itersinin 'elemanıdır L. Bit tamamlayıcısı ~ieşittir -i-1ve böylece birer birer hatayı düzeltir L[-i].


21

PEP448 - Ek Paketi Açma Genelleştirmeleri

Python 3.5'in piyasaya sürülmesiyle listelerin, tuplelerin, setlerin ve diktelerin manipülasyonu daha da golfe çıktı.

Yinelenebilirleri bir kümeye / listeye dönüştürme

Çiftleri karşılaştırın:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Çok daha kısa! Bununla birlikte, bir şeyi bir listeye dönüştürmek ve bir değişkene atamak istiyorsanız, normal uzatılmış yinelemeli paket açma işleminin daha kısa olduğunu unutmayın:

L=[*T]
*L,=T

Benzer bir sözdizimi tuples için işe yarar:

T=*L,

hangi genişletilmiş tekrarlanabilir açılabilir, ancak diğer tarafta yıldız ve virgül ile.

Listelere / tubalara katılma

Her iki tarafa da bir liste / grup eklemeniz gerekirse, ambalajın açılması birleştirme işleminden biraz daha kısadır:

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

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

Birden çok listenin içeriğini yazdırma

Bu bununla sınırlı değil print, ama kesinlikle kilometrenin çoğunun geleceği yer. PEP448 şimdi olduğu gibi çoklu paket açmaya izin veriyor:

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

Birden çok sözlük öğesinin güncellenmesi

Bu muhtemelen çok sık gerçekleşmeyecektir, ancak sözdizimi en az üç öğe güncelliyorsanız sözlükleri güncellemekten tasarruf etmek için kullanılabilir:

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

Bu temelde herhangi bir ihtiyacı ortadan kaldırmaktadır dict.update.


6
Bu Perl'den daha kötü görünüyor, ama işe yarıyor ...
Mega Man

20

Değişim import *içinimport*


Eğer duymadıysanız, import*karakterleri kurtarır!

from math import*

sadece 1 karakterden daha uzundur import math as mve tüm örneklerini kaldırırsınız.m.

Bir defalık kullanım bile bir tasarruftur!


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

Eğer i değeri işe yaramazsa:

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

veya

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

8
for i in[0]*x:s+=input()Başka bir yerden tasarruf etmek için ikinci örneği yapabilirsiniz . Ayrıca, exec ve almak için ilk tırnak işareti arasındaki boşluğu kaldırabilirsinizexec's+=input();'*x
Justin Peel

İkinci satır olmamalı:for i in[0]*x:s+=input()
micsthepick

Dupe (daha yeni ama daha fazlası)
user202729
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.