290
\$\begingroup\$

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.

\$\endgroup\$
9
  • 33
    \$\begingroup\$ Oh, I can see a whole set of questions like this one coming for each language... \$\endgroup\$ – R. Martinho Fernandes Jan 28 '11 at 4:26
  • 6
    \$\begingroup\$ @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. \$\endgroup\$ – moinudin Jan 28 '11 at 12:28
  • 58
    \$\begingroup\$ Love the question but I have to keep telling myself "this is ONLY for fun NOT for production code" \$\endgroup\$ – Greg Guida Dec 21 '11 at 0:08
  • 3
    \$\begingroup\$ Shouldn't this question be a community wiki post? \$\endgroup\$ – dorukayhan May 29 '16 at 15:35
  • 4
    \$\begingroup\$ @dorukayhan Nope; it's a valid code-golf tips question, asking for tips on shortening 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). \$\endgroup\$ – Erik the Outgolfer Sep 9 '16 at 14:48

153 Answers 153

2
\$\begingroup\$

You can generate pseudo random numbers using hash.

hash('V~')%10000

Will print 2014.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Prints 9454 for me. \$\endgroup\$ – nyuszika7h Jun 23 '14 at 13:07
  • 2
    \$\begingroup\$ Python 2.7.2 always returns 2014, but Python 3.4.0 returns more a more random number per session, like 6321, 3744, and 5566. \$\endgroup\$ – Cees Timmerman Aug 13 '14 at 8:34
  • \$\begingroup\$ Pretty similar to this. \$\endgroup\$ – user202729 Jul 5 '18 at 9:42
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Congratulations on the 100th answer to this question! \$\endgroup\$ – NinjaBearMonkey Mar 2 '16 at 20:51
2
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ Related \$\endgroup\$ – Sp3000 Mar 4 '16 at 3:21
  • \$\begingroup\$ @Sp3000 *sighs* I tried searching this question for or, lambda, evaluation etc but didn't see that \$\endgroup\$ – cat Mar 4 '16 at 3:24
  • \$\begingroup\$ lambda i:[sleep(.06),print(i),print(ord(i))] \$\endgroup\$ – user202729 Jul 5 '18 at 9:37
2
\$\begingroup\$

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"%"|"
\$\endgroup\$
4
  • \$\begingroup\$ 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 docs.python.org/2/reference/lexical_analysis.html \$\endgroup\$ – xsot Aug 1 '16 at 5:20
  • \$\begingroup\$ @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. \$\endgroup\$ – xnor Aug 1 '16 at 5:51
  • \$\begingroup\$ I've always assumed these rules so I'm not sure which versions of python deviate from them. Possibly the older ones, if any. \$\endgroup\$ – xsot Aug 1 '16 at 6:12
  • \$\begingroup\$ @xsot It works on 2.7.10 but fails on Anachy's 2.7.2. \$\endgroup\$ – xnor Aug 1 '16 at 6:28
2
\$\begingroup\$

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!

\$\endgroup\$
2
\$\begingroup\$

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()
\$\endgroup\$
1
  • 2
    \$\begingroup\$ 255 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. \$\endgroup\$ – Lynn Jan 3 '18 at 19:10
2
\$\begingroup\$

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])
\$\endgroup\$
2
\$\begingroup\$

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?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ comparisson, challange \$\endgroup\$ – Jonathan Frech Aug 28 '18 at 20:11
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ Most code-golf questions are scored in bytes, not characters \$\endgroup\$ – pppery Sep 7 '19 at 22:00
  • \$\begingroup\$ Interesting, I don't do much and the ones that I have done were scored in characters - but it makes sense. \$\endgroup\$ – Petar Donchev Sep 7 '19 at 22:02
  • 1
    \$\begingroup\$ exec(bytes('compressed code','u16')[2:]) is a shorter way to achieve this. \$\endgroup\$ – dingledooper Jan 12 at 0:42
2
\$\begingroup\$

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))
\$\endgroup\$
1
  • \$\begingroup\$ depending on the context for c in x:locals()[c]=y or for c in x:globals()[c]=y might also work. \$\endgroup\$ – ovs Jun 12 '20 at 13:59
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

When you want to use map with list then cast it to list, use * instead of list(...).

new_a=list(map(f,a))
new_a=[*map(f,a)]     # -3 char

Moreover, you also can convert some iterable things to list with saving 3 characters:

a=list("abc")
a=[*"abc"]
b=list(range(x,y))
b=[*range(x,y)]
\$\endgroup\$
3
  • \$\begingroup\$ the most concise way to do this is like this, saving one character:: *a,=map(f,a) *b,=range(x,y) \$\endgroup\$ – Ryan Laursen Apr 13 at 20:45
  • \$\begingroup\$ sorry but I got "SyntaxError: starred assignment target must be in a list or tuple" when I try it. \$\endgroup\$ – HK boy 2 days ago
  • 1
    \$\begingroup\$ You must be forgetting the comma or possibly using Python 2. Here is a SO question about it: stackoverflow.com/questions/43190992/understanding-x-lst \$\endgroup\$ – Ryan Laursen 2 days ago
1
\$\begingroup\$

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)))
\$\endgroup\$
1
\$\begingroup\$

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]
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ for numbers that won't be used in concatenation: print([0,1,-1][x]) \$\endgroup\$ – Felipe Nardi Batista Jul 12 '17 at 14:00
1
\$\begingroup\$

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)
\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
1
1
\$\begingroup\$

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())
\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Additionally because [] is falsy, if want to check if a list is not empty, you can simply do if a:. \$\endgroup\$ – Backerupper Dec 22 '17 at 21:08
  • 1
    \$\begingroup\$ The second one doesn't seem shorter? Although it can save a following space. But I think 1==len(a) also works for that. \$\endgroup\$ – Ørjan Johansen Dec 22 '17 at 21:44
  • \$\begingroup\$ The second one gives an error on the empty list. Assuming nonempty, a<a[:2] is shorter. \$\endgroup\$ – xnor Dec 23 '17 at 5:25
1
\$\begingroup\$

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)

\$\endgroup\$
1
  • \$\begingroup\$ 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]. \$\endgroup\$ – Erik the Outgolfer Jun 29 '18 at 22:29
1
\$\begingroup\$

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)
\$\endgroup\$
1
\$\begingroup\$
  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.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ from 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. \$\endgroup\$ – Dennis Dec 13 '18 at 4:03
  • \$\begingroup\$ @Dennis the import* trick is covered in a couple of tips farther up the list from here \$\endgroup\$ – Sparr Dec 13 '18 at 21:16
  • \$\begingroup\$ That doesn't prevent you from comparing import lib;F=lib.func to from lib import*;F=func in this answer. \$\endgroup\$ – Dennis Dec 13 '18 at 21:44
  • \$\begingroup\$ @Dennis you have a zillion rep on this site; you could edit it if you thought it would make the answer better \$\endgroup\$ – Sparr Dec 14 '18 at 5:02
1
\$\begingroup\$

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))
\$\endgroup\$
1
  • 1
    \$\begingroup\$ There's already an answer for this trick. Admittedly it has no examples. \$\endgroup\$ – Ørjan Johansen Aug 12 '19 at 3:01
1
\$\begingroup\$

Checking if a boolean value is false and an integer is a specific odd integer

~True is ~1 is -2 and ~False is ~0 is -1

-1&int is always int

-2&int is always even

Therefore, despite operator order, ~bool&int==odd_int works fine.

It's shorter than all of these equivalents:

not bool and int==odd_int

-~bool and int==odd_int

-~bool&int==odd_int

New contributor
Ryan Laursen is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Though it's a niche situation, this does seem to be the shortest code for handling it. It's the same length to do int<<bool==odd_int, but starting with a number rather than ~ can require a space before it, say after if. If we know the integers are non-negative, then int^int|bool<1 or int^int<1>bool works without needing oddness. \$\endgroup\$ – xnor Apr 13 at 18:20
0
\$\begingroup\$

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()
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Isn'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. \$\endgroup\$ – FryAmTheEggman Oct 23 '14 at 20:24
  • 3
    \$\begingroup\$ Here'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. \$\endgroup\$ – Cyoce Feb 17 '16 at 8:02
  • \$\begingroup\$ @Cyoce This deserves to have many votes. \$\endgroup\$ – Erik the Outgolfer Jun 25 '16 at 6:43
  • \$\begingroup\$ Also, the while True is unnecessary. It could be shortened to while func(n):print('Hello')\nexit() where \n is the new line character \$\endgroup\$ – Cyoce Jul 7 '16 at 2:38
0
\$\begingroup\$

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"
\$\endgroup\$
4
  • 4
    \$\begingroup\$ We already have this in shorter form. \$\endgroup\$ – xnor Apr 23 '15 at 8:14
  • \$\begingroup\$ this is specific to print function as asked in the question I guess \$\endgroup\$ – user3340707 Apr 23 '15 at 8:16
  • 6
    \$\begingroup\$ print"yneos"[x!=3::2] based on this answer \$\endgroup\$ – Jakube Apr 23 '15 at 8:28
  • \$\begingroup\$ @xnor That isn't always applicable, for instance if using recursion. \$\endgroup\$ – Ogaday Feb 16 '16 at 12:25
0
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.