43

This must be simple, but as an only occasional python user, fighting some syntax. This works:

def perms (xs):
    for x in itertools.permutations(xs): yield list(x) 

But this won't parse:

def perms (xs): for x in itertools.permutations(xs): yield list(x) 

Is there some restriction on the one-line function syntax? The body definition (for...) can be either two or one line by itself, and the def: can be one or two lines with a simple body, but combining the two fails. Is there a syntax rule that excludes this?

guthrie
  • 4,529
  • 4
  • 26
  • 31
  • 3
    FTR on Python 3.3 `def perms (xs): yield from map(list, itertools.permutations(xs))` – jamylak May 26 '13 at 04:27
  • 3
    As an occasional Python user you should try and learn that in Python, layout matters. Readability counts much more than being able to write one-liners. If in doubt, make it look the way you would like to see it if you had to maintain it. – Paddy3118 May 26 '13 at 05:24
  • 12
    I know layout matters since the first version used it and works. Readability is subjective, and the single line style for something this simple is what I wanted, and also I wanted to understand the syntax issues better. – guthrie May 26 '13 at 12:16

4 Answers4

58

If you must have one line just make it a lambda:

perms = lambda xs: (list(x) for x in itertools.permutations(xs))

Quite often, when you have a short for loop for generating data you can replace it with either list comprehension or a generator expression for approximately the same legibility in slightly less space.

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • Thanks - great answer and very helpful - but since I can only check one as "the answer" and was looking for the syntax rule, I checked the one above. – guthrie May 26 '13 at 12:42
  • @guthrie - no problems at all - this is definitely only a supplement to Lennart's excellent answer :-) – Sean Vieira May 26 '13 at 12:58
  • 3
    you could also use a one line named function as: `def perms(xs): return (list(x) for x in itertools.permutations(xs))` – cosmicFluke Oct 24 '17 at 21:59
  • 4
    pylint will complain on this one - https://stackoverflow.com/questions/25010167/e731-do-not-assign-a-lambda-expression-use-a-def – ikamen Mar 01 '19 at 10:45
42

Yes, there are restrictions. No, you can't do that. Simply put, you can skip one line feed but not two.

See here.

The reason for this is that it would allow you to do

if test1: if test2: print x
else:
    print y

Which is ambiguous.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
7

In your case, I am not sure. But with some functions you can achive this by using semicolons.

>>> def hey(ho): print(ho); print(ho*2); return ho*3
...
>>> hey('you ')
you
you you
'you you you '
jerik
  • 5,714
  • 8
  • 41
  • 80
  • Works inside the interpreter, but seems to not working inside "python -c", unfortunately. For example: python -c 'def func(x): print(x); func(1)' – Alexander Samoylov Nov 24 '22 at 14:12
4

def perms (xs):

for x in itertools.permutations(xs): yield list(x)

You can use exec() to help this problem

exec('def perms (xs):\n  for x in itertools.permutations(xs):\n   yield list(x)\n')

beware to insert indented spacing or chr(9) after \n

Example for if Python in one line

for i in range(10):
 if (i==1):
  print(i)

exec('for i in range(10)\n  if (i==1):\n   print(i)\n')

This is My project on GitHub to use exec to run Python program in interactive console mode

*note multiple line exec run only when end with '\n'

Excalibur
  • 3,258
  • 2
  • 24
  • 32