Tips for golfing in Python

286

190

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.

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

33Oh, I can see a whole set of questions like this one coming for each language... – R. Martinho Fernandes – 2011-01-28T04:26:45.060

6

@Marthinho I agree. Just started a C++ equivalent. I don't think its a bad thing though, as long as we don't see the same answers re-posted across many of these question types.

– moinudin – 2011-01-28T12:28:11.243

3Shouldn't this question be a community wiki post? – dorukayhan – 2016-05-29T15:35:09.277

4@dorukayhan Nope; it's a valid [tag:code-golf] [tag:tips] question, asking for tips on shortening [tag:python] code for CG'ing purposes. Such questions are perfectly valid for the site, and none of these tags explicitly says that the question should be CW'd, unlike SO, which required CG challenges to be CW'd. Also, writing a good answer, and finding such tips always deserves something, that is taken away if the question is community wiki (rep). – Erik the Outgolfer – 2016-09-09T14:48:14.733

2Use Python 2 for golfing not 3 – Chris_Rands – 2017-08-09T15:04:33.713

@Chris_Rands That simply does not universally hold, as there are cases in which Python 3 allows for shorter submissions. – Jonathan Frech – 2018-07-15T14:36:53.527

@JonathanFrech Especially the new := operator in 3.8 – MilkyWay90 – 2019-03-17T17:31:08.077

58Love the question but I have to keep telling myself "this is ONLY for fun NOT for production code" – Greg Guida – 2011-12-21T00:08:53.377

Answers

182

Use a=b=c=0 instead of a,b,c=0,0,0.

Use a,b,c='123' instead of a,b,c='1','2','3'.

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

1@Justin Yes, but only with primitive types – HyperNeutrino – 2015-09-12T15:41:49.540

18But 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. – PhE – 2017-08-22T13:38:54.130

First part bad, second part good. a, b, and c will all refer to the same thing; changing one will change them all! – Artemis – 2019-03-26T22:29:28.250

2that's nice tip in general :) – None – 2014-03-20T20:11:46.337

34Note 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] – isaacg – 2014-04-23T09:02:46.790

6The funny thing about the first tip is that it works in Java too. – Justin – 2014-04-24T07:46:06.593

167

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 a<b:return a
else:return b

To this

return(b,a)[a<b]

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

2Be 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, unlike f = lambda a: f(a-1) if a>1 else a, which only executes the recursive f(a-1) if the condition a>1 evaluates to True. – Ogaday – 2016-02-16T12:24:20.237

3

@marinus, they are not equal: just consider P and A or B for any A that gives bool(A)=False. But (P and [A] or [B])[0] will do the job. See http://www.diveintopython.net/power_of_introspection/and_or.html for reference.

– kgadek – 2013-04-24T11:01:55.967

1Of course, in this particular case, it can be golfed further to 'return min(a,b)' – Acccumulation – 2018-04-17T20:16:46.017

46These 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 and a<b and a or b – marinus – 2011-05-03T11:34:43.783

4(lambda(): b, lambda(): a)[a < b]() make your own short-circuit with lambdas – Ming-Tang – 2011-05-07T23:33:03.050

7Lambdas are way longer than a conditional expression. – user2357112 supports Monica – 2014-03-20T07:07:55.550

21@user2357112 But they make you look so much cooler when you use them. :] – Chase Ries – 2014-03-20T09:06:22.470

138

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

Juan

Posted 2011-01-27T23:55:58.103

Reputation: 2 908

2foo()if 3>a>1<b<5 – Erik the Outgolfer – 2016-06-10T07:31:40.160

@EriktheOutgolfer foo()if 3>a>1<b<5 doesn't work for me. – Dorian Turba – 2019-12-24T08:52:58.887

Note that the second example (no lists) can also be done with if(a<b)+(c>d):foo() – WorldSEnder – 2014-05-22T10:39:33.763

6The + should be a *. An or would be + – WorldSEnder – 2014-05-22T10:53:57.050

4Love the symmetry. Reminds me of the old Perl golf trick for finding the min of $a and $b: [$a => $b]->[$b <= $a] :) – Simon Whitaker – 2011-02-03T21:42:42.727

27Of course if this were actually golfed it'd be 3>a>1<b<5 – Rafe Kettler – 2011-01-28T00:35:01.783

Perl 6 allows it too – malkaroee – 2014-09-28T22:08:06.940

117

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

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

6r=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. – Frank – 2016-08-25T19:52:13.473

17@Frank The additional newline is another character. – L3viathan – 2016-11-14T20:45:16.057

4Indeed 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. – Ørjan Johansen – 2017-03-18T16:26:42.650

1Note this is applicable to all languages with first-class functions. – bfontaine – 2019-07-19T22:30:16.690

Dosent work for split() function :/ – DollarAkshay – 2019-07-27T06:18:26.947

8Didn't actually save any bytes, though. – user2357112 supports Monica – 2014-03-20T07:06:44.350

109

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:
\tpass

Where \t is the tab character.

JPvdMerwe

Posted 2011-01-27T23:55:58.103

Reputation: 2 724

1In python 3.4 this seems to work fine. – trichoplax – 2016-08-15T23:09:30.550

5@trichoplax, In python 3.4.3 I get TabError: inconsistent use of tabs and spaces in indentation. – ceilingcat – 2016-10-03T05:16:08.700

116This fails in python3: you can no more mix spaces and tabs(a bad thing for codegolf, but a good thing in all other cases). – Bakuriu – 2013-10-19T15:41:51.243

For reference, a tab is worth 8 spaces. – Erik the Outgolfer – 2018-06-29T22:35:31.910

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. – MarcinKonowalczyk – 2020-06-22T10:11:45.247

1Cool, I never thought about this one! – Jules Olléon – 2011-06-24T19:09:58.477

106

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 is s bytes long.
  • The replace option is s - 6n + 29 bytes long.
  • The % option is s - 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).

Ming-Tang

Posted 2011-01-27T23:55:58.103

Reputation: 5 571

I added a new operator for lambda in my language based off of python: => is just the string = lambda. For example, f=>:0 would be f = lambda: 0. – NoOneIsHere – 2016-03-10T16:18:08.733

4this should get more votes, it's a very useful tip. – bigblind – 2013-05-11T00:18:16.543

7it's extremely rare that this works. the cost of replace is huge. – boothby – 2013-10-27T02:09:53.097

The same applies to import - you can do for s in ('module1','module2','etc'):exec"from %s import*"%s – enedil – 2017-07-17T10:35:55.680

6If you use this often enough for .replace("R",'.replace("') to save bytes, many other replacements become cheaper. (It also makes your code entirely unreadable.) – Hiatsu – 2019-08-28T18:53:12.723

5When it does work, though, it helps a lot. – undergroundmonorail – 2014-04-16T08:28:29.597

Interesting, never even tghought of this! – Claudiu – 2014-09-25T22:23:46.053

89

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.

gnibbler

Posted 2011-01-27T23:55:58.103

Reputation: 14 520

Note that the first example is exactly the same length as for x in ("foo","bar","baz"): print x – Mateen Ulhaq – 2017-06-02T07:21:14.953

1@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 the x value is derived would be another part of your golf solution. – gnibbler – 2017-06-02T07:31:25.043

85

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 nth table entry. We access the nth 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.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

Could we have an example result for the four-bit block? Did you use a rule for n-bit block? – jeromej – 2015-09-14T08:23:45.470

13Hex might sometimes be even smaller. – Joonazan – 2016-02-03T21:34:40.143

6This is useful for a lot of languages. – Cyoce – 2016-02-11T03:50:14.210

3

@Joonazan Hex is smaller for numbers over 999 999.

– Mateen Ulhaq – 2017-06-02T07:57:34.620

n in [...] might be smaller for sparse sets. – Solomon Ucko – 2020-06-09T00:53:12.767

79

Use `n` to convert an integer to a string instead of using str(n):

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

Note: Only works in Python 2.

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

46btw. `` is short for repr – Alexandru – 2011-01-28T02:14:37.773

11Integers smaller than -2**31 or bigger than 2**31-1 (Longs) gets an 'L' tacked on at the end. – hallvabo – 2011-01-28T08:47:16.517

6This can also be used to print floats to full precision – gnibbler – 2013-02-19T00:28:32.273

45Nice, but doesn't work with Python3. – Alexandru – 2011-01-28T00:04:15.130

2Attention: really works for integers, but not for strings, for example. – Nakilon – 2011-01-28T00:12:14.407

76

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 row and one of the columns, it's usually shorter to use 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 faster to assign their values i=k/n, j=k%n inside the loop.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

5This is awesome. I had never realised this was possible! – theonlygusti – 2015-04-02T19:03:20.690

I saw this in the tips for JavaScript. It's a pretty useful trick in most languages. – Cyoce – 2016-01-12T06:59:01.547

12For 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) – mbomb007 – 2016-10-27T14:48:39.653

5

For n loops: https://repl.it/EHwa

– mbomb007 – 2016-10-27T16:33:29.110

2In 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' – Aaron3468 – 2018-03-16T03:24:50.847

67

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.

JPvdMerwe

Posted 2011-01-27T23:55:58.103

Reputation: 2 724

If you end a variable name with a number, can you put a variable at the front? – theonlygusti – 2015-04-05T14:57:26.330

@theonlygusti No. – mbomb007 – 2016-02-04T00:51:48.733

6@Nabb Not that it matters anyways, since 0 or x is always gonna return x. Might as well cut out the 0 or. – ɐɔıʇǝɥʇuʎs – 2014-04-06T12:57:26.477

60or is fine as part of a longer number though. 10 or x is equivalent to 10or x. – trichoplax – 2014-04-20T22:39:38.807

190or also doesn't work (0o is a prefix for octal numbers). – Nabb – 2011-02-02T17:28:55.460

45if(i,j)==(4,4): is even shorter and in this special case if i==j==4: – gnibbler – 2011-01-28T00:14:11.750

3Related: 4or a works, but not a or4 – moinudin – 2011-01-28T00:15:14.013

66

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

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

17A variation on this trick I ran into today: -~-x saves one byte vs. (1-x). – Lynn – 2015-07-15T11:34:31.017

8Another useful application is that a+b+1 can be more concisely written as a-~b. – Strigoides – 2017-01-22T11:51:33.570

2And n-i-1 is just n+~i. – ruohola – 2019-06-09T22:23:10.040

66

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'

JBernardo

Posted 2011-01-27T23:55:58.103

Reputation: 1 794

2typing *s,='abcde' and then s crashes my interactive python3 with a segfault :( – daniero – 2015-07-06T18:41:07.490

1My Python 3.5 works fine. – NoOneIsHere – 2016-03-10T16:19:13.937

for i = (x**2 for x in range(5)) I get this code returned <generator object <genexpr> at 0x03321690> – george – 2016-06-15T14:27:58.597

@george Now try *x,=i ... – JBernardo – 2016-06-15T17:31:04.427

@JBernardo thanks! – george – 2016-06-15T17:34:03.370

8And if you're doing this in an expression, you can do [*'abcde']. – Esolanging Fruit – 2017-06-05T00:58:31.047

@EsolangingFruit No you can't. SyntaxError: can use starred expression only as assignment target – Jakob – 2018-06-29T14:55:00.967

@Jakob You might be using an older version of Python, because it only works as of version 3.5.

– Esolanging Fruit – 2018-06-30T02:10:43.990

Oh, cool! Yeah, I was on 3.4. – Jakob – 2018-06-30T02:16:25.300

i = [x**2 for x in range(5)] – Artemis – 2019-03-26T22:55:55.610

56

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.

Blazer

Posted 2011-01-27T23:55:58.103

Reputation: 2 044

@MorganThrapp how does that save bytes over for i in[1]*8:pass? – undergroundmonorail – 2016-02-01T10:19:49.163

9exec"pass;"*8 is significantly shorter. – James – 2016-05-19T19:23:15.173

If this is being used in a list comprehension, this can be used to loop with a variable. Useful in lambdas. What I'm saying is instead of for i in[1]*n:a=(expression);, you do for a in[expression]*n: – Artyer – 2017-06-04T18:41:39.367

1if r=1, r*8 is 8, and you can't iterate through a number. I guess you meant r=[1] – Artemis – 2019-03-26T22:58:16.363

1@ArtemisFowl, no it's ok as is, the comma after the 1 creates a tuple which is iterable. – sasha – 2019-06-13T11:48:04.417

@sasha True, I should've tested it. – Artemis – 2019-06-13T14:12:13.463

1@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 than range(8), you also get to save a space because for i in[... is legal while for i in range... is not". – undergroundmonorail – 2014-08-18T17:13:53.637

oh, right, i didn't understand that. fixed now – proud haskeller – 2014-08-18T17:30:23.403

54

You can use the good old alien smiley face to reverse sequences:

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

Strigoides

Posted 2011-01-27T23:55:58.103

Reputation: 1 085

49

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

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

don't forget you can also get both the first and last element of a list with a,*_,b=L – Cyoce – 2016-03-03T02:59:47.593

Wow! I have written a=1;L=[] so many times. It's amazing that you can save chars on something so straightforward as this. – xnor – 2014-12-06T09:16:55.073

@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 :) – Sp3000 – 2014-12-06T09:20:48.487

43

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.

gnibbler

Posted 2011-01-27T23:55:58.103

Reputation: 14 520

7And this also saves the character in ifs as there is no spaces (if{e}&S:) – Artyer – 2017-06-04T18:43:34.640

5Note that you can replace not in by {e}-S with that trick – Black Owl Kai – 2018-11-07T08:20:58.217

41

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.

undergroundmonorail

Posted 2011-01-27T23:55:58.103

Reputation: 5 937

2if 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) – quintopia – 2015-11-18T03:40:57.897

@quintopia: Why 256 instead of 122 (ord('z'))? Aside from it being the same length... Also, if you need alphanumerics, replace str.isalpha in @quintopia's version with str.isalnum. (But if you only need one case, the whole 36-character string is no longer than filter(str.isalnum,map(chr,range(90))).) – Tim Pederick – 2015-12-21T05:36:36.590

@TimPederick using 256 saves having to look up or remember what ord('z') is ;-) Also, I've learned that import string;string.ascii_letters is actually shorter if you don't mind the lowercase coming before the uppercase letters. – quintopia – 2015-12-21T06:10:30.720

3If 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 spell range it is just as long as the alphabet -- uppercase version is shorter – JBernardo – 2017-12-21T20:26:21.027

4Might use this in actual coding, I feel so stupid when hardcoding these things :') – ToonAlfrink – 2014-06-07T19:53:22.257

43In actual coding, use string.lowercase -- that's what it's there for. – Kevin S – 2014-08-13T19:20:16.517

35

Although python doesn't have switch statements, you can emulate them with dictionaries. For example, if you wanted a switch like this:

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

You could use if statements, or you could use this:

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

or this:

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

which is better if all code paths are functions with the same parameters.

To support a default value do this:

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

(or this:)

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

One other advantage of this is that if you do have redundancies, you could just add them after the end of the dictionary:

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

And if you just wanted to use a switch to return a value:

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

You could just do this:

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

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

1Although instead of using a dictionary with numbered keys in the first example, you should just use a list – Cyoce – 2016-10-13T19:25:11.103

2If 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 – Black Owl Kai – 2018-10-27T14:13:23.023

3This is something i would deeply consider using in the wild. I do so miss my switch statements! +1 – HalosGhost – 2014-11-19T12:51:07.977

34

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.

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

3use + for or if you can guarantee a != -b – undergroundmonorail – 2015-04-23T01:18:59.700

2| works in all situations. – CalculatorFeline – 2017-05-31T01:30:00.127

1* instead of and/&& saves some bytes in many languages. – wastl – 2018-04-30T20:48:01.210

10Or you could use &: a=b=False, a&b – ɐɔıʇǝɥʇuʎs – 2014-04-09T07:56:11.827

34

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

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

31

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 (or y-z*b), where z=y-x.

You can also switch x and y if you can rewrite b to be its negation instead.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

30

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

gnibbler

Posted 2011-01-27T23:55:58.103

Reputation: 14 520

29

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

Alexandru

Posted 2011-01-27T23:55:58.103

Reputation: 5 699

3In your function, else: can be dropped as return stops the execution of the function, so everything that follows is only executed if the if condition failed, aka if the else condition is true. Thus else can safely be ommited. (Explained in details for the neophytes out there) – jeromej – 2015-09-14T08:15:58.273

c(-10) returns -15 while it should return 0 – Anvit – 2018-12-05T07:53:24.530

or c=lambda a:a-5+15*(a<3) – JayXon – 2019-08-11T08:59:18.037

25or c=lambda a:a+[-5,10][a<3]. the and/or trick is more useful when you are depending on the shortcircuit behaviour – gnibbler – 2011-02-03T13:23:48.613

29

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

Juan Cortés

Posted 2011-01-27T23:55:58.103

Reputation: 1 386

6This just saved me close to 20 bytes, thank you! – Morgan Thrapp – 2016-01-13T19:27:20.553

1sometimes 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 – fejfo – 2017-12-23T20:26:26.183

round(x) is (x+.5)//1, +1 byte but the latter starts with a (, and if x is a sum consisting of a constant it can be useful. – user202729 – 2018-04-28T05:27:28.950

28

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

Coding man

Posted 2011-01-27T23:55:58.103

Reputation: 1 235

Note that in A+=B B is a tuple. – Erik the Outgolfer – 2016-06-10T07:52:32.753

5In many (but not all) cases, return 0 or return 1 is equivalent to return False or return True. – undergroundmonorail – 2014-04-16T08:30:25.960

5(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 than x*-1. --8.32 rather than -8.32*-1. Or just 8.32... – trichoplax – 2014-04-20T22:56:50.130

Quoting the OP: Please post one tip per answer. – nyuszika7h – 2014-06-23T13:32:32.740

28

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.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

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 (where l was a generator statement, not a list) saved me just one byte... which is still worth it! – Tim Pederick – 2015-12-21T02:08:39.263

27

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!

Timtech

Posted 2011-01-27T23:55:58.103

Reputation: 12 141

27

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.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

6This looks worse than Perl, but it works... – univalence – 2016-06-25T05:52:38.757

24

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 equals b for x=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 is input variable used only once
  • +1 if function must return rather than print 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-char c
  • -5 when going backwards from n to 1 via range(n,0,-1)

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 the map as the lambda expression lambda 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 the filter as the lambda expression lambda 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.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2The "exec" bit goes -9 if you don't need the index. – T. Verron – 2015-10-08T08:43:20.800

21

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

if value of i is useless:

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

or

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

gmunkhbaatarmn

Posted 2011-01-27T23:55:58.103

Reputation: 467

shouldn't the second line be: for i in[0]*x:s+=input() – micsthepick – 2015-08-05T07:47:20.950

8You can make the second example into for i in[0]*x:s+=input() to save another space. Also, you can remove the space between the exec and the first quotation mark to get exec's+=input();'*x – Justin Peel – 2011-04-19T06:12:41.770

Dupe (newer but more upvotes) – user202729 – 2018-04-17T16:07:20.407

21

Common helper functions

These are some golfed implementations of number theoretic functions that come up in challenges a lot. Many of these are due to xnor, especially the “Wilson’s theorem prime machines” of the form lambda n,i=1,p=1. The coprime/totient functions are Dennis’s (explanation here).

It is instructive to study what exactly these are doing, so that you can adapt them to your needs or roll them into another recursive function. That often ends up being shorter than pasting these directly into your solution as-is!

All of these assume n is a positive integer. The ones marked with an asterisk produce the wrong result if n = 1. Furthermore, these snippets assume Python 2. For Python 3, you might need to replace / by // here and there.

# Function                                                   Output of f(360)
#========================================================================================
f=lambda n,i=2:n/i*[0]and[f(n,i+1),[i]+f(n/i)][n%i<1]      # [2, 2, 2, 3, 3, 5] (slow!)
f=lambda n,i=2:n/i*[0]and f(n,i+1)if n%i else[i]+f(n/i)    # [2, 2, 2, 3, 3, 5]
f=lambda n,i=2:n/i*[0]and(n%i and f(n,i+1)or[i]+f(n/i))    # [2, 2, 2, 3, 3, 5]
f=lambda n,i=2:n<2and{1}or n%i and f(n,i+1)or{i}|f(n/i)    # {1, 2, 3, 5}
f=lambda n,i=2:n<2and{i}or n%i and f(n,i+1)or{i}|f(n/i,i)  #*{2, 3, 5}
f=lambda n,i=2:n/i and[f(n,i+1),i+f(n/i)][n%i<1]           # 2+2+2+3+3+5 (slow!)
f=lambda n,i=2:n/i and f(n,i+1)if n%i else i+f(n/i)        # 2+2+2+3+3+5
f=lambda n,i=2:n/i and(n%i and f(n,i+1)or i+f(n/i))        # 2+2+2+3+3+5
f=lambda n,i=1,p=1:n*[0]and p%i*[i]+f(n-p%i,i+1,p*i*i)     # first n primes
f=lambda n,i=1,p=1:n*[0]and p%i*[i]+f(n-1,i+1,p*i*i)       # primes <= n
f=lambda n,i=1,p=1:n/i and p%i*i+f(n,i+1,p*i*i)            # sum of primes <= n
f=lambda n,i=1,p=1:n/i and p%i+f(n,i+1,p*i*i)              # count primes <= n
f=lambda n,i=1,p=1:n and-~f(n-p%i,i+1,p*i*i)               # nth prime
f=lambda n:all(n%m for m in range(2,n))                    #*is n prime? (not recursive)
f=lambda n:1>>n or n*f(n-1)                                # factorial
f=lambda n:sum(k/n*k%n>n-2for k in range(n*n))             # totient phi(n) (not recursive)
f=lambda n:[k/n for k in range(n*n)if k/n*k%n==1]          # coprimes up to n (not recursive)

Try it online!

Additions and byte saves are very welcome!

Lynn

Posted 2011-01-27T23:55:58.103

Reputation: 58 974

#7 has a redundant space after ). (Also it has a variant similar to #2.) – Ørjan Johansen – 2018-01-04T00:16:59.817

Um ... can f=lambda n:1>>n or n*f(n-1) be lambda n:n<2or n*f(n-1), or am I going crazy? – Zacharý – 2018-11-26T21:09:09.727

1That looks like an acceptable alternative whenever it's acceptable that f(0) == f(1) == True rather than 1. – Lynn – 2018-11-26T23:08:41.910

Oh, totally forgot about that >_<. – Zacharý – 2018-11-28T13:01:50.347

In Python 3.8, from math import perm as f is shorter than factorial definition. and that gives a shorter way to check primality using Wilson's theorem if math is already imported (first used in https://codegolf.stackexchange.com/a/218738/69850, ls mentioned in https://codegolf.stackexchange.com/a/194319/69850)

– user202729 – 2021-02-08T00:38:29.460

20

Arithmetic tricks

Here are some arithmetic tricks which are either shorter or are more useful due to precedence rules.

Assumptions                  Version 1        Version 2
-------------------------------------------------------------------
n >= 0 float                 n==0             0**n
n >= 0 integer               n==0             1>>n
n >  0 integer               n!=1             1%n
n >  0 integer, Python 2     n==1             1/n

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

31//n could still be useful in Python 3 for n==1 since they have different precedence. – mbomb007 – 2015-06-16T21:11:19.820

20

Multiple statements can be put on one line separated by ;. This can save a lot of whitespace from indentation.

while foo(a):
 print a;a*=2

Or even better:

while foo(a):print a;a*=2

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

11you can save one more by putting this one all on one line – gnibbler – 2011-02-03T13:16:17.577

9Not always possible if you have other compound statements like ifs and whiles inside the while. – JPvdMerwe – 2011-10-29T20:23:23.033

20

Printing a string without a trailing newline in Python 3

Suppose you have a string s, and need to print it without a trailing newline. The canonical way of doing this would be

print(s,end='')

However, if we look at the documentation for print, we can see that print takes in a variable number of objects as its first parameter, with "variable number" including zero. This means that we can do

print(end=s)

instead, for a saving of 3 bytes.

Note that this only works when s is a string, since otherwise the conversion to string would be too expensive:

print(1,end='')
print(end=str(1))

Thanks to @Reticality for this tip.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

Note for \`` commenters: \`` does not work in Python 3 (This is a spam prevention comment) – Erik the Outgolfer – 2016-06-25T13:56:01.757

18

Assignment expressions

Assignment expressions are a powerful language feature introduced in Python 3.8 (TIO). Use the "walrus operator" := to assign a variable inline as part of expression.

>>> (n:=2, n+1)
(2, 3)

You can save an expression to a variable inside a lambda, where assignments are not ordinarily allowed. Compare:

def f(s):t=s.strip();return t+t[::-1]
lambda s:s.strip()+s.strip()[::-1]
lambda s:(t:=s.strip())+t[::-1]

An assignment expression can be used in a comprehension to iteratively update a value, storing the result after each step in a list or other collection. This example computes a running sum by updating the running total t.

>>> t=0
>>> l=[1,2,3]
>>> print([t:=t+x for x in l])
[1, 3, 6]
>>> t
6

This can be done in a lambda with the initial value as an optional argument:

>>> f=lambda l,t=0:[t:=t+x for x in l]
>>> f([1,2,3])
[1, 3, 6]

This function is reusable: each call with start t back at 0.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

5This changes everything! – Lynn – 2019-02-23T19:56:46.860

What is Python infamous for? Oh... nevermind. – Erik the Outgolfer – 2019-03-01T22:42:57.820

18

Translating chars in a string

I've seen this situation pop up a few times, so I thought a tip would be good.

Suppose you have a string s and you want to translate some chars of s to other chars (think ROT-13 like ciphers). For a more concrete example, suppose we want to swap just the as and bs in a string, e.g.

"abacus" -> "babcus"

The naïve way to do this would be:

lambda s:s.replace('a','T').replace('b','a').replace('T','b')

Note how we need to introduce a temporary 'T' to get the swapping right.

With eval, we can shorten this a bit:

lambda s:eval("s"+".replace('%s','%s')"*3%tuple("aTbaTb"))

For this particular example, iterating char-by-char gives a slightly better solution (feel free to try it!). But even so, the winner is str.translate, which takes a dictionary of from: to code points:

# Note: 97 is 'a' and 98 is 'b'
lambda s:s.translate({97:98,98:97})

In Python 2 this only works for Unicode strings, so unfortunately the code here is slightly longer:

lambda s:(u''+s).translate({97:98,98:97})

Some important points which make str.translate so useful are:

  • It's easily extendable.
  • Any char not specified is untouched by default, e.g. the "cus" in "abacus" above.
  • The to part of the dictionary can actually be a (Unicode) string as well, e.g. {97:"XYZ"} (u"XYZ" in Python 2) would turn abacus -> XYZbXYZcus. It can also be None, but that doesn't save any bytes compared to "" or u"".

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

1"ab".translate({97:None}) is longer than "ab".translate({97:""}). – T. Verron – 2015-10-08T08:16:29.663

@T.Verron Thanks for pointing that out - I'm not sure why I added that there tbh... – Sp3000 – 2015-10-08T08:24:22.160

The second example you gave can be shortened: replace "aTbaTb" with "aTb"2. Also, you neglected to mention maketrans here, which could significantly shorten translations involving many characters, e.g.: `from string import;t="abcdefghijklmABCDEFGHIJKLMZYXWVUTSRQPONzyxwvutsrqpon";lambda s:s.translate(maketrans(t,t[::-1]))` – quintopia – 2017-08-18T04:05:13.860

14

You only need to indent nested control structures:

def baz(i):
 if i==0:i=1;print i;bar()
 while i:i+=foo(i-1)

boothby

Posted 2011-01-27T23:55:58.103

Reputation: 9 199

14

Safely get the first element

You can check if a possibly-empty list l starts with a value x by doing

l[:1]==[x]

This gives False on an empty list, while l[0]==x gives an out-of-bounds error. Strings works similarly

s[:1]=='a'

In general, you can safely check the n'th element as

l[n:n+1]==[a]

or as l[n:][:1]==[a] when n is a long expression.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

14

If you're doing somewhat more complex golfing that require something from the standard library to be used a lot, import x as y can save some space:

import itertools as i
i.groupby(...) # same as itertools.groupby

Rafe Kettler

Posted 2011-01-27T23:55:58.103

Reputation: 2 357

25You can also do from itertools import *. This uses up 2 more characters, but you hit equal immediately by typing groupby instead of i.groupby. If you use groupby twice, you just saved 2 characters! – Jonathan Sternberg – 2011-01-28T07:52:06.413

7from blah import* (without the last whitespace) is even shorter. – hallvabo – 2011-01-28T08:42:19.190

import* also gets you all the rest of the itertools. I wish it were shorter to use product/combinations/permutations though – gnibbler – 2011-02-03T13:14:31.493

3Yeah, the names in itertools are just way too descriptive, makes me sad. – Clueless – 2011-08-23T21:50:45.547

13

Replace a value in a list

To replace every entry of value a with b in a list L, use:

map({a:b}.get,L,L)

For example,

L=[1,2,3,1,2,3]
a=2
b=3
print map({a:b}.get,L,L)

[1, 3, 3, 1, 3, 3]  #Output

In Python 3, this returns a map object rather than a list. The list entries can be any hashable values (ints, floats, strings, tuples, etc).

Here's how this works. A dictionary's get method takes a key and default value, and returns the dictionary's entry for that key, using the default value is the key is not present. This method is mapped method over each entry in L both as the key and the default value, which results in

[{a:b}.get(x,x) for x in L]

If x is a, then the dictionary transforms it to b, and otherwise, it defaults to itself. You can perform multiple replacements at the same time using a larger dictionary.

Credit to twobit on Anarchy Golf for exposing me to this trick.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

13

Negating Booleans

So you have a Boolean... a real Boolean, not one represented as an integer. You have a condition where it needs to be negated, and you can't just go back and negate it where you got it (e.g. != instead of ==), maybe because you use it once straight and once negated.

Well, who says your Booleans aren't longing to be integers deep in their little hearts?

>>> False < 1
True
>>> True < 1
False

8 bytes, not counting the colon:

if not C:

6 bytes:

if C<1:

EDIT: 5 bytes, thanks to user202729 in the comments:

if~-C:

This works because:

>>> -False
0
>>> -True
-1
>>> ~-False
-1
>>> ~-True
0

Tim Pederick

Posted 2011-01-27T23:55:58.103

Reputation: 1 561

13

Reading multi-line input

In Python 3, the built-in function open underwent some changes. In particular, its first argument

file is either a string or bytes object giving the pathname (absolute or relative to the current working directory) of the file to be opened or an integer file descriptor of the file to be wrapped.

(source)

That means

open(0).read()

suffices to read all input from STDIN.

Try it online on Ideone.

Dennis

Posted 2011-01-27T23:55:58.103

Reputation: 200 652

1... except on Windows :/ (OSError: [WinError 6] The handle is invalid) – Sp3000 – 2016-02-17T07:14:23.293

12

If you represent boolean values as numbers you can save characters. This is especially true for using -1 as True.

Bitty conditionals work (Truth table):

a  b   &  |  ^ 
0  0   0  0  0
0  -1  0 -1 -1
-1 0   0 -1 -1
-1 -1 -1 -1  0

And ~ works as not:

 a ~a
 0 -1
-1  0

Even though the - for initializing -1 costs one character, this can easily save characters overall.

Compare:

while~a:

to:

while not a:

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

12

You can use default arguments of a function to save some indentation, since

def f(a,l=[1,2,3]):
 return sum(a==i for i in l)

is one byte shorter than

def f(a):
 l=[1,2,3]
 return sum(a==i for i in l)

Falko

Posted 2011-01-27T23:55:58.103

Reputation: 5 427

7A small caution: if a list that is passed in as an optional argument is modified in the function (like with pop or l[0] =1), that list will be changed in the outer scope too. – xnor – 2014-08-22T00:14:52.093

1Also, this is only needed if the function body contains nested block statements; otherwise, you can just put everything on one line to avoid indentation. – DLosc – 2014-09-26T01:55:21.083

12

Use extended slicing to select one of two strings

>>> for x in-2,2:print"WoolrlledH"[::x]
... 
Hello
World

vs

>>> for x in 0,1:print["Hello","World"][x]
... 
Hello
World

gnibbler

Posted 2011-01-27T23:55:58.103

Reputation: 14 520

2

Made redundant by http://codegolf.stackexchange.com/a/407/4999

– Cees Timmerman – 2015-05-27T09:37:08.803

12

Just found out two new things. First, input() can parse tuples, like 1, 2, 3 is equivalent to the tuple (1, 2, 3).

And if you need to convert a value to float, just multiply by 1.. Yes, 1. is valid syntax (At least in 2.6).

Juan

Posted 2011-01-27T23:55:58.103

Reputation: 2 908

1To further explicate the point of this answer: in a challenge where input format is flexible, for instance if reading in a bunch of numerical arguments, you can write input() only once. E.g. a,b,c=input() will read in three comma-separated arguments and assign them to a, b, and c – quintopia – 2016-02-01T04:17:30.490

6I think it's worth noting that in Python 2, input(x) is basically the same thing as eval(raw_input(x)). Unsafe to use in practice, but good for code golfing. – C0deH4cker – 2014-01-24T02:33:11.083

2Quoting the OP: Please post one tip per answer. – nyuszika7h – 2014-06-23T13:56:56.960

12

None arguments in Python builtins

map (Python 2 only)

Mapping with None in place of a function assumes the identity function instead. This allows it to be used as an alternative to itertools.izip_longest for zipping lists to the length of the longest list:

>>> L = [[1, 2], [3, 4, 5, 6], [7]]
>>> map(None,*L)
[(1, 3, 7), (2, 4, None), (None, 5, None), (None, 6, None)]

For visualisation (with . representing None):

1 2                1 3 7
3 4 5 6      ->    2 4 .
7                  . 5 .
                   . 6 .

filter

filter with None also assumes the identity function, thus removing falsy elements.

>>> L = ["", 1, 0, [5], [], None, (), (4, 2)]
>>> filter(None, L)
[1, [5], (4, 2)]

This is a bit better than a list comprehension:

filter(None,L)
[x for x in L if x]

However, as @KSab notes, if all elements are of the same type then there may be shorter alternatives, e.g. filter(str,L) if all elements are strings.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

1I had no idea you could do this! In the case of the filter, something similar I have done in the past is filter(str,L) if L is all strings or filter(int,L) if all ints which in some cases could be shorter. – KSab – 2015-05-30T09:18:46.667

12

Use os.read to read all input:

import os
s=os.read(0,1e9)

Which is shorter than

import sys
s=sys.stdin.read()

Note that this has a limitation on input length, but it's so ridiculously large I'd say we're safe from the angry mob.

moinudin

Posted 2011-01-27T23:55:58.103

Reputation: 11 074

1e9 -> 9e9. – Erik the Outgolfer – 2016-06-25T13:52:16.930

2This doesn't work in python2.7/3. The number of bytes to read must be an integer. – Bakuriu – 2013-10-19T15:46:59.790

raw_input isn't available in Python 3 - use int(input()) instead. – None – 2014-01-09T04:31:24.360

1raw_input() is shorter. If you need to read once, just spelling it out is shorter than the import + os.read; if more than once, assign it to a single-character value. – Wooble – 2011-04-30T03:17:59.343

@hosch250: I use raw_input with Python3. – Mathieu Rodic – 2014-03-21T17:47:16.853

@MathieuRodic I tried to use raw_input with my installation, but the program wouldn't compile. It said it wasn't available. Are you sure you aren't using Python 2, or maybe a dual installation? – None – 2014-03-22T18:16:44.100

Maybe it is due to the dual installation indeed... – Mathieu Rodic – 2014-03-22T18:23:47.617

4@Wooble: why use raw_input for golfing? just use input. – Lie Ryan – 2011-09-01T13:54:57.153

1@Lie: good point; although it depends on the problem specification whether having input evaluated would work, you can just stipulate that you're using python 3 (although then your print functions require a bit more space...) – Wooble – 2011-09-01T15:20:57.340

11

Split into chunks

You can split a list into chunks of a given size using zip and iter, as explained in this SO question.

>>> l=range(12)
>>> zip(*[iter(l)]*4)
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]

Of course, substituting in l as zip(*[iter(range(12))]*4) gives the same result.

The 4 is the number of elements per chunk. If the length isn't a multiple of this, any elements in the remainder are not included. For example, l=range(13) would give the same result.

The result is a list of tuples. If your input is a string and you want to produce a list of strings, you can do

>>> l="Code_golf"
>>> map(''.join,zip(*[iter(l)]*3)) 
['Cod', 'e_g', 'olf'] # Python 3 would give a map object

When the list l is defined by a list comprehension, instead of converting to an iterable as iter(l), you can instead write it as a generator comprehension with (...) instead of [...].

>>> l=(n for n in range(18)if n%3!=1)
>>> zip(*[l]*4)
[(0, 2, 3, 5), (6, 8, 9, 11), (12, 14, 15, 17)]

This consumes the generator, so l will appear empty afterwards. Note as before that we can inline l as zip(*[(n for n in range(18)if n%3!=1)]*4).

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

11

map can take multiple iterable arguments and apply the function in parallel.

Instead of

a=[1,4,2,6,4]
b=[2,3,1,8,2]
map(lambda x,y:...,zip(a,b))

you can write

map(lambda x,y:...,a,b)

Jakube

Posted 2011-01-27T23:55:58.103

Reputation: 21 677

I didn't know this and it's super useful! – undergroundmonorail – 2015-02-03T14:59:37.493

11

Use .center in ASCII art

In drawing a symmetrical ASCII art, you can center-justify each line in a fixed width of spaces. For example, "<|>".center(7) gives ' <|> '. This can be shorter than computing how many spaces are needed to center it.

You can also pad with a different character by doing "<|>".center(7,'_')

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2This is actually really cool! – Rɪᴋᴇʀ – 2016-11-05T00:41:55.137

I wish JS had this function... – ETHproductions – 2016-11-05T00:57:37.563

Would f"{'<|>':^7}" not be shorter in python3.6+ for non-variable widths? Even more so when providing the character to center by, f"{'<|>':-^7}" vs "<|>".center(7,"-") – Sam Rockett – 2019-09-13T10:48:06.890

10

If you want to know the type of a variable x:

x*0is 0  # -> integer
x*0==0   # -> float (if the previous check fails)
x*0==""  # -> string
x*0==[]  # -> array

G B

Posted 2011-01-27T23:55:58.103

Reputation: 12 142

10

Binomial coefficient

The binomial coefficient \$\binom{n}{k} \ = \frac{n!}{k!(n-k)!}\$ can be expressed arithmetically as

((2**n+1)**n>>n*k)%2**n

Try it online!

This works for \$n,k \geq 0\$, except for \$n=k=0\$ it gives \$0\$ rather than \$1\$. More generally, it works to use

(b+1)**n/b**k%b

(TIO), where \$b\$ is any value strictly greater than the result. The first expression uses \$b=2^n\$, which exceeds \$\binom{n}{k}\$ except for \$n=k=0\$.


Why does this work? Let's look at an example with b=1000. Then, for n=6, we have

(b+1)**n = 1001 ** 6 = 1006015020015006001

Note how triples of digits encode the binomial coefficients in the n=6 row of Pascal's triangle:

1   6  15  20  15   6   1
1 006 015 020 015 006 001

This works because the binomial coefficients are the coefficients of the polynomial

$$ (b+1)^n = \sum_{k=0}^n\binom{n}{k}b^k$$

and so can be read off as digits in base b, as long no binomial coefficient exceeds b which would cause regrouping.

We can extract a given triple of digits, say for \$\binom{6}{2}=15\$, by floor-dividing by 1000000 to delete the last 6 digits leaving 1006015020015, then take %1000 to extract the last triplet 015. More generally, doing /b**k%b extracts the k-th digit from the end zero-indexed in base b, that is the digit with multiplier b**k.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2Why is this a tip for golfing in Python? Many languages have built-ins for exponentiation. – Peter Taylor – 2018-08-10T12:46:27.773

10

Adding vectors

Python doesn't have a built-in way to do vector (component-wise) addition except with libraries. Say a and b are two equal-length lists of numbers you want to add. Instead of the list comprehension

c=[a[i]+b[i]for i in range(len(a))]

you can use

c=map(sum,zip(a,b))

This produces an annoying map object in Python 3, but it's shorter even if you have to convert to a list.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

map(int.__add__,a,b) is more readable with 1 char longer. – est – 2017-08-22T01:44:05.540

3@est But this is code golf... – user202729 – 2018-04-17T16:17:51.767

10

use os.urandom() as a random source instead of random.randint()

gnibbler

Posted 2011-01-27T23:55:58.103

Reputation: 14 520

3Late to the party, but if you only need a few random numbers, try using id(id), substituting the inner id with any 3-letter builtin if you need more than one. 'abc'[id(id)%3] is 11 characters shorter than 'abc'[random.randrange(3)], not even counting the import statement. – ashastral – 2013-04-20T02:04:59.473

@Fraxtil id can be applied on mostly everything, such as 1 or []. – user202729 – 2018-07-05T09:41:37.407

1Doesn't this require use of ord() to get a number instead of character? len("ord(os.urandom(1))") -> 18 and len("random.randint()") -> 16 – jscs – 2011-05-01T03:10:45.390

3@Josh, don't forget you need to import random vs import os. randint() needs 3 parameters anyway. If you need a list of random numbers, you can use map(ord,os.urandom(N)) Also, sometimes, you actually need a random char instead of a number – gnibbler – 2011-05-01T07:17:40.950

10

Make a mutable matrix

If you want to make a 3*4 grid of zeroes, the natural expression M=[[0]*4]*3 gives an unpleasant surprise if you modify an entry:

>>> M=[[0]*4]*3
>>> M
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> M[0][0]=1
>>> M
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]

Since each row is a copy of the same list by reference, modifying one row modifies all of them, which is usually not the behavior you want.

In Python 2, avoid this with the hack (19 chars):

M=eval(`[[0]*4]*3`)

Doing eval(`_`) converts to the string representation, then re-evaluates it, converting the object to the code of how it's displayed. In effect, it's doing copy.deepcopy.

If you're OK getting a tuple of lists, you can do (18 chars):

M=eval('[0]*4,'*3)

to get ([0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]). This lets you do M[0][0]=1 but not M[0]=[1,2,3,4]. It also works in Python 3.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

what about python3? – micsthepick – 2015-08-05T09:22:22.633

@micsthepick Good question. You can use str for backticks as M=eval(str([[0]*3]*4)). Or, M=[3*[0]for _ in[0]*4] which is the same length. Maybe there's better. – xnor – 2015-08-05T23:19:49.200

10

Store 8-bit numbers compactly as a bytes object in Python 3

In Python 3, a bytes object is written as a string literal preceded by a b, like b"golf". It acts much like a tuple of the ord values of its characters.

>>> l=b"golf"
>>> list(l)
[103, 111, 108, 102]
>>> l[2]
108
>>> 108 in l
True
>>> max(l)
111
>>> for x in l:print(x)
103
111
108
102

Python 2 also has bytes objects but they act as strings, so this only works in Python 3.

This gives a shorter way to express an explicit list of numbers between 0 to 255. Use this to hardcode data. It uses one byte per number, plus three bytes overhead for b"". For example, the list of the first 9 primes [2,3,5,7,11,13,17,19,23] compresses to 14 bytes rather than 24. (An extra byte is used for a workaround explained below for character 13.)

In many cases, your bytes object will contain non-printable characters such as b"\x01x02\x03" for [1, 2, 3]. These are written with hex escape characters, but you may use them a single characters in your code (unless the challenge says otherwise) even though SE will not display them. But, characters like the carriage return b"\x0D" will break your code, so you need to use the two-char escape sequence "\r".

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

10

Avoid startswith

The string method startswith is too long. There are shorter ways to check if a string s starts with a prefix t of unknown length.

t<=s<t+'~'     #Requires a char bigger than any in s,t
s.find(t)==0
s[:len(t)]==t    
s.startswith(t)

The second one is well-suited for the truth/falsity of the negation.

if s.find(t):

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

s[:len(t)]==t is shorter if t has a constant length less than 100000. – Erik the Outgolfer – 2017-06-15T18:48:41.390

9

Use powers of the imaginary unit to calculate sines and cosines.

For example, given an angle d in degrees, you can calculate the sine and cosine as follows:

p=1j**(d/90.)
s=p.real
c=p.imag

This can also be used for related functions such as the side length of a unit n-gon:

l=abs(1-1j**(4./n))

Neil

Posted 2011-01-27T23:55:58.103

Reputation: 116 352

2Does... Does this also become a math golfing tip? o0 – totallyhuman – 2017-10-31T01:14:59.400

9

Iterating over indices in a list

Sometimes, you need to iterate over the indices of a list l in order to do something for each element that depends on its index. The obvious way is a clunky expression:

# 38 chars
for i in range(len(l)):DoStuff(i,l[i])

The Pythonic solution is to use enumerate:

# 36 chars
for i,x in enumerate(l):DoStuff(i,x)

But that nine-letter method is just too long for golfing.

Instead, just manually track the index yourself while iterating over the list.

# 32 chars
i=0
for x in l:DoStuff(i,x);i+=1

Here's some alternatives that are longer but might be situationally better

# 36 chars
# Consumes list
i=0
while l:DoStuff(i,l.pop(0));i+=1

# 36 chars
i=0
while l[i:]:DoStuff(i,l[i]);i+=1

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

9

Use complex numbers to find the distance between two points

Say you have two 2-element tuples which represent points in the Euclidean plane, e.g. x=(0, 0) and y=(3, 4), and you want to find the distance between them. The naïve way to do this is

d=((x[0]-y[0])**2+(x[1]-y[1])**2)**.5

Using complex numbers, this becomes:

c=complex;d=abs(c(*x)-c(*y))

If you have access to each coordinate individually, say a=0, b=0, c=3, d=4, then

abs(a-c+(b-d)*1j)

can be used instead.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

1Only 3 chars longer is d=abs(x[0]-y[0]+(x[1]-y[1])*1j). Can this be made shorter than what you have? I'm just wondering if 1j could be useful in converting a tuple to a complex number. – mbomb007 – 2015-06-16T21:42:55.417

@mbomb007 It depends on what you have I guess. If you need to process the individual numbers in the two tuples anyway, then *1j is usually shorter. – Sp3000 – 2015-06-17T07:25:21.073

In this case, it's the list subscription that's expensive. Consider, instead of x=(0,0);y=(3,4);c=complex;d=abs(c(*x)-c(*y)), different assignments: a,b=0,0;c,d=3,4;d=((a-c)**2+(b-d)**2)**.5. Yes, writing x=0,0;y=3,4 does indeed make the complex option shorter, but using different assignments makes it even shorter: x=0,0;y=3,4;c=complex;d=abs(c(*x)-c(*y). Finally, consider @mbomb007's approach with different assignments: a,b=0,0;x,y=3,4;d=abs(a-x+(b-y)*1j): with or without the assignment, it's shorter than all of the alternatives I've found. – Ogaday – 2016-02-16T13:11:48.173

1@Ogaday This tip's been long overdue for the 1j part, so I've added that in. The general point was basically that ((a-b)**2+(c-d)**2)**.5 is rarely ever needed. – Sp3000 – 2016-02-16T13:32:26.333

9

Leak variables to save on assignment

Combining with this tip, suppose you have a situation like

for _ in[0]*x:doSomething()
a="blah"

You can instead do:

for a in["blah"]*x:doSomething()

to skip out on a variable assignment. However, be aware that

exec"doSomething();"*x;a="blah"

in Python 2 is just shorter, so this only really saves in cases like assigning a char (via "c"*x) or in Python 3.

However, where things get fun is with Python 2 list comprehensions, where this idea still works due to a quirk with list comprehension scope:

[doSomething()for a in["blah"]*x]

(Credits to @xnor for expanding the former, and @Lembik for teaching me about the latter)

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

Does the last one not work in Python 3? – xnor – 2015-06-26T17:29:49.207

@xnor in Python 3 exec requires parentheses, so it would be one character longer than the for... format. – Coty Johnathan Saxman – 2017-07-14T07:10:25.427

9

Avoid list.insert

Instead of list.insert, appending to a slice is shorter:

L.insert(i,x)
L[:i]+=x,

For example:

>>> L = [1, 2, 3, 4]
>>> L[:-2]+=5,
>>> L
[1, 2, 5, 3, 4]
>>> L[:0]+=6,
>>> L
[6, 1, 2, 5, 3, 4]

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

8

Abuse the fact that in case of an expression yielding True boolean operators return the first value that decides about the outcome of the expression instead of a boolean:

>>> False or 5
5

is pretty straightforward. For a more complex example:

>>> i = i or j and "a" or ""

i's value remains unchanged if it already had a value set, becomes "a" if j has a value or in any other case becomes an empty string (which can usually be omitted, as i most likely already was an empty string).

cemper93

Posted 2011-01-27T23:55:58.103

Reputation: 680

3Shorter: i=i or j and"a"or"" – nyuszika7h – 2014-08-18T16:46:24.363

8

Use map for side effects

Usually you use map to transform a collection

>> map(ord,"abc")
[97, 98, 99]

But you can also use it to repeatedly act on object by a built-in method that modifies it.

>> L=[1,2,3,4,5]
>> map(L.remove,[4,2])
[None, None]
>> L
[1, 3, 5]

Be aware that the calls are done in order, so earlier ones might mess up later ones.

>> L=[1,2,3,4,5]
>> map(L.pop,[0,1])
[1, 3]
>> L
[2, 4, 5]

Here, we intended to extract the first two elements of L, but after extracting the first, the next second element is the original third one. We could sort the indices in descending order to avoid this.

An advantage of the evaluation-as-action is that it can be done inside of a lambda. Be careful in Python 3 though, where map objects are not evaluated immediately. You might need an expression like 0in map(...) to force evaluation.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

1

Or [*map(...)].

– user202729 – 2018-07-05T09:31:57.367

8

Use f-strings

Python 3.6 introduces a new string literal that is vastly more byte-efficient at variable interpolation than using % or .format() in non-trivial cases. For example, you can write:

l='Python';b=40;print(f'{l}, {b} bytes')

instead of

l='Python';b=43;print('%s, %d bytes'%(l,b))

Lynn

Posted 2011-01-27T23:55:58.103

Reputation: 58 974

At the time of writing, getting a Python 3.6 pre-release to run on Windows is a more difficult matter... ^^; – Lynn – 2016-03-02T20:05:29.160

1cough ...linux ftw... cough – cat – 2016-03-04T03:08:51.237

If you get MinGW, you could just build from source – cat – 2016-03-04T03:09:36.927

1It's shorter in trivial cases, too. Compare ' '+str(n) (10 bytes) and f' {n}' (7 bytes). – Evpok – 2016-09-08T18:29:15.683

The better comparison would be with ' %d'%n I think, where this example doesn't save any bytes. You do need more args for this to help – Sp3000 – 2016-09-09T06:04:51.867

Also to note, this does not trip up if'foo'==bar: or foo if'bar'else 6 as the if is lex-ed (?) before f''. Also, this helps where % may have lower precedence than other operators, removing the need for brackets. – Artyer – 2016-11-06T20:16:30.403

7

A condition like

s = ''
if c:
    s = 'a'

can be written as

s = c*'a'

and there is possibly a need for parenthesis for condition.

This can also be combined with other conditions as (multiple ifs)

s = c1*'a' + c2*'b'

or (multiple elifs)

s = c1*'a' or c2*'b'

For example FizzBuzz problem's solution will be

for i in range(n):
    print((i%3<1)*"Fizz"+(i%5<1)*"Buzz" or i)

kon psych

Posted 2011-01-27T23:55:58.103

Reputation: 171

7

Check if a number is a power of 2

Check whether a positive integer n is a perfect power of 2, that is one of 1, 2, 4, 8, 16, ..., with any of these expression:

n&~-n<1
n&-n==n
2**n%n<1

This is shorter than converting to binary or using a loop. The last one also works for checking, say, powers of 3.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

7

Lets play with some list tricks

a=[5,5,5,5,5,5,5]

can be written as:

a=[5]*7

It can be expanded in this way. Lets, say we need to do something like

for i in range(0,100,3):a[i]=5

Now using the slicing trick we can simply do:

a[0:100:3]=[5]*(1+99//3)

Wasi

Posted 2011-01-27T23:55:58.103

Reputation: 1 700

4last example, of course, must be written a[:100:3]=[5]*34 – AMK – 2013-12-16T18:57:11.730

3@AMK yap i know ;) But i kept that way cause people may get hard time guessing how i got 34. it just from the formula (1+(100-1)//3) where 100 is number of elements and 3 is the step. Thanks for pointing it :D – Wasi – 2013-12-16T19:03:43.333

7

Use eval to iterate

Say you want to apply f composed k times to the number 1, then print the result.

This can be done via an exec loop,

n=1
exec("n=f(n);"*k)
print(n)

which runs code like n=1;n=f(n);n=f(n);n=f(n);n=f(n);n=f(n);print(n).

But, it's one character shorter to use eval

print(eval("f("*k+'1'+")"*k))

which evaluates code like f(f(f(f(f(1))))) and prints the result.

This does not save chars in Python 2 though, where exec doesn't need parens but eval still does. It does still help though when f(n) is an expression in which n appears only once as the first or last character, letting you use only one string multiplication.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

7

Logical short-circuiting in recursive functions

A detailed guide

I had worked with short-circuiting and/or's for a while without really grasping how they work, just using b and x or y just as a template. I hope this detailed explanation will help you understand them and use them more flexibly.


Recursive named lambda functions are often shorter than programs that loop. For evaluation to terminate, there must be control flow to prevent a recursive call for the base case. Python has a ternary condition operator that fits the bill.

f=lambda x:base_value if is_base_case else recursive_value

Note that list selection won't work because Python evaluates both options. Also, regular if _: isn't an option because we're in a lambda.


Python has another option to short-circuit, the logical operator keywords and and or. The idea is that

True or b == True
False and b == False

so Python can skip evaluate b in these cases because the result is known. Think of the evaluation of a or b as "Evaluate a. If it's True, output a. Otherwise, evaluate and output b." So, it's equivalent to write

a or b
a if a else b

It's the same for a or b except we stop if a is False.

a and b
a if (not a) else b

You might wonder why we didn't just write False if (not a) else b. The reason is that this works for non-Boolean a. Such values are first converted to a Boolean. The number 0, None, and the empty list/tuple/set become False, and are so called "Falsey". The rest are "Truthy".

So, a or b and a and b always manages to produce either a or b, while forming a correct Boolean equation.

(0 or 0) == 0
(0 or 3) == 3
(2 or 0) == 2
(2 or 3) == 2
(0 and 0) == 0
(0 and 3) == 0
(2 and 0) == 0
(2 and 3) == 3
('' or 3) == 3
([] and [1]) == []
([0] or [1]) == [0]

Now that we understand Boolean short-circuiting, let's use it in recursive functions.

f=lambda x:base_value if is_base_case else recursive_value

The simplest and most common situation is when the base is something like f("") = "", sending a Falsey value to itself. Here, it suffices to do x and with the argument.

For example, this function doubles each character in a string, f("abc") == "aabbcc".

f=lambda s:s and s[0]*2+f(s[1:])

Or, this recursively sums the cubes of numbers 1 through n, so f(3)==36.

f=lambda n:n and n**3+f(n-1)

Another common situation is for your function to take non-negative numbers to lists, with a base case of 0 giving the empty list. We need to transform the number to a list while preserving Truthiness. One way is n*[5], where the list can be anything nonempty. This seems silly, but it works.

So, the following returns the list [1..n].

f=lambda n:n*[5]and f(n+1)+[n]  

Note that negative n will also give the empty list, which works here, but not always. For strings, it's similar with any non-empty string. If you've previously defined such a value, you can save chars by using it.

More generally, when your base value is an empty list, you can use the arithmetic values True == 1 and False == 0 to do:

[5]*(is_not_base_case)and ...

TODO: Truthy base value


TODO: and/or

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

An easy way to explain how and and or work might be:
x or y=if x:return x;return y
x and y:if x:return y;return x
– fejfo – 2018-01-11T19:47:26.363

7

One trick I have encountered concerns returning or printing Yes/No answers:

 print 'YNeos'[x::2]

x is the condition and can take value 0 or 1.

I found this rather brilliant.

Richie Lee

Posted 2011-01-27T23:55:58.103

Reputation: 71

3

Welcome to PPCG! It seems that this is mostly a special case of this tip though.

– Martin Ender – 2016-04-14T16:26:50.600

7

Object method as answer

Your submission can be a method of an object

range(123,790,111).count

This defines an anonymous function much shorter than

lambda n:range(123,790,111).count(n)

The object method is a valid function that meets our definition. For example, it could be bound and called

f=range(123,790,111).count
print f(99)

Because it avoids a costly lambda, this saves characters even rewriting from

lambda n:n in range(123,790,111)

Consider using an object method when your solution is a simple two-input function of your input and some concrete object. You can use dir() to get a list of methods of an object. Note in particular methods like .__add__ that are called for an operator like +. Most infix operators correspond to a method.

Other examples:

"prefix{}suffix".format
lambda s:"prefix"+s+"suffix"

2 .__rpow__    #Space for lexer
lambda n:n*n

[0,0].__le__
lambda l:[0,0]<=l

["North","East","South","West"].pop
lambda n:["North","East","South","West"][n]

You can even something save bytes with two input by currying. For example, compare

lambda l:expression_in_l.count
lambda n,l:n in expression_in_l

where expression_in_l produces a list with no duplicates and has favorable spacing and precedence.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2["North","East","South","West"].pop a function submission must work multiple times, no? using .__getitem__ would do the trick, but the length would be the same – Felipe Nardi Batista – 2017-07-12T13:51:53.483

6

When mapping a function on a list in Python 3, instead of doing [f(x)for x in l] or list(map(f,l)), do [*map(f,l)].

It works for all other functions returning generators too (like filter).

The best solution is still switching to Python 2 though

TuxCrafting

Posted 2011-01-27T23:55:58.103

Reputation: 4 699

6

Multiple if statements in comprehensions

If you need to keep multiple conditions inside comprehension, you can replace and with if to save a byte each time.

Works in Python 2 and 3.

[a for a in 'abc'if cond1()and cond2()or cond3()and cond4()and cond5()]
[a for a in 'abc'if cond1()if cond2()or cond3()if cond4()if cond5()]

Try it online!

Dead Possum

Posted 2011-01-27T23:55:58.103

Reputation: 3 296

6

List comprehension.

shortList = []
for x in range(10):
    shortList += [x * 2]

can be shortened into

shortList = [x*2 for x in range(10)]

Or even shorter:

shortList = range(0,20,2)

zhazam

Posted 2011-01-27T23:55:58.103

Reputation: 191

Can even be shortened (by a character) to [x**2for x in range(10)] – TerryA – 2013-05-13T11:31:55.237

@Haidro I think you mean [x*2for x in range(10)] – Timtech – 2013-12-08T17:58:21.033

@Timtech You are right :) – TerryA – 2013-12-08T19:13:54.717

6

If you are doing something small in a for loop whose only purpose is to invoke a side effect (pop, print in Python 3, append), it might be possible to translate it to a list-comprehension. For example, from Keith Randall's answer here, in the middle of a function, hence the indent:

  if d>list('XXXXXXXXX'):
   for z in D:d.pop()
   c=['X']

Can be converted to:

  if d>list('XXXXXXXXX'):
   [d.pop()for z in D]
   c=['X']

Which then allows this golf:

  if d>list('XXXXXXXXX'):[d.pop()for z in D];c=['X']

An if within a for works just as well:

for i in range(10):
 if is_prime(i):d.pop()

can be written as

[d.pop()for i in range(10)if is_prime(i)]

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

5

Format() works on dates:

"We are in year: %s" % (date.strftime('%y'))

Becomes:

"We are in year: {:%y}".format(date)

Or even better with f-strings:

f"We are in year: {date:%y}"

e-satis

Posted 2011-01-27T23:55:58.103

Reputation: 161

5

Sometimes you need convert boolean expression into integer (0/1) Simple use this Boolean (in examples below c > 0) in ariphmetic

a=b+(c>0)
a+=c>0
a=sum(c>0 for c in b) # space in "0 for" may be omitted

And sometimes you need simple convert boolean to int (for example for printing or convert to binary string). In programm you may use some variants

1 if c>0 else 0
c>0and 1or 0
(0,1)[c>0]
int(c>0)

but shortest way is

+(c>0)

AMK

Posted 2011-01-27T23:55:58.103

Reputation: 624

7I find +c being shorter. E.g. let c be a boolean, then 4+c is 5 if c is True else 4. – MyGGaN – 2014-02-25T23:41:40.510

5

Math built-ins in 3.8

In addition to the famous walrus operator, Python 3.8 introduces useful new math features.

Modular inverse

The modular-power built-in pow(base, exp, mod) can now compute the modular inverse using exp=-1. This requires that base and mod are relatively prime integers.

>>> pow(38, -1, 97)
23
>>> 23 * 38 % 97 == 1
True

exp may be any negative integer, which lets you compute modular powers of the modular inverse.


The math library has useful new functions for combinatorics and distances. Access them with import math. Or, write from math import* to import them without the math., which is worth it if you write more than one call.

Combinatorics

  • math.comb(n,k): The binomial coefficient n choose k, which equals n! / (k! * (n - k)!).
  • math.perm(n,k): The number of ordered choices of k elements from n, which is n! / (n - k)!. Calling just math.perm(n) gives n!, useful as a synonym for math.factorial(n).
  • math.prod(l): The product of the elements of a list or iterable l, analogous to sum.

Distances and square roots

  • math.dist(p,q): The Euclidean distance between two points p and q. The inputs p and q must be lists or iterables that are the same length.
  • math.hypot(*p): The Euclidean distance from a point p to zero. Now takes any number of arguments; before it took only two. For some reason, arguments still must be splatted like math.hypot(1,2,3) rather than math.hypot([1,2,3]).
  • math.isqrt(n): The integer square root, that is the floor of the square root of n. Requires than n is a non-negative integer. Usually n**.5//1 suffices instead, but this gives exact integer output rather than a float.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

5

Cut out newlines wherever you can.

At the top-level, it doesn't matter.

a=1
b=9

Takes the same amount of characters as:

a=1;b=9

In the first case you have a newline instead of a ;. But in function bodies, you save however deep the nesting level is:

def f():
 a=1;b=9

Actually in this case, you can have them all on one line:

def f():a=1;b=9

If you have an if or a for, you can likewise have everything on one line:

if h:a=1;b=9
for g in(1,2):a=1;b=9

But if you have a nesting of control structures (e.g. if in a for, or if in a def), then you need the newline:

if h:for g in(1,2):a=1;b=9 #ERROR

if h:
 for g in(1,2):a=1;b=9 # SAUL GOODMAN

Claudiu

Posted 2011-01-27T23:55:58.103

Reputation: 3 880

You can use a,b=1,9 – Oliver Ni – 2015-01-04T01:24:21.017

It's too bad you can't have multiple :s on one line :( – CalculatorFeline – 2017-05-28T05:35:43.060

@OliverNi a,b=1,9 does not save any bytes – Felipe Nardi Batista – 2017-07-12T14:40:51.023

5

Build a string instead of joining

To concatenate strings or characters, it can be shorter to repeatedly append to the empty string than to join.

23 chars

s=""
for x in l:s+=f(x)

25 chars

s="".join(f(x)for x in l)

Assume here that f(x) stands for some expression in x, so you can't just map.

But, the join may be shorter if the result doesn't need saving to a variable or if the for takes newlines or indentation.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

5

String keys to dicts

For a dictionary with string keys which also happen to be valid Python variable names, you can get a saving if there's at least three items by using dict's keyword arguments:

{'a':1,'e':4,'i':9}
dict(a=1,e=4,i=9)

The more string keys you have, the more quote characters you'll save, so this is particularly beneficial for large dictionaries (e.g. for a kolmogorov challenge).

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

5

When squaring single letter variables, it is shorter to times it by itself

>>> x=30
>>> x*x
900

Is one byte shorter than

>>> x=30
>>> x**2
900

Beta Decay

Posted 2011-01-27T23:55:58.103

Reputation: 21 982

5

Iterate over adjacent pairs

It's common to want to iterate over adjacent pairs of items in a list or string, i.e.

"golf" -> [('g','o'), ('o','l'), ('l','f')]

There's a few methods, and which is shortest depends on specifics.

Shift and zip

## 47 bytes
l=input()
for x,y in zip(l,l[1:]):do_stuff(x,y)

Create a list of adjacent pairs, by removing the first element and zipping the original with the result. This is most useful in a list comprehension like

sum(abs(x-y)for x,y in zip(l,l[1:]))

You can also use map with a two-input function, though note that the original list is no longer truncated.

## Python 2
map(cmp,l[:-1],l[1:])

Keep the previous

## 41 bytes, Python 3
x,*l=input()
for y in l:do_stuff(x,y);x=y

Iterate over the elements of the list, remembering the element from a previous loop. This works best with Python 3's ability to unpack to input into the initial and remaining elements.

If there's an initial value of x that serves as a null operation in do_stuff(x,y), you can iterate over the whole list.

## 39 bytes
x=''
for y in input():do_stuff(x,y);x=y

Truncate from the front

## 46 bytes
l=input()
while l[1:]:do_stuff(*l[:2]);l=l[1:]

Keep shortening the list and act on the first two elements. This works best when your operation is better-expressed on a length-two list or string than on two values.


I've written these all as loops, but they also lend to a recursive functions. You can also adjust to get cyclic pairs by putting the first element at the end of the list, or as the initial previous-value.


The Python 3.8 "walrus" assignment expressions allow a short expression to give pairs, though with an extra initial element.

>>> p=''
>>> [(p,p:=c)for c in"golf"]
[('', 'g'), ('g', 'o'), ('o', 'l'), ('l', 'f')]

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

4

If transforming from list to a tuple or set to a set, list or tuple is needed, as of Python 3.5 you can use the splat operator:

tuple(iterable) -> (*iterable,)  (-3 bytes)
set(iterable)   -> {*iterable}   (-2 bytes)
list(iterable)  -> [*iterable]   (-3 bytes)

If you're doing this as well as appending/prepending, you can do the following for an extra bonus:

iterable+[1]       -> *iterable,1          (-2 bytes, 3 for tuples)
iterable+iter2     -> *iterable,*iterable2 (+1 byte, 0 for tuples, though can combine types)
[1]+iterable+[1]   -> 1,*iterable,1        (-3 bytes, -4 for tuples)
iterable+[1]+iter2 -> *iterable,1,*iter2   (0 bytes, -1 for tuples)

Basically, ,* instead of , gives a +1 byte penalty and , instead of ,[] gives -2 bytes.

This shows [1,*iterable,1] is a golfier way of doing [1]+iterable+[1] by one byte, even when we're not doing any type conversion.

And just for fun, {*{}} is the same length as set() for challenges without letters.

Blue

Posted 2011-01-27T23:55:58.103

Reputation: 27 508

1The last one can also be useful if there is a letter preceding set() (e.g. ...and set() can become ...and{*{}}). Oh, and it can be replaced with {*()} or {*[]} if an empty dict feels unsettling. ;-) – Erik the Outgolfer – 2018-06-29T22:37:52.700

4

Difference of two parallel expressions

Say you have a challenge to find the difference of some characteristic on two inputs. Your solution has the form lambda a,b:e(b)-e(a), where e is some long expression you've written. Repeating e twice is wasteful, so what do you do?

Here are templates sorted by length. Assume that e stands for a long expression, not one that's already defined as a function. Also assume inputs can be taken in either order.

31 bytes*

lambda*l:eval('e(%s)-'*2%l+'0')

*Requires that e only mentions its variable once. Assumes -e(x) negates the whole expression, otherwise requires parens like -(e(x)) for two more bytes.

34 bytes

f=lambda a,*b:e(a)-(b>()and f(*b))

36 bytes

lambda a,b:d(b)-d(a)
d=lambda x:e(x)

36 bytes

a,b=[e(x)for x in input()]
print b-a

37 bytes

r=0
for x in input():r=e(x)-r
print r

39 bytes

lambda*l:int.__sub__(*[e(x)for x in l])

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

4

Use Splat (*) to pass a bunch of single character strings into a function

For example:

a.replace("a","b")
a.replace(*"ab")    -2 bytes

some_function("a","b","c")
some_function(*"abc")       -5 bytes

In fact, if you have n single-character strings, you will save 3(n - 1) - 1 or 3n - 4 bytes by doing this (because each time, you remove the "," for each one and add a constant *).

HyperNeutrino

Posted 2011-01-27T23:55:58.103

Reputation: 27 328

4

Formatting a Matrix

I've seen this code to get a character matrix (2D array) as a string.

'\n'.join(''.join(i)for i in M)

It's shorter to use a map instead:

'\n'.join(map(''.join,M))

If you're printing the result, it's shortest to use a for loop:

print('\n'.join(map(''.join,M)))
for i in M:print(*i,sep='')      # -5 bytes

If you're using Python 2, you can't use the print trick, but you can still use the for loop:

for i in M:print(''.join(i))     # -3 bytes

Esolanging Fruit

Posted 2011-01-27T23:55:58.103

Reputation: 14 090

4

Be aware of all, any and map:

if isdigit(a) and isdigit(b) and isdigit(c)
if all(map(isdigit,[a,b,c]))

Martin Thoma

Posted 2011-01-27T23:55:58.103

Reputation: 679

1Over a year later, I'm reading this thread again and I'm embarrassed about my previous comment. if filter(isdigit,[a,b,c]) is not equivalent to the code in the answer; but it would be if @moose used isdigit(a) or... and if any(.... – undergroundmonorail – 2015-04-21T13:36:47.877

4filter(function, iterable) returns a list of all the elements ofiterablefor whichfunctionis aTrue-y value and a non-empty list isTrue-y, so this can be shortened further toif filter(isdigit,[a,b,c])` – undergroundmonorail – 2014-04-16T08:33:39.690

4

Using exec to remove repeated print

This is not quite often applicable, but can save some bytes, especially in ASCII art. Take the following code, which prints the flag where n=4.

# 43 bytes                  |  ***
n=input()                   |  **
while~-n:n-=1;print'*'*n    |  *
print'|'                    |  |

Notice that we repeat print twice. We can remove this using exec in the following code, saving 3 bytes.

# 40 bytes
n=input()
exec"'*'*n;n-=1;print"*n+"'|'"

dingledooper

Posted 2011-01-27T23:55:58.103

Reputation: 6 923

4

Abuse == short circuiting

If you have:

  • A function with a side effect (such as print);
  • That you only want to run if some condition is (or is not) met.

Then you might be able to use == over or to save a byte.

Here's printing all numbers n under 100 that have f(n) less than 2:

# Naive
for n in range(100):f(n)<2and print(n)
# Invert condition
for n in range(100):f(n)>1or print(n)
# Use ==
for n in range(100):f(n)<2==print(n)

Sisyphus

Posted 2011-01-27T23:55:58.103

Reputation: 9 747

4

If you need to import a lot of modules you can reassign __import__ to something shorter, this also has the advantage of being able to name imports anything you want.

i=__import__;s=i('string');x=i('itertools');

Justin Fay

Posted 2011-01-27T23:55:58.103

Reputation: 247

2I've rarely found this to be actually useful. Generally import string,itertools, import string,itertools as M, from itertools import* and other variants tend to be shorter... – Sp3000 – 2015-07-25T09:05:20.617

s,i=map(__import__,['string','itertools']) is shorter than your example, but still longer than import string as s,itertools as i – Felipe Nardi Batista – 2017-07-12T14:44:27.010

4

Alternatives to builtin string functions

str.capitalize for single words

Use str.title instead for single words. The difference between the two functions is that capitalize only capitalises the first word, while title capitalises all words:

>>> "the quick brown fox".capitalize()
'The quick brown fox'
>>> "the quick brown fox".title()
'The Quick Brown Fox'

str.index

str.find is almost always better, and even returns -1 if the substring is not present rather than throwing an exception.

str.startswith

See this tip by @xnor.

str.splitlines

str.split is shorter:

s.splitlines()
s.split('\n')

However, str.splitlines may be useful if you need to preserve trailing newlines, which can be done by passing 1 as the keepends argument.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

4

Dictionary defaults as entries

Say you have an dictionary literal, which I'll denote {...}, and you want to get the value for a key k, with a default of d if k is missing.

You can save two bytes by prepending an entry rather than using get

{k:d,...}[k]
{...}.get(k,d)

Because later entries override earlier ones of the same key, the entry k:d gets overwritten if it appears in the dict, but remains if key k isn't present.

Note that this required writing k twice, which is fine for a variable, but poor when k is an expression.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

4

Take multi-line input

Use list(iter(input,eof)) to take multi-line input. eof can be any string that you want to stop taking input on if you see it. An example would be eof = ''. The python 2 version is list(iter(raw_input,eof)), however you may want to use sys.stdin.readlines() instead if you have already imported sys.

J Atkin

Posted 2011-01-27T23:55:58.103

Reputation: 4 918

list(iter(input,eof)) is shorter by one, you don't need that space. Also worth noting that this is only for Python 3 - Python 2 is 4 bytes longer because raw_input. – None – 2015-11-30T03:15:01.237

Is shorter than what? – J Atkin – 2015-11-30T03:33:49.500

Than what you have posted, because it has an extraneous space. – None – 2015-11-30T03:34:47.457

Oh, I see. I assume the reader would remove the space though. I will edit it out now. – J Atkin – 2015-11-30T03:38:20.647

4

Find the n'th number meeting a condition

Many sequence challenges ask you to find the n'th number in a sequence of increasing positive integers. When you have a expression p(i) that checks membership, you can do this with the recursive function:

f=lambda n,i=1:n and-~f(n-p(i),i+1)

Note that expression p(i) must give 0 or 1, not just Falsey or Truthy. The outputs are one-indexed, so say for the sequence of primes, it would give

f(1) = 2
f(2) = 3
...

For 0-indexed outputs, shift the base case

f=lambda n,i=1:n+1and-~f(n-p(i),i+1)

The recursive function f=lambda n,i=1:n and-~f(n-p(i),i+1) works by decrementing the required count n each time it gets a hit, and incrementing the output value each time for each value it checks. It might seem weird to redundantly track i, but it's longer to do:

f=lambda n,i=1:n and f(n-p(i),i+1)or~-i

Also compare the natural list strategy (zero-indexed here)

lambda n:[i for i in range(n*n)if p(i)][n]

(You might need a larger bound than n*n.)

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

3

Access list, while building it inside comprehension

In python version 2.4 (and <2.3 with some tweaks) it is possible to access list, from list comprehension. Source #1, Source #2 (Safari, Python Cookbook, 2nd edition)

Python creates secret name _[1] for list, while it is created and store it in locals. Also names _[2], _[3]... are used for nested lists.

So to access list, you may use locals()['_[1]'].

In earlier versions this is not enough. You'll need to use locals()['_[1]'].__self__

I couldn't find evidence, that somethins like that is possible in versions >2.4

Don't think, that it might be usefull often, but who knows! At least it helps with building one-liners.

Example:

# Remove duplicates from a list:
>>> L = [1,2,2,3,3,3]
>>> [x for x in L if x not in locals()['_[1]']]
[1,2,3]

Dead Possum

Posted 2011-01-27T23:55:58.103

Reputation: 3 296

5This still exists in later Pythons. In Python 3, it's called '.0', and it's a generator. – isaacg – 2017-08-18T06:42:52.767

3

When your program needs to return a value, you might be able to use a yield, saving one character:

def a(b):yield b

However, to print it you'd need to do something like

for i in a(b):print i

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

Or just do print[*a(b)] – Esolanging Fruit – 2017-06-05T00:59:36.950

1If only a single value is yielded, print next(i()) will work too. – nyuszika7h – 2014-06-23T13:35:26.440

3

Shorter way to copy/clone a list

(not deep clone. For deep clone see this answer)

(credit to this answer)

a=x[:]
b=[*x]
c=x*1

Try it online!

user202729

Posted 2011-01-27T23:55:58.103

Reputation: 16 190

3

Slicing tricks for hard-wired lists of strings

Warning: Python is the language which worships readability above all else; so coding this way is a Mortal Sin.

This sort of thing comes up a lot; such as here where for a given digit in 0<=d<=9, we can get the 7-bit segment b value as a hex string from the list

b=['7e','30','6d','79','33','5b','5f','70','7f','7b'][d]

If the length of such a list is more than just a few elements, you're usually better off at least using split because you can replace a bunch of "','"s with a single character " " as delimiter. E.g.:

b='7e 30 6d 79 33 5b 5f 70 7f 7b'.split()[d]

This can be used for almost any list of strings (possibly at a small additional cost using a delimiter such as ",").

But if in addition, the strings we are selecting for all have the same length k (k==2 in our example), then with the magic of Python slicing, we can write the above as:

b='7e306d79335b5f707f7b'[2*d:][:2]

which saves a lot of bytes because we don't need character delimiters at all. But in that case, usually even shorter would be:

b='7367355777e0d93bf0fb'[d::10]

Chas Brown

Posted 2011-01-27T23:55:58.103

Reputation: 9 449

3

Unpacking in Python3

If you only need the first few values in the array

>>> a, b, *c = [1, 2, 3, 4, 5]
>>> a
1
>>> b
2
>>> c
[3, 4, 5]

Same applies to when you need last few values

>>> *a, b, c = [1, 2, 3, 4, 5]
>>> a
[1, 2, 3]
>>> b
4
>>> c
5

Or even with the first few and last few

>>> a, *b, c = [1, 2, 3, 4, 5]
>>> a
1
>>> b
[2, 3, 4]
>>> c
5

Tim Rijavec

Posted 2011-01-27T23:55:58.103

Reputation: 179

3

I was experimenting with this, and I found out you can also initialise an empty array if the number of values is one less than the number of variables, such as a,*b,c=1,2 or a,*b,c="ab"

– Jo King – 2018-10-22T11:25:48.593

3

Replace not with 1-

In python, the negation operator not wastes bytes, so we have to find a shorter way. Negation can be implemented as subtraction from 1 (obtained from my Keg experiece), which saves 1 byte. (Also, True and False can be alternatively represented as 1 and 0 internally, so this will not matter much.)

Compare this program:

lambda s:not(s[0]+s[-1]).isdigit()

With this program:

lambda s:1-(s[0]+s[-1]).isdigit()

Some straightforward tricks that might help:

and -> *
or -> +

user85052

Posted 2011-01-27T23:55:58.103

Reputation:

These answers show some other ways to manipulate boolean variables: https://codegolf.stackexchange.com/a/66574/88506 and https://codegolf.stackexchange.com/a/40795/88506

– Joel – 2019-08-27T06:36:01.347

3

Was somewhat mentioned but I want to expand:

[a,b],[c,d]=[[1,2],[3,4]]

works as well as simple a,b=[1,2]. Another great thing is to use ternary operator (similiar to C-like ?:)

x if x<3 else y

and no one mentioned map. Map will call first function given as first argument on each item from second argument. For example assume that a is a list of strings of integers (from user input for example):

sum(map(int,a)) 

will make sum of all integers.

rplnt

Posted 2011-01-27T23:55:58.103

Reputation: 49

x if cond else y == cond and x or y. – user202729 – 2018-07-05T09:34:06.053

5Quoting the OP: Please post one tip per answer. – nyuszika7h – 2014-06-23T13:53:50.233

3

If you rely on data (mostly for kolmogorov-complexity problems), use the built-in zip encoding/decoding and store the data in a file (add +1 for the filename):

open('f','rb').read().decode('zip')

If you have to store the data in the source code, then you need to encode the zip with base64 and do:

"base64literal".decode('base64').decode('zip')

These don't necessarily save characters in all instances, though.

Claudiu

Posted 2011-01-27T23:55:58.103

Reputation: 3 880

3

Abusing try/except blocks can sometimes save characters, especially for exiting out of nested loops or list comprehensions. This:

for c in s:
 for i in l:
  q=ord(c)==i
  if q:print i,c;break
 if q:break

... can become this, saving 3 characters:

try:
 for c in s:
  for i in l:
   if ord(c)==i:print i,c;1/0
except:0

... which in this particular instance can be compressed even further using list comprehensions:

try:[1/(ord(c)-i)for c in s for i in l]
except:print i,c

For an example, see e.g. https://codegolf.stackexchange.com/a/36492/16766.

DLosc

Posted 2011-01-27T23:55:58.103

Reputation: 23 122

3

When using Python 3, for your final print statement, use exit to save one char (note: this prints to STDERR, so you might not be able to use this):

print('x')
exit('x')

exit even adds a trailing newline. There is one caveat, however: exit(some_integer) will not print.

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

Does this print to STDOUT or STDERR? This sounds like it would be the latter, but in most challenges only the former is allowed. – Sp3000 – 2015-04-19T04:24:15.473

@Sp3000 I don't know... how can I tell? – Justin – 2015-04-19T05:18:11.643

Seems to be stderr

– Sp3000 – 2015-04-19T05:32:17.963

exit(some_integer) is valid because exit code is a default output form. – pppery – 2020-06-23T15:20:55.337

3

Easiest way to swap two values

>>> a=5
>>> b=4
>>> a,b=b,a
>>> a
4
>>> b
5

Tim Rijavec

Posted 2011-01-27T23:55:58.103

Reputation: 179

3

Avoid the repeat argument of itertools.product

As @T.Verron points out, in most cases (e.g. ranges and lists), you can instead do

product(*[x]*n)

However, even if you have a generator which you can only use once, like a Python 3 map, the repeat argument is still unnecessary. In such a case you can use itertools.tee:

product(x,repeat=n)
product(*tee(x,n))

For n = 2 you don't even need to include n, since 2 is the default argument to tee.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

product(*[L]*n) is even shorter. – T. Verron – 2015-10-08T11:59:41.970

@T.Verron The initial use case I had in mind was something like a Python 3 map, for which that wouldn't work, but I'll add it as a note thanks :) – Sp3000 – 2015-10-08T12:05:47.037

1

Doesn't feersum have an open 500-point bounty for using itertools at all in a sufficiently old question?

– lirtosiast – 2015-10-08T13:17:57.043

3

Shorter isinstance

Instead of

isinstance(x,C) # 15 bytes

there are several alternatives:

x.__class__==C  # 14 bytes
'a'in dir(x)    # 12 bytes, if the class has a distinguishing attribute 'a'
type(x)==C      # 10 bytes, doesn't work with old-style classes
'K'in`x`        # 8 bytes, only in python 2, if no other classes contain 'K'
                # watch out for false positives from the hex address

Some of them may save extra bytes depending on the context, because you can eliminate a space before or after the expression.

Thanks Sp3000 for contributing a couple of tips.

aditsu quit because SE is EVIL

Posted 2011-01-27T23:55:58.103

Reputation: 22 528

3

Use IDLE 3.3 to take multiline input

In IDLE versions 3.1 to 3.3, the command input() reads an entire multiline string like "line1\nline2", rather than a single line at a time as per the spec. This was fixed in version 3.4.

Calling input() only once is very convenient for golfing. Whether one can take advantage of this is debatable, but I think it is an acceptable interpreter- or environment-specific behavior.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

Wait... so how do you... sort of, enter the string if Enter adds a newline rather than EOF? Does CTRL+D work on Windows? – cat – 2016-03-04T03:00:00.273

1@tac I copy-paste it into IDLE. – xnor – 2016-03-04T03:30:51.043

3

Sometimes you can use Python's exec-statement combined with string repetition, to shorten loops. Unfortunately, you can't often use this, but when you can you can get rid of a lot of long loop constructs. Additionally, because exec is a statement you can't use it in lambdas, but eval() might work (but eval() is quite restricted in what you can do with it) although it's 2 characters longer.

Here is an example of this technique in use: GCJ 2010 1B-A Codegolf Python Solution

JPvdMerwe

Posted 2011-01-27T23:55:58.103

Reputation: 2 724

What kind of restrictions are you thinking about? I don't think Python in itself has any kind of restriction on exec, so you must be referring to problem statements? – hallvabo – 2011-01-28T08:43:54.150

@hallvabo, you're right it's eval() I was most likely thinking of. You can't do eval("print 1") because print 1 is a statement. I'll update the post. – JPvdMerwe – 2011-01-28T10:23:48.823

2In Python 3 you can also do exec("print(1)") since exec() is now a function. – CalculatorFeline – 2017-05-28T05:37:13.607

2In Python 3 you can do eval("print(1)") since print() is now a function. – trichoplax – 2014-04-20T23:02:03.880

As a general rule, this is worth trying when you need to do something n times, but don't care about the index. As soon as you need to initialise a loop variable and increment it, it ends up slightly longer than a for loop – gnibbler – 2011-02-03T20:35:50.167

Also used in my GCJ 2009 1B-A Solution. nested exec's and evals (4 in total) http://stackoverflow.com/questions/1433263/code-golf-decision-tree/1436664

– gnibbler – 2011-02-03T20:39:17.357

3

Use slicing + assignment instead of mutator methods

l.insert(x,y) # before
l[x:x]=y,     # after

l.reverse()   # before
l[::-1]=l     # after

l.append(x)   # before
l[L:]=x,      # after (where L is any integer >= len(l))

l[:]=x        # set the contents of l to the contents of x

EDIT: thanks to @quintopia for pointing this out, these are statements, not expressions. The mutator methods are void functions, so they are expressions which evaluate to None. This means that things like [l.reverse() for x in L] and condition or l.reverse() are valid, whereas [l[::-1]=l for x in L] and condition or l[::-1]=l are not.

Cyoce

Posted 2011-01-27T23:55:58.103

Reputation: 2 888

Note that this cannot always be done. For instance, when using or or and as conditionals, assignment is not allowed, but append and the like are. – quintopia – 2016-01-13T05:34:01.333

l[:]=x is a bit unpythonic - same number of bytes, but I reckon l=x[:] is better practice. Also, [::-1] is listed as a tip here, L[:x]+=y, is better for the general case where x might be an expression (but same byte count if it's just x), and l+=x, is listed here for append. – Sp3000 – 2016-02-17T07:10:18.287

@Sp3000 l[:]=x and l=x[:] do different things. The former mutates the list itself, i.e. all references to that list, whereas the latter sets the variable l to a copy of x – Cyoce – 2016-02-17T07:47:59.703

@Cyoce Oh, nevermind then - my eyes are going to have to get used to seeing that :P – Sp3000 – 2016-02-17T08:01:25.493

3

Optional empty sequence argument

Suppose we want to write a recursive function that prepends to a sequence (e.g. list, tuple) each time. For example, the Python 3 program

def f(n,k,L=[]):n and[f(n-1,k,[b]+L)for b in range(k)]or print(L)

works like itertools.product, taking n,k and printing all length n lists of numbers taken from range(k). (Example thanks to @xnor)

If we don't need L to be a list specifically, we can save on the optional empty list argument by making use of unpacking, like so:

def f(n,k,*T):n and[f(n-1,k,b,*T)for b in range(k)]or print(T)

where T is now a tuple instead. In the general case, this saves 3 bytes!

In Python 3.5+, this also works if we're appending to the end of a sequence, i.e. we can change f(n-1,k,L+[b]) to f(n-1,k,*T,b). The latter is a syntax error in earlier versions of Python though.

Sp3000

Posted 2011-01-27T23:55:58.103

Reputation: 59 387

3

To assign to a tuple, don't use parentheses. For example, a=1,2,3 assigns a to the tuple (1, 2, 3). b=7, assigns b to the tuple (7,). This works in both Python 2 and Python 3.

Erik the Outgolfer

Posted 2011-01-27T23:55:58.103

Reputation: 39 182

2

Python 2 and 3 differences

Recent challange pushed me to search for differences in two major versions of python. More precisely - same code, that returns different results in different versions. This might be helpful in other polyglot challenges.

1) Strings and bytes comparisson

  • Python 2: '' == b''
  • Python 3: '' != b''

2) Rounding (Luis Mendo answer)

  • Python 2: round(1*0.5) = 1.0
  • Python 3: round(1*0.5) = 0

3) Division (Jonathan Allan answer)

  • Python 2: 10/11 = 0
  • Python 3: 10/11 = 0.9090909090909091

4) Suggestions?

Dead Possum

Posted 2011-01-27T23:55:58.103

Reputation: 3 296

1comparisson, challange – Jonathan Frech – 2018-08-28T20:11:36.390

2

List all substrings

You can generate the contiguous substrings of a string s with a recursive function (Python 3 for [*s]).

f=lambda s:[*s]and[s]+f(s[1:])+f(s[:-1])

This will repeat substrings multiple times, but can be made a set to avoid repeats.

f=lambda s:{*s}and{s}|f(s[1:])|f(s[:-1])

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2

Shortening a%b==a if b has a constant sign

For two expressions a and b, where each one results in an int (or long in Python 2) or float, you can replace these:

a%b==a

a==a%b

with these, if b is positive:

0<=a<b

b>a>=0

or these, if b is negative:

b<a<=0

0>=a>b

I'm presenting two expressions for each case because sometimes you may want to use one over the other to eliminate a space to separate expression b from an adjacent token. They both have the same precedence, so you're not usually going to need to surround the second expression with () if you don't need to do so to the first one.

This is useful if expression a is more than 1 byte long or b is negative, because it removes one occurrence of a from the expression. If \$a,b\$ are the lengths of expressions a and b respectively, and \$l\$ is the length of the original expression, the resulting expression will be \$l-a+1\$ bytes long. Note that this method is always going to be shorter than assigning expression a to a separate variable.

Example

For example,

(a+b)%c==a+b

can be replaced with

0<=a+b<c

for a total saving of 4 bytes.

Proof

Let's define the operator \$x\mathbin\%y\$ for \$x,y\in\mathbb Q\$.

Every rational number \$a\$ can be represented as \$a=bq+r\$, where \$q\in\mathbb Z,0\le r<|b|\$. Therefore, we can define an operator \$a\mathbin\%b\$, where the result has the same sign as \$b\$:

$$a=bq+r,q\in\mathbb Z,0\le r<|b|\\a\mathbin\%b=\begin{cases}\begin{align}r\quad b>0\\-r\quad b<0\end{align}\end{cases}$$

This represents the % operator in Python, which calculates the remainder of the division of two numbers. a % b is the same as abs(a) % b, and the result has the same sign as the divisor, b. For the \$a\mathbin\%b\$ operator, this equality holds:

$$(a\pm b)\mathbin\%b=a\mathbin\%b$$

Proof:

$$a=bq+r\leftrightarrow a\pm b=bq+r\pm b=(bq\pm b)+r=b(q\pm1)+r$$

Moreover, for \$b>0\$, we have:

$$a\mathbin\%b=a\leftrightarrow r=a\leftrightarrow0\le a<b$$

Proof for \$r=a\leftarrow0\le a<b\$:

$$0\le a<b\leftrightarrow0\le bq+r<b\leftrightarrow bq=0\leftrightarrow a=r$$

Similarly, for \$b<0\$, we have \$b<a\le0\$.

Therefore, \$a\mathbin\%b=a\leftrightarrow\begin{cases}\begin{align}0\le a<b\quad b>0\\b<a\le0\quad b<0\end{align}\end{cases}\$, or, equivalently, \$(0\le a<b)\lor(b<a\le0)\$.

Erik the Outgolfer

Posted 2011-01-27T23:55:58.103

Reputation: 39 182

2

Recursive functions that print

Functions are allowed to print as programs do. A recursive function that prints can be shorter than both a pure function and a pure program.

Compare these Python 2 submissions to make a list of iteratively floor-halving a number while it's positive, like 10 -> [10, 5, 2, 1].

# 30 bytes: Program 
n=input()
while n:print n;n/=2

# 29 bytes: Function
f=lambda n:n*[0]and[n]+f(n/2)

# 27 bytes: Function that prints
def g(n):1/n;print n;g(n/2)

Try it online!

The function that prints uses 1/n to terminate with error on hitting n=0 after having printing the desired numbers. This saves characters over the program's while and the pure function's base case, giving it the edge in byte count. Often, the termination can be shorter as part of the expression to print or the recursive call. It might even happen on its own for free, like terminating on an empty string when the first character is read.

The key property of our function here is that we're repeatedly applying an operation and listing the results at each step, in order. Additional variables can still be used this way by having them as optional inputs to the function that are passed in the recursive call. Moreover, because we're def'ing a function rather than writing a lambda, we can put statements such as variable assignments in its body.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2

Note: The below makes sense only in the program is scored as characters, not as bytes.

I haven't seen this, though somebody may have posted it somewhere.

I needed to have some long literal ASCII strings in the code so somehow shortening them (as characters, not bytes) would be beneficial. After some experiments I came up with what I call the "Chinese reencoding". I call it that way because ASCII characters mostly seem to be squashed in unicode code points that represent Chinese characters. You take an ASCII string S, encode it in bytes as ASCII, and then decode it in UTF16-BE, like that:

E=S.encode().decode('utf16-be')

The resulting string is half the length. It has to be big endian, as the reverse reencoding may not work - and on most systems the shorter 'utf16' is little endian. You also may need to add a character like space if the original string has odd length, but many times this is OK. Also, for non ASCII characters this does not save length, because they result in too big unicode code points that are represented in the liong form ("\uXXXX")

In you code, use the following:

[E].encode('utf16-be').decode()

in order to get the original longer string, where [E] is the literal shortened string. This costs 29 additional characters, so the original string has to be longer than 58, obviously.

One example - below is my 12 days of Christmas (it can be shortened additionally, but let's use that as an example):

for i in range(12):print('On the %s day of Christmas\nMy true love sent to me\n%s'%('First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth'.split()[i],'\n'.join('Twelve Drummers Drumming,+Eleven Pipers Piping,+Ten Lords-a-Leaping,+Nine Ladies Dancing,+Eight Maids-a-Milking,+Seven Swans-a-Swimming,+Six Geese-a-Laying,+Five Gold Rings,+Four Calling Birds,+Three French Hens,+Two Turtle Doves, and+A Partridge in a Pear Tree.\n'.split('+')[11-i:])))

It's 477 characters long. Let's apply the "Chinese" trick to the two longer string:

r=lambda s:s.encode('utf-16be').decode();for i in range(12):print('On the %s day of Christmas\nMy true love sent to me\n%s'%(r('䙩牳琠卥捯湤⁔桩牤⁆潵牴栠䙩晴栠卩硴栠卥癥湴栠䕩杨瑨⁎楮瑨⁔敮瑨⁅汥癥湴栠呷敬晴栠').split()[i],'\n'.join(r('呷敬癥⁄牵浭敲猠䑲畭浩湧Ⱛ䕬敶敮⁐楰敲猠偩灩湧Ⱛ呥渠䱯牤猭愭䱥慰楮本⭎楮攠䱡摩敳⁄慮捩湧Ⱛ䕩杨琠䵡楤猭愭䵩汫楮本⭓敶敮⁓睡湳ⵡⵓ睩浭楮本⭓楸⁇敥獥ⵡⵌ慹楮本⭆楶攠䝯汤⁒楮杳Ⱛ䙯畲⁃慬汩湧⁂楲摳Ⱛ周牥攠䙲敮捨⁈敮猬⭔睯⁔畲瑬攠䑯癥猬\u2061湤⭁⁐慲瑲楤来\u2069渠愠健慲⁔牥攮ਠ').split('+')[11-i:])))

That's 362, including the lambda (it happens to be worth it, as it is used twice).

Now, all code is mostly ASCII characters, so you may have already guessed that you can use that with exec. There is higher overhead - 43 chars for "exec(''.encode('utf-16be').decode())" (in addition to the whole compressed program) and you may need to double escape some escaped characters in your literal strings (like '\n' in mine has to become '\n'). As a bonus you can always easily add that one space. The compressed porogram looks like:

exec("景爠椠楮\u2072慮来⠱㈩㩰物湴⠧佮⁴桥‥猠摡礠潦⁃桲楳瑭慳屮䵹⁴牵攠汯癥\u2073敮琠瑯\u206d敜渥猧┨❆楲獴⁓散潮搠周楲搠䙯畲瑨⁆楦瑨⁓楸瑨⁓敶敮瑨⁅楧桴栠乩湴栠呥湴栠䕬敶敮瑨⁔睥汦瑨✮獰汩琨⥛楝Ⱗ屮✮橯楮⠧呷敬癥⁄牵浭敲猠䑲畭浩湧Ⱛ䕬敶敮⁐楰敲猠偩灩湧Ⱛ呥渠䱯牤猭愭䱥慰楮本⭎楮攠䱡摩敳⁄慮捩湧Ⱛ䕩杨琠䵡楤猭愭䵩汫楮本⭓敶敮⁓睡湳ⵡⵓ睩浭楮本⭓楸⁇敥獥ⵡⵌ慹楮本⭆楶攠䝯汤⁒楮杳Ⱛ䙯畲⁃慬汩湧⁂楲摳Ⱛ周牥攠䙲敮捨⁈敮猬⭔睯⁔畲瑬攠䑯癥猬\u2061湤⭁⁐慲瑲楤来\u2069渠愠健慲⁔牥攮屮✮獰汩琨✫✩嬱ㄭ椺崩⤩".encode('utf-16be').decode())

and it's 299 characters long. You can see some high code points can always appear. I have not found a way to eliminate them, as the added handling code is not worth the benefit.

This is a cheap trick, in fact, but it can always be applied on top of your solution when the program is longish and there are no or few non-ASCII characters. Often you can devise a custom encoding that can stuff more than two ASCII chars in an unicode one, but it is specific for the task.

Petar Donchev

Posted 2011-01-27T23:55:58.103

Reputation: 121

Most [tag:code-golf] questions are scored in bytes, not characters – pppery – 2019-09-07T22:00:41.770

Interesting, I don't do much and the ones that I have done were scored in characters - but it makes sense. – Petar Donchev – 2019-09-07T22:02:00.330

1exec(bytes('compressed code','u16')[2:]) is a shorter way to achieve this. – dingledooper – 2021-01-12T00:42:49.710

2

To set lots of variables to the same thing use:

# x is a list of the names of the variables you want and y is
# the value you want all of them to have
exec(("%s="*len(x))%tuple(x)+str(y))

user95722

Posted 2011-01-27T23:55:58.103

Reputation: 21

depending on the context for c in x:locals()[c]=y or for c in x:globals()[c]=y might also work. – ovs – 2020-06-12T13:59:29.463

2

Printing the elements of a list, with spaces

Suppose we have to print a list as a string with spaces, like square of numbers upto 10. Then,

Instead of,

print(' '.join(str(i**2)for i in range(11))) # 44 chars

We can do,

print(*(i**2for i in range(11))) # 32 chars

vrintle

Posted 2011-01-27T23:55:58.103

Reputation: 2 730

2

The best way to check whether is a number even or not

Usually you do it this way (6 bytes):

n%2==0

But you can reduce it to 5 bytes:

n%2<1

And even 4 bytes:

~n&1

Bonus tip: when you use if you can ignore spacebetween if and ~n&1 this way:

if~n&1:

Danis

Posted 2011-01-27T23:55:58.103

Reputation: 587

2

Run your code through an space-remover, like this one:

#Pygolfer
a=raw_input()
for i in [i for i in range(len(a)) if a[i]==" "]:
    try:b=a[:i]+a[i+1:];eval(b);a=b;print a
    except:pass

(This just tries to remove the spaces one by one, and try if the code still works. Please still do check your code manually.)

Manual things to do: print'string' works.

[str(i)for i in(1,2,3,4)] works.

etc.

ɐɔıʇǝɥʇuʎs

Posted 2011-01-27T23:55:58.103

Reputation: 4 509

2

You can generate pseudo random numbers using hash.

hash('V~')%10000

Will print 2014.

Eyrofire

Posted 2011-01-27T23:55:58.103

Reputation: 31

Pretty similar to this.

– user202729 – 2018-07-05T09:42:08.493

1Prints 9454 for me. – nyuszika7h – 2014-06-23T13:07:44.750

2Python 2.7.2 always returns 2014, but Python 3.4.0 returns more a more random number per session, like 6321, 3744, and 5566. – Cees Timmerman – 2014-08-13T08:34:12.723

2

Try a lambda expression

By default, submissions may be functions and functions may be anonymous. A lambda expression is often the shortest framework for input/output. Compare:

lambda s:s+s[::-1]
def f(s):return s+s[::-1]
s=input();print s+s[::-1]

(These concatenate a string with its reverse.)

The big limitation is that the body of a lambda must be a single expression, and so cannot contain assignments. For built-ins, you can do assignments like e=enumerate outside the function body or as an optional argument.

This doesn't work for expressions in terms of the inputs. But, note that using a lambda might still be worth repeating a long expression.

lambda s:s.lower()+s.lower()[::-1]
def f(s):t=s.lower();return t+t[::-1]

The lambda is shorter even though we save a char in the named function by having it print rather than return. The break-even point for two uses is length 12.

However, if you have many assignments or complex structures like loops (that are hard to make recursive calls), you're probably be better off taking the hit and write a named function or program.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

2

cmp in Python 2

Say you want to output P if x>0, N if x<0, and Z if x==0.

"ZPN"[cmp(x,0)]

Try it online

This function was removed in Python 3.0.1, although it remained in Python 3.0 by mistake.

mbomb007

Posted 2011-01-27T23:55:58.103

Reputation: 22 375

1Congratulations on the 100th answer to this question! – NinjaBearMonkey – 2016-03-02T20:51:54.993

2

Abuse of or in lambdas

I'm surprised this isn't in here yet, but if you need a multi-statement lambda, or evaluates both of its operands, as opposed to and which doesn't evaluate the second one if the first one is not True. For instance, a contrived example, to print the characters in a string one by one with an interval:

list(
    map(
        (lambda i: 
            sleep(.06) or print(i) or print(ord(i)) # all of these get executed
        ), 
        "compiling... "
    )
)
            

In this case it isn't shorter, but I've found it to be, sometimes.

cat

Posted 2011-01-27T23:55:58.103

Reputation: 5 297

Related – Sp3000 – 2016-03-04T03:21:47.770

@Sp3000 *sighs* I tried searching this question for or, lambda, evaluation etc but didn't see that – cat – 2016-03-04T03:24:08.280

lambda i:[sleep(.06),print(i),print(ord(i))] – user202729 – 2018-07-05T09:37:13.357

2

Omit needless spaces

Python tokens only need to separated by a space for

  • A letter followed by a letter
  • A letter followed by a digit

In all other cases, the space can be omitted (with a few exceptions). Here's a table.

  L D S
 +-----
L|s s n
D|n - n
S|n n n    

First token is row, second token is column
L: Letter
D: Digit
S: Symbol

s: space
n: no space
-: never happens (except multidigit numbers)

Examples

Letter followed by letter: Space

not b
for x in l:
lambda x:
def f(s):
x in b"abc"

Letter followed by digit: Space

x or 3
while 2<x:

Letter followed by symbol: No space

c<d
if~x:
x and-y
lambda(a,b):
print"yes"
return[x,y,z]

Digit followed by letter: No space

x+1if x>=0else 2
0in l

(Some versions of Python 2 will fail on a digit followed by else or or.)

Digit followed by digit: Never occurs

Consecutive digits make a multidigit number. I am not aware of any situation where two digits would be separated by a space.

Digit followed by symbol: No space

3<x
12+n
l=0,1,2

A space is needed for 1 .__add__ and other built-ins of integers, since otherwise the 1. is parsed as a float.

Symbol followed by letter: No space

~m
2876<<x&1
"()"in s

Symbol followed by digit: No space

-1
x!=2

Symbol followed by symbol: No space

x*(a+b)%~-y
t**=.5
{1:2,3:4}.get()
"% 10s"%"|"

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

In general, you can't have a letter after a digit if it confuses the lexer. A digit followed by e is expected to be a float literal, so something like 1else wouldn't work for versions of python that support exponents in the literal. Similarly, as 0o is the prefix of an octal literal, o can follow any digit but 0. For the complete lexical rules, refer to https://docs.python.org/2/reference/lexical_analysis.html

– xsot – 2016-08-01T05:20:13.653

@xsot Do you know what versions of Python will parse this way? I remember a comment thread on this, but I can't find it. – xnor – 2016-08-01T05:51:08.120

I've always assumed these rules so I'm not sure which versions of python deviate from them. Possibly the older ones, if any. – xsot – 2016-08-01T06:12:25.563

@xsot It works on 2.7.10 but fails on Anachy's 2.7.2. – xnor – 2016-08-01T06:28:32.597

2

If you're drawing, for colors, instead of typing:

'#000' for black you can just use 0 (no apostrophes)
'#fff' for white you can simply use ~0 (no apostrophes)
'#f00' for red you can just use 'red'


Example of white being used with ~0

from PIL.ImageDraw import*
i=Image.new('RGB',(25,18),'#d72828')
Draw(i).rectangle((1,1,23,16),'#0048e0',~0)
i.show()

Albert Renshaw

Posted 2011-01-27T23:55:58.103

Reputation: 3 015

2255 is even shorter than 'red'. Some more ideas: ~255 is '#0ff' (cyan). 1<<7 is #800000 (half-brightness red); similarly 1<<15 and 1<<23 are half-brightness green and blue. – Lynn – 2018-01-03T19:10:20.300

2

Booleans are integers, too!

assert True == 1
assert False == 0
assert 2 * True == 2
assert 3 * False == 0
assert (2>1)+(1<2) == 2

If you have a statement like [a,a+x][c] (where c is some boolean expression), you can do a+x*c instead and save a few bytes. Doing arithmetic with booleans can save you lots of bytes!

user45941

Posted 2011-01-27T23:55:58.103

Reputation:

1

Pathlib from shorter files manipulations:

# get current dir, go up one dir, go down one dir, list all "py" files
# and get the whole file bytes

import os.path as p
import glob

d = p.join(p.dirname(p.abspath(__file__))), 'foo', '*.py')
for x in glob.glob(d):
    with open(x, 'rb') as f:
        do_stuff(f)

Becomes:

import pathlib as p

d = p.Path(__file__).absolute().parent / 'foo'
for f in d.glob('*.py'):
    do_stuff(f.read_bytes())

e-satis

Posted 2011-01-27T23:55:58.103

Reputation: 161

1

Checking the length of a list

Empty      : `a==[]` but just checking if it's non empty and swapping the if and the else can be shorter 
Non-Empty  : `a` (assuming it is in a situation where it will be interpreted as a boolean)
len(a)>i   : `a>a[:i]` if the list is non-empty

fejfo

Posted 2011-01-27T23:55:58.103

Reputation: 359

1Additionally because [] is falsy, if want to check if a list is not empty, you can simply do if a:. – Backerupper – 2017-12-22T21:08:30.337

1The second one doesn't seem shorter? Although it can save a following space. But I think 1==len(a) also works for that. – Ørjan Johansen – 2017-12-22T21:44:03.933

The second one gives an error on the empty list. Assuming nonempty, a<a[:2] is shorter. – xnor – 2017-12-23T05:25:09.910

1

Fuse list comprehensions

You can write

[f(x)for x in l]+[g(x)for x in l]

As

sum([[f(x),g(x)]for x in l],[])

It gets even better with more comprehensions or if you have to take out more values

If you need to expand a list you can even turn l+[f(x)for x in l]+[g(x)for x in l] into sum([[f(x),g(x)]for x in l],l)

fejfo

Posted 2011-01-27T23:55:58.103

Reputation: 359

I don't think the two snippets return the same result. For example, [i for i in range(10)]+[-i for i in range(10)] returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9], while sum([[i,-i]for i in range(10)],[]) returns [0, 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9]. – Erik the Outgolfer – 2018-06-29T22:29:05.927

1

Large hard coded numbers can be represented in larger bases, but there is a trade off. Higher bases only become worthwhile after a certain cutoff.

The only three bases you're likely to need to worry about are 10, 16, and 36. These are the cutoffs:

1000000000000 (13 bytes)                            -> 0xe8d4a51000 (12 bytes)
0x10000000000000000000000000000000000000 (40 bytes) -> int("9gmd8o3gbbaz3m2ydgtgwn9qo6xog",36) (39 bytes)

mypetlion

Posted 2011-01-27T23:55:58.103

Reputation: 732

1

In Python,

True == 1   # true
False == 0  # true

So,

(a<b)*2-1

returns 1 if b is larger than a. If not, returns -1.

More golfing,

-(a>b)|1

returns exactly same value as mentioned above.

Useful when modify iterator index by comparable values.

cobaltp

Posted 2011-01-27T23:55:58.103

Reputation: 411

1

  1. from lib import func as F

  2. from lib import*;F=func

  3. import lib;F=lib.func

#2 is better than #1 except in rare cases where something in lib clobbers another name that's important to you.

#3 uses lib twice, winning with short library names.

Sparr

Posted 2011-01-27T23:55:58.103

Reputation: 5 850

1from lib import*;F=func is shorter than import lib;F=lib.func for six letter names; it is always shorter than from lib import func as F. – Dennis – 2018-12-13T04:03:49.493

@Dennis the import* trick is covered in a couple of tips farther up the list from here – Sparr – 2018-12-13T21:16:55.317

That doesn't prevent you from comparing import lib;F=lib.func to from lib import*;F=func in this answer. – Dennis – 2018-12-13T21:44:42.840

@Dennis you have a zillion rep on this site; you could edit it if you thought it would make the answer better – Sparr – 2018-12-14T05:02:14.137

1

If you have multidimensional array of numbers and for instance need to count all numbers greater than n.

First flatten the array, then apply filter function to match condition:

l=[[1,[8,4,7,1],3],[5,[7],3,9],[7,3,9,[[[8]]]]]
n=5
flatten=lambda l: sum(map(flatten,l),[]) if isinstance(l,list) else [l]
len(filter(lambda x:x>n,flatten(l)))

Tim Rijavec

Posted 2011-01-27T23:55:58.103

Reputation: 179

1

I discovered a clever trick used here.

Instead of using the for loop to repeat multiple times, repeat exec multiple times.

p='+'
i=1
exec"print[p*i,i/9*p+'[>'+p*9+'<-]>'+i%9*p][i>20];i+=1;"*255

Compare this with

print"\n".join(">"+"+"*(i/16)+"[<"+"+"*16+">-]<"+"+"*(i%16)if i>31 else"+"*i for i in range(256))

user85052

Posted 2011-01-27T23:55:58.103

Reputation:

1

There's already an answer for this trick. Admittedly it has no examples.

– Ørjan Johansen – 2019-08-12T03:01:52.753

1

Special characters in string literals

When you write a quoted literal string in your code, perhaps to compress a big blob of data, certain characters must be replaced by a two-character escape sequence.

Null byte \0 (ASCII 0)

The null byte can't be present verbatim in Python code. Write it as \0.

Newline \n (ASCII 10)

An actual newline \n can't appear in a string literal because the Python lexer will read it and think the line has ended without closing the initial quote. But, a triple-quoted string like '''stuff''' or """stuff""" may contain newlines. This saves bytes with 5+ newlines, which can be useful in ASCII art.

Carriage return \r (ASCII 13)

A carriage return always needs escaping as \r. Though allowed in a triple-quoted string, a literal \r is misread as a newline \n.

Quotes ' (ASCII 34) and " (ASCII 37)

A single-quoted string can contain double quotes like '"', but must escape single-quotes like '\'', and vice-versa for double-quoted strings. Choose whichever option leads to less escaping.

A triple-quoted string is OK with unescaped quotes of the same type like '''it's'''. But, having quotes at the start and end or three-in-a-row can confuse the lexer into giving a SyntaxError.

Backslash \ (ASCII 92)

A backslash can be escaped as \\. But, Python allows just writing \ if it's followed by a character that can't make it an escape sequence. This is any character not in abfnrtvx0123456789"'\ or literal newline \n.

You can use a r-prefixed raw string like r'\n' to ignore most escape sequences, so r'\n' is just a backslash followed by a letter n and r'\\' is two backslashes. Quote characters still get escaped but don't consume the backslash, so r'\'' is backslash then single-quote. This can cause complications: r'\', r'\\\', and r'\\'' all give SyntaxError.


For reference, the special characters are ASCII values [0, 10, 13, 39, 34, 92]. When doing compression, you might tweak your method to avoid hitting these values.

Some weird characters can be written verbatim without escaping, such as:

  • bell \a (ASCII 7)
  • backspace \b (ASCII 8)
  • tab \t (ASCII 9)
  • vertical tab (ASCII 11)
  • form feed \f (ASCII 12)
  • DEL (ASCII 127)

StackExchange posts won't render these, but Python clients and TIO should handle them fine. Here they are for copy-pasting.

Characters with ASCII codes 128 and up can't be included in Python 2 code without a extra line declaring an encoding like this. Python 3, though, handles them fine, including multibyte Unicode characters.

xnor

Posted 2011-01-27T23:55:58.103

Reputation: 128 762

1

To find the all the indexes of a certain element in a list l, use

filter(lambda x:l[x]==element,range(len(l)))

To find the next index after a certain index:

l[:index].index(element)

To find the nth index:

list(filter(lambda x:l[x]==element,range(len(l))))[n]

Justin

Posted 2011-01-27T23:55:58.103

Reputation: 20 247

1

Rename everything

Here's a little Python 2 snippet that takes a module and a string, and renames every function in that module whose name is longer than 2 characters to a single character with the provided string prefixed. If you're writing a VERY LONG python program that uses many library or builtin functions (and if you manage to golf this snippet better than I have), it has the potential to save quite a few characters. On short programs or programs that use few functions, it will be useless. Since dir() sorts the names in a module, this will always provide the same names to the same functions, and you can use globals() to inspect which names it has given to which functions.

import string
def _(x,y):
 for c,f in zip(string.letters,[x.__dict__[q]for q in dir(x)if q in x.__dict__ and(len(q)>2)*type(x.__dict__[q]).__name__.find('eth')>0]):globals()[y+c]=f

You can use it to rename all the string and builtin functions like so:

_(str,'s')
_(__builtins__,'')

And then see what you actually ended up naming them like so:

for k in sorted(globals().keys(),key=lambda x:`len(x)`+x):print k,globals()[k]

If you only want to rename the builtin functions, it's best not to define the function and just use the body directly:

import string
b=__builtins__
for c,f in zip(string.letters,[b.__dict__[q]for q in dir(b)if(len(q)>2)*type(x.__dict__[q]).__name__.find('eth')>0]):globals()[c]=f

quintopia

Posted 2011-01-27T23:55:58.103

Reputation: 3 869

1

Use a list if you have multiple choices based on int

Say for example you have some output that will be 1, 0, or -1 and you need a different output for each case. You could do something like this:

print('0'if x==0else('1'if x>0else'-1'))

However, the better way is to use x as an index to a list like so:

print(['0','1','-1'][x])

which is 16 bytes shorter.

J Atkin

Posted 2011-01-27T23:55:58.103

Reputation: 4 918

for numbers that won't be used in concatenation: print([0,1,-1][x]) – Felipe Nardi Batista – 2017-07-12T14:00:17.643

1

You can assign to a list inside of a for loop.

For example:

L=[1, 2, 3, 4, 6]
queue = [None]*len(L)
for e, queue[e] in enumerate(L):
    print("adding", queue[e], "to processing queue")

This can also be helpful if you need to switch the object you're assigning to.

class Foo:
    def __init__(self):
        self.x = None
a = Foo()
b = Foo()
for q, (lambda x: a if x%2==0 else b)(q).x in enumerate(range(10)):
    print(a.x, b.x)

Morgan Thrapp

Posted 2011-01-27T23:55:58.103

Reputation: 3 577

0

Slicing can assign:

Converting BGR pixels array to RGB:

l = len(pixels)
for idx in range(0, l - 2, 3):
    pixels[idx + 2], pixels[idx] = pixels[idx], pixels[idx + 2]

Becomes:

l = len(pixels)
pixels[2:l:3], pixels[0:l:3] = pixels[0:l:3], pixels[2:l:3]

It's not just shorter. It's 5 times faster. Except on pypy, where the first version is 2x times faster :)

e-satis

Posted 2011-01-27T23:55:58.103

Reputation: 161

You don't really need to get the length, pixels[2::3] should work too – wastl – 2018-06-02T19:26:55.697

0

Tricks with dicts:

# create a dict from iterable
d = {k: None for k in iterable}
# merge 2 dicts
d.merge(d1)
d.merge(d2)
# access a key, if it doesn't exist set a default value and return it
if 'foo' not in d:
    res = d['foo'] = 'bar'
    res = 'bar
else:
    res = d['foo']

Becomes:

d = {**dict.fromkeys(iterable), **d1, **d2}
res = d.setdefault('foo', 'bar')

Or if you need repeated access:

import collections as c
d = c.ChainMap(dict.fromkeys(iterable), d1, d2, {'foo': 'bar'})
res = d['foo']

e-satis

Posted 2011-01-27T23:55:58.103

Reputation: 161

0

dict.get as a first-class function

# all keys in the dict G with a truthy value
[k for k in G if G[k]]
filter(G.get,G)

# all keys in the dict G with a falsy value
[k for k in G if not G[k]]
G.keys()-filter(G.get,G)

{…, **d} to merge dicts in Python 3

# merge two dicts
a={…}
b={…}
merged: {**a,**b} # the order lets you decide which overrides which

# set a defaut value
G.setdefault(a,1)
G[a]=G.get(a,1)
G={a:1,**G}

Extract elements from a list using ::

# This is a very specific tip when you want to get both an element at
# the near beginning of a list and one somewhere near the end.
# For example, let's assume you want to take the elements at indices 6 and 37
# from a list L of length 40 (it's important it's < 6+37*2)

# ok
a=L[5];b=L[36]
# equivalent
a,b=L[5],L[36]
# 36 = 5 + 31
a,b=L[5::31]

Set literals

set() is 5 chars just to create an empty set. If you can have an initial element e, you can save 2 chars with {e}.

Generators instead of comprehension lists in function calls

# assuming the function iterates on its argument
f([x**2 for x in range(4)])
f(x**2 for x in range(4))

bfontaine

Posted 2011-01-27T23:55:58.103

Reputation: 133

0

1 or 0 can act as boolean operators in Python:

func = lambda x:1 if x//2==x/2 else 0
while 1:
    if func(n):
         print('Hello')
    else:
         exit()

Which is 10 characters shorter than:

func = lambda x:True if x//2==x/2 else False
while True:
    if func(n):
         print('Hello')
    else:
         exit()

Beta Decay

Posted 2011-01-27T23:55:58.103

Reputation: 21 982

3Here's a tip for golfing everywhere: don't return booleans with a conditional! return True if condition else False can always be simplified to return condition, or if the condition isn't a boolean and you need a boolean, use return bool(condition) or return condition!=0 if it's a number. – Cyoce – 2016-02-17T08:02:17.153

@Cyoce This deserves to have many votes. – Erik the Outgolfer – 2016-06-25T06:43:50.127

Also, the while True is unnecessary. It could be shortened to while func(n):print('Hello')\nexit() where \n is the new line character – Cyoce – 2016-07-07T02:38:06.010

1Isn't this pointless in func? You could just have func= lambda x:x//2-x/2 and reverse the consequences of the if (the subtraction will give 0 if they are the same, +/-1 if they are different). It might be better to point out that any python type that has a definition for __bool__ or __non_zero__ could be used instead of a boolean. – FryAmTheEggman – 2014-10-23T20:24:54.257

0

Not read all the answers but you can instead of

if x==3:
    print "yes"
else:
    print "no"

use

print "yes" if x==3 else "no"

user3340707

Posted 2011-01-27T23:55:58.103

Reputation: 11

4

We already have this in shorter form.

– xnor – 2015-04-23T08:14:44.397

this is specific to print function as asked in the question I guess – user3340707 – 2015-04-23T08:16:10.690

6print"yneos"[x!=3::2] based on this answer – Jakube – 2015-04-23T08:28:13.447

@xnor That isn't always applicable, for instance if using recursion. – Ogaday – 2016-02-16T12:25:38.243

0

Convert modules to lists

This will work for CPython (probably both 2 and 3), and lets you maybe shave a few bytes if you need to use a lot of different functions and classes with long names from the same module, but you aren't using any of them often enough to rename individually. You'll have to do some research first to figure out which magic numbers give you which functions. Example (rot13):

d=sorted
e=".__dict__.values()"
b=d(eval("__builtins__"+e))
s=d(eval("str"+e))
t=b[12]('string').maketrans
r=''.join(map(chr,range(65,91)))
w=r[13:]+r[:13]
l=t(r+s[4](r),w+s[4](w))
print s[28](b[53](),l)

Translated back to plain python, this is the same as:

t=__import__('string').maketrans
r=''.join(map(chr,range(65,91)))
w=r[13:]+r[:13]
l=t(r+r.lower(),w+w.lower())
print raw_input().translate(l)

which is obviously much shorter, but it should be clear how this methodology would eventually save bytes on much longer, more complicated programs that use more modules.

quintopia

Posted 2011-01-27T23:55:58.103

Reputation: 3 869