What general tips do you have for golfing in Python? I'm looking for ideas which can be applied to code-golf problems and which are also at least somewhat specific to Python (e.g. "remove comments" is not an answer).
Please post one tip per answer.
184 Answers 184
Use a=b=c=0
instead of a,b,c=0,0,0
. (Note that this uses the same instance for each variable, so don't do this with objects like lists if you intend to mutate them independently)
Use a,b,c='123'
instead of a,b,c='1','2','3'
.
-
4\$\begingroup\$ that's nice tip in general :) \$\endgroup\$user18660– user186602014年03月20日 20:11:46 +00:00Commented Mar 20, 2014 at 20:11
-
44\$\begingroup\$ Note that this will not necessarily work for defining mutable objects that you will be modifying in-place. a=b=[1] is actually different from a=[1];b=[1] \$\endgroup\$izzyg– izzyg2014年04月23日 09:02:46 +00:00Commented Apr 23, 2014 at 9:02
-
8\$\begingroup\$ The funny thing about the first tip is that it works in Java too. \$\endgroup\$Justin– Justin2014年04月24日 07:46:06 +00:00Commented Apr 24, 2014 at 7:46
-
3\$\begingroup\$ @Justin Yes, but only with primitive types \$\endgroup\$2015年09月12日 15:41:49 +00:00Commented Sep 12, 2015 at 15:41
-
28\$\begingroup\$ But NEVER use a=b=c=[] or any object instanciation since all the variables will point to the same instance. That's probably not what you want. \$\endgroup\$PhE– PhE2017年08月22日 13:38:54 +00:00Commented Aug 22, 2017 at 13:38
Conditionals can be lengthy. In some cases, you can replace a simple conditional with (a,b)[condition]
. If condition
is true, then b
is returned.
Compare
if x<y:return a
else:return b
To this
return(b,a)[x<y]
-
61\$\begingroup\$ These aren't exactly the same. The first one evaluates only the expression that is returned while the second one always evaluates them both. These ones do short-circuit:
a if a<b else b
anda<b and a or b
\$\endgroup\$marinus– marinus2011年05月03日 11:34:43 +00:00Commented May 3, 2011 at 11:34 -
7\$\begingroup\$
(lambda(): b, lambda(): a)[a < b]()
make your own short-circuit with lambdas \$\endgroup\$Ming-Tang– Ming-Tang2011年05月07日 23:33:03 +00:00Commented May 7, 2011 at 23:33 -
10\$\begingroup\$ Lambdas are way longer than a conditional expression. \$\endgroup\$user2357112– user23571122014年03月20日 07:07:55 +00:00Commented Mar 20, 2014 at 7:07
-
30\$\begingroup\$ @user2357112 But they make you look so much cooler when you use them. :] \$\endgroup\$Chase Ries– Chase Ries2014年03月20日 09:06:22 +00:00Commented Mar 20, 2014 at 9:06
-
4\$\begingroup\$ Be careful of using this to do recursion, ie.
f = lambda a:(a, f(a-1))[a>1]
because this will evaluate the options before the conditional, unlikef = lambda a: f(a-1) if a>1 else a
, which only executes the recursivef(a-1)
if the conditiona>1
evaluates toTrue
. \$\endgroup\$Ogaday– Ogaday2016年02月16日 12:24:20 +00:00Commented Feb 16, 2016 at 12:24
A great thing I did once is:
if 3 > a > 1 < b < 5: foo()
instead of:
if a > 1 and b > 1 and 3 > a and 5 > b: foo()
Python’s comparison operators rock.
Using that everything is comparable in Python 2, you can also avoid the and
operator this way. For example, if a
, b
, c
and d
are integers,
if a<b and c>d:foo()
can be shortened by one character to:
if a<b<[]>c>d:foo()
This uses that every list is larger than any integer.
If c
and d
are lists, this gets even better:
if a<b<c>d:foo()
-
36\$\begingroup\$ Of course if this were actually golfed it'd be
3>a>1<b<5
\$\endgroup\$Rafe Kettler– Rafe Kettler2011年01月28日 00:35:01 +00:00Commented Jan 28, 2011 at 0:35 -
5\$\begingroup\$ Love the symmetry. Reminds me of the old Perl golf trick for finding the min of $a and $b:
[$a => $b]->[$b <= $a]
:) \$\endgroup\$Simon Whitaker– Simon Whitaker2011年02月03日 21:42:42 +00:00Commented Feb 3, 2011 at 21:42 -
9\$\begingroup\$ The + should be a
*
. Anor
would be+
\$\endgroup\$WorldSEnder– WorldSEnder2014年05月22日 10:53:57 +00:00Commented May 22, 2014 at 10:53 -
2\$\begingroup\$
foo()if 3>a>1<b<5
\$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2016年06月10日 07:31:40 +00:00Commented Jun 10, 2016 at 7:31 -
1\$\begingroup\$ @EriktheOutgolfer
foo()if 3>a>1<b<5
doesn't work for me. \$\endgroup\$Dorian Turba– Dorian Turba2019年12月24日 08:52:58 +00:00Commented Dec 24, 2019 at 8:52
If you're using a built-in function repeatedly, it might be more space-efficient to give it a new name, if using different arguments:
r=range
for x in r(10):
for y in r(100):print x,y
-
12\$\begingroup\$ Didn't actually save any bytes, though. \$\endgroup\$user2357112– user23571122014年03月20日 07:06:44 +00:00Commented Mar 20, 2014 at 7:06
-
9\$\begingroup\$ r=range and the other two r's are 9 characters; using range twice is 10 characters. Not a huge saving in this example but all it would take is one more use of range to see a significant saving. \$\endgroup\$Frank– Frank2016年08月25日 19:52:13 +00:00Commented Aug 25, 2016 at 19:52
-
26\$\begingroup\$ @Frank The additional newline is another character. \$\endgroup\$L3viathan– L3viathan2016年11月14日 20:45:16 +00:00Commented Nov 14, 2016 at 20:45
-
10\$\begingroup\$ Indeed two repetitions is too little to save on a length five function name. You need: length 2: 6 reps, length 3: 4 reps, length 4 or 5: 3 reps, length >=6: 2 reps. AKA (length-1)*(reps-1)>4. \$\endgroup\$Ørjan Johansen– Ørjan Johansen2017年03月18日 16:26:42 +00:00Commented Mar 18, 2017 at 16:26
-
4\$\begingroup\$ @DollarAkshay It works for
str.split
though. \$\endgroup\$enzo– enzo2021年11月25日 17:32:36 +00:00Commented Nov 25, 2021 at 17:32
Use string substitution and exec
to deal with long keywords like lambda
that are repeated often in your 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 (%)
The target string is very often 'lambda '
, which is 7 bytes long. Suppose your code snippet contains n
occurences of 'lambda '
, and is s
bytes long. Then:
- The
plain
option iss
bytes long. - The
replace
option iss - 6n + 29
bytes long. - The
%
option iss - 5n + 22 + len(str(n))
bytes long.
From a plot of bytes saved over plain
for these three options, we can see that:
- For n < 5 lambdas, you're better off not doing anything fancy at all.
- For n = 5, writing
exec"..."%(('lambda ',)*5)
saves 2 bytes, and is your best option. - For n > 5, writing
exec"...".replace('`','lambda ')
is your best option.
For other cases, you can index the table below:
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)
For example, if the string lambda x,y:
(length 11) occurs 3 times in your code, you're better off writing exec"..."%(('lambda x,y:',)*3)
.
-
8\$\begingroup\$ this should get more votes, it's a very useful tip. \$\endgroup\$bigblind– bigblind2013年05月11日 00:18:16 +00:00Commented May 11, 2013 at 0:18
-
13\$\begingroup\$ it's extremely rare that this works. the cost of
replace
is huge. \$\endgroup\$boothby– boothby2013年10月27日 02:09:53 +00:00Commented Oct 27, 2013 at 2:09 -
7\$\begingroup\$ When it does work, though, it helps a lot. \$\endgroup\$undergroundmonorail– undergroundmonorail2014年04月16日 08:28:29 +00:00Commented Apr 16, 2014 at 8:28
-
1\$\begingroup\$ The same applies to
import
- you can dofor s in ('module1','module2','etc'):exec"from %s import*"%s
\$\endgroup\$enedil– enedil2017年07月17日 10:35:55 +00:00Commented Jul 17, 2017 at 10:35 -
20\$\begingroup\$ If you use this often enough for
.replace("R",'.replace("')
to save bytes, many other replacements become cheaper. (It also makes your code entirely unreadable.) \$\endgroup\$Hiatsu– Hiatsu2019年08月28日 18:53:12 +00:00Commented Aug 28, 2019 at 18:53
Sometimes your Python code requires you to have 2 levels of indentation. The obvious thing to do is use one and two spaces for each indentation level.
However, Python 2 considers the tab and space characters to be different indenting levels.
This means the first indentation level can be one space and the second can be one tab character.
For example:
if 1:
if 1:
pass
-
147\$\begingroup\$ This fails in python3: you can no more mix spaces and tabs(a bad thing for codegolf, but a good thing in all other cases). \$\endgroup\$Bakuriu– Bakuriu2013年10月19日 15:41:51 +00:00Commented Oct 19, 2013 at 15:41
-
1\$\begingroup\$ In python 3.4 this seems to work fine. \$\endgroup\$trichoplax is on Codidact now– trichoplax is on Codidact now2016年08月15日 23:09:30 +00:00Commented Aug 15, 2016 at 23:09
-
10\$\begingroup\$ @trichoplax, In python 3.4.3 I get
TabError: inconsistent use of tabs and spaces in indentation.
\$\endgroup\$ceilingcat– ceilingcat2016年10月03日 05:16:08 +00:00Commented Oct 3, 2016 at 5:16 -
2\$\begingroup\$ For reference, a tab is worth 8 spaces. \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2018年06月29日 22:35:31 +00:00Commented Jun 29, 2018 at 22:35
-
3\$\begingroup\$ Note that your editor may be changing the tab characters into space. This happened to me in VSCode. The trick there is to 1) enable whitespace rendering -
"editor.renderWhitespace": "all"
and 2) stop the editor from replacing it with whitespace -"editor.insertSpaces": false, "editor.detectIndentation": false
. (VSCode version 1.46.1). If you want these to work only for the current golfing project, you can add a local settings.json file to the current workspace. \$\endgroup\$MarcinKonowalczyk– MarcinKonowalczyk2020年06月22日 10:11:45 +00:00Commented Jun 22, 2020 at 10:11
Store lookup tables as magic numbers
Say you want to hardcode a Boolean lookup table, like which of the first twelve English numbers contain an 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
Then, you can implement this lookup table concisely as:
3714>>i&1
with the resulting 0
or 1
being equal to False
to True
.
The idea is that the magic number stores the table as a bitstring bin(3714)
= 0b111010000010
, with the n
-th digit (from the end) corresponding the the n
th table entry. We access the n
th entry by bitshifting the number n
spaces to the right and taking the last digit by &1
.
This storage method is very efficient. Compare to the alternatives
n in[1,7,9,10,11]
'0111010000010'[n]>'0'
You can have your lookup table store multibit entries that can be extracted like
340954054>>4*n&15
to extract the relevant four-bit block.
-
1\$\begingroup\$ Could we have an example result for the four-bit block? Did you use a rule for n-bit block? \$\endgroup\$jeromej– jeromej2015年09月14日 08:23:45 +00:00Commented Sep 14, 2015 at 8:23
-
21\$\begingroup\$ Hex might sometimes be even smaller. \$\endgroup\$Joonazan– Joonazan2016年02月03日 21:34:40 +00:00Commented Feb 3, 2016 at 21:34
-
7\$\begingroup\$ This is useful for a lot of languages. \$\endgroup\$Cyoce– Cyoce2016年02月11日 03:50:14 +00:00Commented Feb 11, 2016 at 3:50
-
6\$\begingroup\$ @Joonazan Hex is smaller for numbers over 999 999. \$\endgroup\$Mateen Ulhaq– Mateen Ulhaq2017年06月02日 07:57:34 +00:00Commented Jun 2, 2017 at 7:57
-
2\$\begingroup\$
n in [...]
might be smaller for sparse sets. \$\endgroup\$Solomon Ucko– Solomon Ucko2020年06月09日 00:53:12 +00:00Commented Jun 9, 2020 at 0:53
Use extended slicing to select one string from many
>>> 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 this Boolean two-string case, one can also write
b*"string"or"other_string"
for
["other_string","string"][b]
Unlike interleaving, this works for strings of any length, but can have operator precedence issues if b
is instead an expression.
-
\$\begingroup\$ Note that the first example is exactly the same length as
for x in ("foo","bar","baz"): print x
\$\endgroup\$Mateen Ulhaq– Mateen Ulhaq2017年06月02日 07:21:14 +00:00Commented Jun 2, 2017 at 7:21 -
5\$\begingroup\$ @MateenUlhaq, That's just an example of how the different values of
x
are rendered. The golfed part is the"fbboaaorz"[x::3]
vs["foo","bar","baz"][x]
How thex
value is derived would be another part of your golf solution. \$\endgroup\$gnibbler– gnibbler2017年06月02日 07:31:25 +00:00Commented Jun 2, 2017 at 7:31
Collapse two numerical loops into one
Say you're iterating over the cells of an m*n
grid. Instead of two nested for
loops, one for the rows and one for the columns, it's usually shorter to write a single loop to iterate over the m*n
cells of the grid. You can extract the row and column of the cell inside the loop.
Original code:
for i in range(m):
for j in range(n):
do_stuff(i,j)
Golfed code:
for k in range(m*n):
do_stuff(k/n,k%n)
In effect, you're iterating over the Cartesian product of the two ranges, encoding the pair (i,j)
as x=i*n+j
. You've save a costly range
call and a level of indentation inside the loop. The order of iteration is unchanged.
Use //
instead of /
in Python 3. If you refer to i
and j
many times, it may be shorter to assign their values i=k/n
, j=k%n
inside the loop.
-
5\$\begingroup\$ This is awesome. I had never realised this was possible! \$\endgroup\$user36219– user362192015年04月02日 19:03:20 +00:00Commented Apr 2, 2015 at 19:03
-
1\$\begingroup\$ I saw this in the tips for JavaScript. It's a pretty useful trick in most languages. \$\endgroup\$Cyoce– Cyoce2016年01月12日 06:59:01 +00:00Commented Jan 12, 2016 at 6:59
-
17\$\begingroup\$ For reference, to extend this to 3 loops:
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
\$\endgroup\$mbomb007– mbomb0072016年10月27日 14:48:39 +00:00Commented Oct 27, 2016 at 14:48 -
6\$\begingroup\$ For
n
loops: repl.it/EHwa \$\endgroup\$mbomb007– mbomb0072016年10月27日 16:33:29 +00:00Commented Oct 27, 2016 at 16:33 -
2\$\begingroup\$ In some cases,
itertools.product
can be much more concise than nested loops, especially when generating cartesian products.a1, a2, b1, b2
are examples of the cartesian product of'ab'
and'12'
\$\endgroup\$Aaron3468– Aaron34682018年03月16日 03:24:50 +00:00Commented Mar 16, 2018 at 3:24
Use `n`
to convert an integer to a string instead of using str(n)
:
>>> n=123
>>> `n`
'123'
Note: Only works in Python 2.
-
2\$\begingroup\$ Attention: really works for integers, but not for strings, for example. \$\endgroup\$Nakilon– Nakilon2011年01月28日 00:12:14 +00:00Commented Jan 28, 2011 at 0:12
-
57\$\begingroup\$ btw. `` is short for repr \$\endgroup\$Alexandru– Alexandru2011年01月28日 02:14:37 +00:00Commented Jan 28, 2011 at 2:14
-
16\$\begingroup\$ Integers smaller than -2**31 or bigger than 2**31-1 (Longs) gets an 'L' tacked on at the end. \$\endgroup\$hallvabo– hallvabo2011年01月28日 08:47:16 +00:00Commented Jan 28, 2011 at 8:47
-
8\$\begingroup\$ This can also be used to print floats to full precision \$\endgroup\$gnibbler– gnibbler2013年02月19日 00:28:32 +00:00Commented Feb 19, 2013 at 0:28
For integer n
, you can write
n+1
as-~n
n-1
as~-n
because the bit flip ~x
equals -1-x
. This uses the same number of characters, but can indirectly cut spaces or parens for operator precedence.
Compare:
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
The operators ~
and unary -
are higher precedence than *
, /
, %
, unlike binary +
.
-
24\$\begingroup\$ A variation on this trick I ran into today:
-~-x
saves one byte vs.(1-x)
. \$\endgroup\$lynn– lynn2015年07月15日 11:34:31 +00:00Commented Jul 15, 2015 at 11:34 -
11\$\begingroup\$ Another useful application is that
a+b+1
can be more concisely written asa-~b
. \$\endgroup\$Strigoides– Strigoides2017年01月22日 11:51:33 +00:00Commented Jan 22, 2017 at 11:51 -
5\$\begingroup\$ And
n-i-1
is justn+~i
. \$\endgroup\$ruohola– ruohola2019年06月09日 22:23:10 +00:00Commented Jun 9, 2019 at 22:23
Unless the following token starts with e
or E
. You can remove the space following a number.
For instance:
if i==4 and j==4:
pass
Becomes:
if i==4and j==4:
pass
Using this in complicated one line statements can save quite a few characters.
EDIT: as @marcog pointed out, 4or a
will work, but not a or4
as this gets confused with a variable name.
-
56\$\begingroup\$
if(i,j)==(4,4):
is even shorter and in this special caseif i==j==4:
\$\endgroup\$gnibbler– gnibbler2011年01月28日 00:14:11 +00:00Commented Jan 28, 2011 at 0:14 -
5\$\begingroup\$ Related:
4or a
works, but nota or4
\$\endgroup\$moinudin– moinudin2011年01月28日 00:15:14 +00:00Commented Jan 28, 2011 at 0:15 -
25\$\begingroup\$
0or
also doesn't work (0o
is a prefix for octal numbers). \$\endgroup\$Nabb– Nabb2011年02月02日 17:28:55 +00:00Commented Feb 2, 2011 at 17:28 -
8\$\begingroup\$ @Nabb Not that it matters anyways, since
0 or x
is always gonna returnx
. Might as well cut out the0 or
. \$\endgroup\$ɐɔıʇǝɥʇuʎs– ɐɔıʇǝɥʇuʎs2014年04月06日 12:57:26 +00:00Commented Apr 6, 2014 at 12:57 -
11\$\begingroup\$
0or
is fine as part of a longer number though.10 or x
is equivalent to10or x
. \$\endgroup\$trichoplax is on Codidact now– trichoplax is on Codidact now2014年04月20日 22:39:38 +00:00Commented Apr 20, 2014 at 22:39
A nice way to convert an iterable to list on Python 3:
imagine you have some iterable, like
i = (1,2,3,4)
i = range(4)
i = (x**2 for x in range(5))
But you need a list:
x=list(i) #the default way
*x,=i #using starred assignment -> 4 char fewer
It's very useful to make a list of chars out of a string
s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
-
2\$\begingroup\$ typing
*s,='abcde'
and thens
crashes my interactive python3 with a segfault :( \$\endgroup\$daniero– daniero2015年07月06日 18:41:07 +00:00Commented Jul 6, 2015 at 18:41 -
1\$\begingroup\$ My Python 3.5 works fine. \$\endgroup\$NoOneIsHere– NoOneIsHere2016年03月10日 16:19:13 +00:00Commented Mar 10, 2016 at 16:19
-
1\$\begingroup\$ @george Now try
*x,=i
... \$\endgroup\$JBernardo– JBernardo2016年06月15日 17:31:04 +00:00Commented Jun 15, 2016 at 17:31 -
12\$\begingroup\$ And if you're doing this in an expression, you can do
[*'abcde']
. \$\endgroup\$Esolanging Fruit– Esolanging Fruit2017年06月05日 00:58:31 +00:00Commented Jun 5, 2017 at 0:58 -
1\$\begingroup\$ @Jakob You might be using an older version of Python, because it only works as of version 3.5. \$\endgroup\$Esolanging Fruit– Esolanging Fruit2018年06月30日 02:10:43 +00:00Commented Jun 30, 2018 at 2:10
Extended iterable unpacking ("Starred assignment", Python 3 only)
The best way to explain this is via an example:
>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4
We've already seen a use for this — turning an iterable into a list in Python 3:
a=list(range(10))
*a,=range(10)
Here are a few more uses.
Getting the last element from a list
a=L[-1]
*_,a=L
In some situations, this can also be used for getting the first element to save on parens:
a=(L+[1])[0]
a,*_=L+[1]
Assigning an empty list and other variables
a=1;b=2;c=[]
a,b,*c=1,2
Removing the first or last element of a non-empty list
_,*L=L
*L,_=L
These are shorter than the alternatives L=L[1:]
and L.pop()
. The result can also be saved to a different list.
Tips courtesy of @grc
-
\$\begingroup\$ Wow! I have written
a=1;L=[]
so many times. It's amazing that you can save chars on something so straightforward as this. \$\endgroup\$xnor– xnor2014年12月06日 09:16:55 +00:00Commented Dec 6, 2014 at 9:16 -
\$\begingroup\$ @xnor That one's thanks to grc. With only one other element it's not as good (
a,*L=1,
), but it still saves one char :) \$\endgroup\$Sp3000– Sp30002014年12月06日 09:20:48 +00:00Commented Dec 6, 2014 at 9:20 -
\$\begingroup\$ don't forget you can also get both the first and last element of a list with
a,*_,b=L
\$\endgroup\$Cyoce– Cyoce2016年03月03日 02:59:47 +00:00Commented Mar 3, 2016 at 2:59
Instead of range(x)
, you can use the *
operator on a list of anything, if you don't actually need to use the value of i
:
for i in[1]*8:pass
as opposed to
for i in range(8):pass
If you need to do this more than twice, you could assign any iterable to a variable, and multiply that variable by the range you want:
r=1,
for i in r*8:pass
for i in r*1000:pass
Note: this is often longer than exec"pass;"*8
, so this trick should only be used when that isn't an option.
-
1\$\begingroup\$ @proudhaskeller I think the point of the line you removed was that "In addition to the obvious character savings you get because
[1]*8
is shorter thanrange(8)
, you also get to save a space becausefor i in[...
is legal whilefor i in range...
is not". \$\endgroup\$undergroundmonorail– undergroundmonorail2014年08月18日 17:13:53 +00:00Commented Aug 18, 2014 at 17:13 -
\$\begingroup\$ oh, right, i didn't understand that. fixed now \$\endgroup\$proud haskeller– proud haskeller2014年08月18日 17:30:23 +00:00Commented Aug 18, 2014 at 17:30
-
11\$\begingroup\$
exec"pass;"*8
is significantly shorter. \$\endgroup\$DJMcMayhem– DJMcMayhem2016年05月19日 19:23:15 +00:00Commented May 19, 2016 at 19:23 -
1\$\begingroup\$ if
r=1
,r*8
is 8, and you can't iterate through a number. I guess you meantr=[1]
\$\endgroup\$Miriam– Miriam2019年03月26日 22:58:16 +00:00Commented Mar 26, 2019 at 22:58 -
5\$\begingroup\$ @ArtemisFowl, no it's ok as is, the comma after the 1 creates a tuple which is iterable. \$\endgroup\$AndJM– AndJM2019年06月13日 11:48:04 +00:00Commented Jun 13, 2019 at 11:48
You can use the good old alien smiley face to reverse sequences:
[1, 2, 3, 4][::-1] # => [4, 3, 2, 1]
Use ~ to index from the back of a list
If L
is a list, use L[~i]
to get the i
'th element from the back.
This is the i
'th element of the reverse of L
. The bit complement ~i
equals -i-1
, and so fixes the off-by-one error from L[-i]
.
-
7\$\begingroup\$ Woah, that's so good I wanna use it in real code \$\endgroup\$Zachary Barbanell– Zachary Barbanell2022年08月08日 07:35:41 +00:00Commented Aug 8, 2022 at 7:35
For ages it bothered me that I couldn't think of a short way to get the entire alphabet. If you use range
enough that R=range
is worth having in your program, then
[chr(i+97)for i in R(26)]
is shorter than the naive
'abcdefghijklmnopqrstuvwxyz'
, but otherwise it's longer by a single character. It haunted me that the clever one that required some knowledge of ascii values ended up being more verbose than just typing all the letters.
Until I saw this answer for My Daughter's Alphabet. I can't follow the edit history well enough to figure out if this genius was the work of the OP or if it was a suggestion by a commenter, but this is (I believe) the shortest way to create an iterable of the 26 letters in the Roman alphabet.
map(chr,range(97,123))
If case doesn't matter, you can strip off another character by using uppercase:
map(chr,range(65,91))
I use map
way too much, I don't know how this never occurred to me.
-
4\$\begingroup\$ Might use this in actual coding, I feel so stupid when hardcoding these things :') \$\endgroup\$ToonAlfrink– ToonAlfrink2014年06月07日 19:53:22 +00:00Commented Jun 7, 2014 at 19:53
-
56\$\begingroup\$ In actual coding, use
string.lowercase
-- that's what it's there for. \$\endgroup\$Kevin S– Kevin S2014年08月13日 19:20:16 +00:00Commented Aug 13, 2014 at 19:20 -
2\$\begingroup\$ if you need both cases, the shortest way I know is filter(str.isalpha,map(chr,range(256))). It's just barely shorter than s=map(chr,range(256));s+=map(str.lower,s) \$\endgroup\$quintopia– quintopia2015年11月18日 03:40:57 +00:00Commented Nov 18, 2015 at 3:40
-
\$\begingroup\$ @quintopia: Why 256 instead of 122 (
ord('z')
)? Aside from it being the same length... Also, if you need alphanumerics, replacestr.isalpha
in @quintopia's version withstr.isalnum
. (But if you only need one case, the whole 36-character string is no longer thanfilter(str.isalnum,map(chr,range(90)))
.) \$\endgroup\$Tim Pederick– Tim Pederick2015年12月21日 05:36:36 +00:00Commented Dec 21, 2015 at 5:36 -
5\$\begingroup\$ If you going to be unfair and use range as
R
, my version is shorter than your original one:'%c'*26%tuple(R(97,123))
(only 24 chars) if you spellrange
it is just as long as the alphabet -- uppercase version is shorter \$\endgroup\$JBernardo– JBernardo2017年12月21日 20:26:21 +00:00Commented Dec 21, 2017 at 20:26
Choosing one of two numbers based on a condition
You already know to use the list selection [x,y][b]
with a Boolean b
for the ternary expression y if b else x
. The variables x
, y
, and b
can also be expressions, though note that both x
and y
are evaluated even when not selected.
Here's some potential optimizations when x
and y
are numbers.
[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
(ory-z*b
), where z=y-x.
You can also switch x
and y
if you can rewrite b
to be its negation instead.
-
4\$\begingroup\$ Bonus one:
[-x,~x][b] -> -x-b
\$\endgroup\$touka– touka2022年07月20日 12:41:39 +00:00Commented Jul 20, 2022 at 12:41
set literals in Python2.7
You can write sets like this S={1,2,3}
This also means you can check for membership using {e}&S
instead of e in S
which saves one character.
-
9\$\begingroup\$ And this also saves the character in
if
s as there is no spaces (if{e}&S:
) \$\endgroup\$Artyer– Artyer2017年06月04日 18:43:34 +00:00Commented Jun 4, 2017 at 18:43 -
11\$\begingroup\$ Note that you can replace
not in
by{e}-S
with that trick \$\endgroup\$Kateba– Kateba2018年11月07日 08:20:58 +00:00Commented Nov 7, 2018 at 8:20
When you have two boolean values, a
and b
, if you want to find out if both a
and b
are true, use *
instead of and
:
if a and b: #7 chars
vs
if a*b: #3 chars
if either value is false, it will evaluate as 0
in that statement, and an integer value is only true if it is nonzero.
-
16\$\begingroup\$ Or you could use
&
:a=b=False
,a&b
\$\endgroup\$ɐɔıʇǝɥʇuʎs– ɐɔıʇǝɥʇuʎs2014年04月09日 07:56:11 +00:00Commented Apr 9, 2014 at 7:56 -
4\$\begingroup\$ use
+
foror
if you can guaranteea != -b
\$\endgroup\$undergroundmonorail– undergroundmonorail2015年04月23日 01:18:59 +00:00Commented Apr 23, 2015 at 1:18 -
3\$\begingroup\$
|
works in all situations. \$\endgroup\$CalculatorFeline– CalculatorFeline2017年05月31日 01:30:00 +00:00Commented May 31, 2017 at 1:30 -
1\$\begingroup\$
*
instead ofand
/&&
saves some bytes in many languages. \$\endgroup\$wastl– wastl2018年04月30日 20:48:01 +00:00Commented Apr 30, 2018 at 20:48 -
\$\begingroup\$
*
unfortunately only works if what youre comparing are bool variables, otherwise you need parentheses, which cuts out any savings over usingand
, but I have found that>0<
actually works as anand
, and at least cuts out a byte or two of whitespace \$\endgroup\$des54321– des543212022年03月08日 23:45:40 +00:00Commented Mar 8, 2022 at 23:45
Although python doesn't have very golfable switch statements (the match
/case
syntax since Python 3.10), you can emulate them with dictionaries. For example, if you wanted to golf this:
match a:
case 1: runCodeOne()
case 2: runCodeTwo()
case 3: runCodeThree()
case _: runDefault()
You could use if
statements, or you could use one of these:
# Code as strings
exec{1:"runCodeOne()",2:"runCodeTwo()",3:"runCodeThree()"}[a]
# Functions with non-consecutive indices
{1:runCodeOne,4:runCodeFour,30:runCodeThirty)[a]()
# Functions with consecutive indices
# (you can't add a default value)
(0,runCodeOne,runCodeTwo,runCodeThree)[a]()
# Code as strings (and default code)
exec{ <same as before> }.get(a,"runDefault()")
# Run functions (and default function)
{ <same as before> }.get(a,runDefault)()
This can be used to condense return statements:
# Before
def getValue(k):
if k=='blah':return 1
if k=='foo':return 2
if k=='bar':return 3
return 4
# After
# getValue = ...
lambda k:{'blah':1,'foo':2,'bar':3}.get(k,4)
-
4\$\begingroup\$ This is something i would deeply consider using in the wild. I do so miss my switch statements! +1 \$\endgroup\$HalosGhost– HalosGhost2014年11月19日 12:51:07 +00:00Commented Nov 19, 2014 at 12:51
-
2\$\begingroup\$ Although instead of using a dictionary with numbered keys in the first example, you should just use a list \$\endgroup\$Cyoce– Cyoce2016年10月13日 19:25:11 +00:00Commented Oct 13, 2016 at 19:25
-
2\$\begingroup\$ If you have strings as keys, using
dict(s1=v1,s2=v2,...,sn=vn)
instead of{'s1':v1,'s2':v2,...,'sn':vn}
saves 2*n-4 bytes and is better if n>=3 \$\endgroup\$Kateba– Kateba2018年10月27日 14:13:23 +00:00Commented Oct 27, 2018 at 14:13 -
3\$\begingroup\$ Note that the
match
statement was added in 3.10. python.org/dev/peps/pep-0636 \$\endgroup\$Alan Bagel– Alan Bagel2021年11月03日 15:43:14 +00:00Commented Nov 3, 2021 at 15:43 -
\$\begingroup\$ Extra code can be run with
exec{...}[k];func()
instead of (previously)exec{...}[k]+";func()"
, being 3 bytes shorter \$\endgroup\$smots-18– smots-182024年08月17日 11:03:42 +00:00Commented Aug 17, 2024 at 11:03
PEP448 – Additional Unpacking Generalizations
With the release of Python 3.5, manipulation of lists, tuples, sets and dicts just got golfier.
Turning an iterable into a set/list
Compare the pairs:
set(T)
{*T}
list(T)
[*T]
tuple(T)
(*T,)
Much shorter! Note, however, that if you just want to convert something to a list and assign it to a variable, normal extended iterable unpacking is shorter:
L=[*T]
*L,=T
A similar syntax works for tuples:
T=*L,
which is like extended iterable unpacking, but with the asterisk and comma on the other side.
Joining lists/tuples
Unpacking is slightly shorter than concatenation if you need to append a list/tuple to both sides:
[1]+T+[2]
[1,*T,2]
(1,)+T+(2,)
(1,*T,2)
Printing the contents of multiple lists
This isn't limited to print
, but it's definitely where most of the mileage will come from. PEP448 now allows for multiple unpacking, like so:
>>> T = (1, 2, 3)
>>> L = [4, 5, 6]
>>> print(*T,*L)
1 2 3 4 5 6
Updating multiple dictionary items
This probably won't happen very often, but the syntax can be used to save on updating dictionaries if you're updating at least three items:
d[0]=1;d[1]=3;d[2]=5
d={**d,0:1,1:3,2:5}
This basically negates any need for dict.update
.
-
9\$\begingroup\$ This looks worse than Perl, but it works... \$\endgroup\$univalence– univalence2016年06月25日 05:52:38 +00:00Commented Jun 25, 2016 at 5:52
Ceil and Floor
If you ever want to get the rounded-up result for a division, much like you'd do with //
for floor, you could use math.ceil(3/2)
for 15 or the much shorter -(-3//2)
for 8 bytes.
math.floor(n) : 13 bytes+12 for import
n//1 : 4 bytes
math.ceil(n) : 12 bytes+12 for import
-(-n//1) : 8 bytes
-
3\$\begingroup\$ sometimes you can get away with
n//1+1
instead of ceil but it does mean ceil(n)=n+1 but it should work for all non integer values \$\endgroup\$fejfo– fejfo2017年12月23日 20:26:26 +00:00Commented Dec 23, 2017 at 20:26 -
\$\begingroup\$
round(x)
is(x+.5)//1
, +1 byte but the latter starts with a(
, and ifx
is a sum consisting of a constant it can be useful. \$\endgroup\$user202729– user2027292018年04月28日 05:27:28 +00:00Commented Apr 28, 2018 at 5:27 -
\$\begingroup\$ You can use
0--n//1
. \$\endgroup\$Lucenaposition– Lucenaposition2024年08月19日 00:05:24 +00:00Commented Aug 19, 2024 at 0:05
loops up to 4 items may be better to supply a tuple instead of using range
for x in 0,1,2:
vs
for x in range(3):
Use +=
instead of append
and extend
A.append(B)
can be shortened to:
A+=B,
B,
here creates a one-element tuple which can be used to extend A
just like [B]
in A+=[B]
.
A.extend(B)
can be shortened to:
A+=B
-
5\$\begingroup\$ In many (but not all) cases,
return 0
orreturn 1
is equivalent toreturn False
orreturn True
. \$\endgroup\$undergroundmonorail– undergroundmonorail2014年04月16日 08:30:25 +00:00Commented Apr 16, 2014 at 8:30 -
5\$\begingroup\$ (1) only works if you already know the number is negative, in which case you can save a further 2 characters by simply using a minus sign.
-x
rather thanx*-1
.--8.32
rather than-8.32*-1
. Or just8.32
... \$\endgroup\$trichoplax is on Codidact now– trichoplax is on Codidact now2014年04月20日 22:56:50 +00:00Commented Apr 20, 2014 at 22:56 -
\$\begingroup\$ Quoting the OP: Please post one tip per answer. \$\endgroup\$user344– user3442014年06月23日 13:32:32 +00:00Commented Jun 23, 2014 at 13:32
-
\$\begingroup\$ Note that in
A+=B
B
is atuple
. \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2016年06月10日 07:52:32 +00:00Commented Jun 10, 2016 at 7:52 -
\$\begingroup\$ this can also be used with sets and dicts if you use
|=
in place of+=
\$\endgroup\$des54321– des543212022年03月08日 23:52:34 +00:00Commented Mar 8, 2022 at 23:52
Change import *
to import*
If you haven't heard, import*
saves chars!
from math import*
is only 1 character longer than import math as m
and you get to remove all instances of m.
Even one time use is a saver!
Length tradeoff reference
I've think it would be useful to have a reference for the character count differences for some common alternative ways of doing things, so that I can know when to use which. I'll use _
to indicate an expression or piece of code.
Assign to a variable: +4
x=_;x
_
So, this breaks even if you
- Use
_
a second time:_
has length 5 - Use
_
a third time:_
has length 3
Assign variables separately: 0
x,y=a,b
x=a;y=b
- -2 when
a
equalsb
forx=y=a
Expand lambda
to function def
: +7
lambda x:_
def f(x):return _
- -2 for named functions
- -1 if
_
can touch on the left - -1 in Python 2 if can
print
rather than return - +1 for starred input
*x
Generically, if you're def
to save an expression to a variable used twice, this breaks even when the expression is length 12.
lambda x:g(123456789012,123456789012)
def f(x):s=123456789012;return g(s,s)
STDIN rather than function: +1
def f(x):_;print s
x=input();_;print s
- -1 for line of code needed in
_
if not single-line - +4 if
raw_input
needed in Python 2 - -4 if input variable used only once
- +1 if function must
return
rather thanprint
in Python 2
Use exec
rather than looping over range(n)
: +0
for i in range(n):_
i=0;exec"_;i+=1;"*n
- +2 for Python 3
exec()
- -4 if shifted range
range(c,c+n)
for single-charc
- -5 when going backwards from
n
to1
viarange(n,0,-1)
- -9 if index variable never used
Apply map
manually in a loop: +0
for x in l:y=f(x);_
for y in map(f,l):_
Apply map
manually in a list comprehension: +8
map(f,l)
[f(x)for x in l]
- -12 when
f
must be written in themap
as thelambda
expressionlambda x:f(x)
, causing overall 4 char loss.
Apply filter
manually in a list comprehension: +11
filter(f,l)
[x for x in l if f(x)]
- -1 if
f(x)
expression can touch on the left - -12 when
f
must be written in thefilter
as thelambda
expressionlambda x:f(x)
, causing overall 1 char loss.
Import versus import single-use: +4*
import _;_.f
from _ import*;f
- Breaks even when
_
has length 5 import _ as x;x.f
is always worse except for multiple imports__import__('_').f
is also worse
Thanks to @Sp3000 for lots of suggestions and fixes.
-
4\$\begingroup\$ The "exec" bit goes -9 if you don't need the index. \$\endgroup\$T. Verron– T. Verron2015年10月08日 08:43:20 +00:00Commented Oct 8, 2015 at 8:43
-
1\$\begingroup\$
lambda x:g(123456789012,123456789012)
can be replaced withlambda x:g(a:=123456789012,a)
\$\endgroup\$Lucenaposition– Lucenaposition2024年08月19日 00:10:03 +00:00Commented Aug 19, 2024 at 0:10
A one line function can be done with lambda:
def c(a):
if a < 3: return a+10
else: return a-5
can be converted to (note missing space 3and
and 10or
)
c=lambda a:a<3and a+10or a-5
-
28\$\begingroup\$ or
c=lambda a:a+[-5,10][a<3]
. the and/or trick is more useful when you are depending on the shortcircuit behaviour \$\endgroup\$gnibbler– gnibbler2011年02月03日 13:23:48 +00:00Commented Feb 3, 2011 at 13:23 -
4\$\begingroup\$ In your function,
else:
can be dropped asreturn
stops the execution of the function, so everything that follows is only executed if theif
condition failed, aka if theelse
condition is true. Thuselse
can safely be ommited. (Explained in details for the neophytes out there) \$\endgroup\$jeromej– jeromej2015年09月14日 08:15:58 +00:00Commented Sep 14, 2015 at 8:15 -
1\$\begingroup\$ c(-10) returns -15 while it should return 0 \$\endgroup\$Anvit– Anvit2018年12月05日 07:53:24 +00:00Commented Dec 5, 2018 at 7:53
-
2\$\begingroup\$ or
c=lambda a:a-5+15*(a<3)
\$\endgroup\$JayXon– JayXon2019年08月11日 08:59:18 +00:00Commented Aug 11, 2019 at 8:59
Exploit Python 2 string representations
Python 2 lets you convert an object x
to its string representation `x`
at a cost of only 2 chars. Use this for tasks that are easier done on the object's string than the object itself.
Join characters
Given a list of characters l=['a','b','c']
, one can produce ''.join(l)
as `l`[2::5]
, which saves a byte.
The reason is that `l`
is "['a', 'b', 'c']"
(with spaces), so one can extract the letters with a list slice, starting that the second zero-indexed character a
, and taking every fifth character from there. This doesn't work to join multi-character strings or escape characters represented like '\n'
.
Concatenate digits
Similarly, given a non-empty list of digits like l=[0,3,5]
, one can concatenate them into a string '035'
as `l`[1::3]
.
This saves doing something like map(str,l)
. Note that they must be single digits, and can't have floats like 1.0
mixed in. Also, this fails on the empty list, producing ]
.
Check for negatives
Now, for a non-string task. Suppose you have a list l
of real numbers and want to test if it contains any negative numbers, producing a Boolean.
You can do
'-'in`l`
which checks for a negative sign in the string rep. This shorter than either of
any(x<0for x in l)
min(l+[0])<0
For the second, min(l)<0
would fail on the empty list, so you have to hedge.
-
\$\begingroup\$ Concatenating single digits string slicing is also effective in Python 3, albeit less so:
str(l)[2::5]
is 12 bytes, versus 19 for''.join(map(str,l))
. An actual situation where this came up (wherel
was a generator statement, not a list) saved me just one byte... which is still worth it! \$\endgroup\$Tim Pederick– Tim Pederick2015年12月21日 02:08:39 +00:00Commented Dec 21, 2015 at 2:08 -
\$\begingroup\$ Sadly,
sum
doesn't work for lists of strings. \$\endgroup\$Lucenaposition– Lucenaposition2024年08月18日 00:26:54 +00:00Commented Aug 18, 2024 at 0:26
:=
operator in 3.8 \$\endgroup\$