5

I was trying to create a shortest-possible code for a puzzle, and the question came to mind trying to do something like this:

zip(l=[1,2,3,4,5],l[1:])

So I was wondering, is there a way to produce a value, assign it to a variable and use that variable on the very same line/function call?

EDIT:To clarify things, I am aware that this thing is not recommended nor good nor does it yield faster results. Also, the essence of the question is assignment and reusing of the same variable in the same function call. The list is produced using input, the static list here is for the example only. In a situation like this, I would like to avoid repeating the same task twice while I have already produced the result somewhere.

Noob Doob
  • 1,757
  • 3
  • 19
  • 27
  • You do realize that shorter code doesn't necessarily yield faster execution, right? So what exactly is your motivation for creating this obfuscated code? – barak manos Aug 28 '16 at 12:29
  • 1
    My question is solely by curiosity, the motivation was creating a one line code, just because, and who knows if one might decide to use this in his own code. I know that the above is not in the lines of proper programming of course. I am just aiming for shortest, not fastest, code. – Noob Doob Aug 28 '16 at 12:31
  • BTW, for the given example, you could simply write `l = zip([1,2,3,4,5],[2,3,4,5])`. – barak manos Aug 28 '16 at 12:32
  • You can: `a=1;print(a)`. – Jordan Jambazov Aug 28 '16 at 12:32
  • I could, but the list is created by other init, the list here was just for the example. – Noob Doob Aug 28 '16 at 12:33
  • Well, the questions revolves around the same variable assigned and reused in the same function call – Noob Doob Aug 28 '16 at 12:33
  • @JordanJambazov's answer can save you a character if you play code golf on windows since windows uses two newline characters (carriage return + line feed). – timakro Aug 28 '16 at 12:35
  • Is this for Python 2? – PM 2Ring Aug 28 '16 at 12:50
  • @PM2Ring yes, it is – Noob Doob Aug 28 '16 at 12:51
  • I don't see the value of this question. The only possible result is bad code. – TigerhawkT3 Aug 28 '16 at 13:52
  • I wondered if it was possible in Python, and I did not find any answer about it. The question itself is not unreasonable, so no problem in being aswered. Whether it will provide bad code or not is another matter. This is a place to answer technical questions, not to teach others how to programme the right way - even though that is possible through good answers. – Noob Doob Aug 28 '16 at 14:00
  • @TigerhawkT3: Many coders enjoy [code golf](http://codegolf.stackexchange.com) and even though golfing code is rarely the kind of thing you want to see in production code golfing can be a fun way to learn more about algorithms and about the more obscure syntax features of a language; it can also improve one's ability to think laterally about coding problems. – PM 2Ring Aug 28 '16 at 14:40
  • @TigerhawkT3: (cont) I guess golfing questions aren't exactly on-topic for SO, but I don't know of anything prohibiting them, and all the answers on this page warn that these techniques are not appropriate for production code, so I don't see the harm in the occasional golf-related question. – PM 2Ring Aug 28 '16 at 14:42

5 Answers5

4

You can use lambdas and default arguments to code golf this. Stressing that this shouldn't be used in production code, but just demonstrating what is possible in python.

(lambda l=[1, 2, 3]: zip(l, l[1:]))()
Dunes
  • 37,291
  • 7
  • 81
  • 97
  • That's definitely better than my code. But I don't do a lot of golfing. :) – PM 2Ring Aug 28 '16 at 13:11
  • @PM2Ring I only know about it from when looking up ways in which `eval` can be "hacked" to allow arbitrary execution (including imports). I've just looked at my answer and the default argument isn't even necessary. – Dunes Aug 28 '16 at 13:17
  • Yes, you'd save 1 char by passing the list as a normal arg to the lambda. – PM 2Ring Aug 28 '16 at 13:18
2

Here is one hack, but not pythonic. Actually since all you need is creating an object in global namespace you can simply update the namespace by your intended object.

>>> zip(globals().update(a=[1, 2, 3]) or a, a[1:])
[(1, 2), (2, 3)]

Since the update() attribute returns None, its logical or with the object would be the object itself.

Mazdak
  • 105,000
  • 18
  • 159
  • 188
  • Correct me if I'm wrong, but using non-wierd code, for `a = [1,2,3]` the result of my `zip([1,2,3],[1,2,3][1:])` would be `[(1,2),(2,3)]`. – Noob Doob Aug 28 '16 at 12:42
  • @ŁukaszRogalski Indeed! – Mazdak Aug 28 '16 at 12:43
  • And if you're not in the global scope? What then? – TigerhawkT3 Aug 28 '16 at 13:51
  • @TigerhawkT3 First off, the local namespace is always inside the global scope after enclosing scopes (if there is any) so when you update the global namespace you can simply access the object in local namespace too, but If you mean what if we only want to change it in local namespace,basically there is no need for such tasks, when 1. you can simply create your objects by assignments, and 2. you can pass is as an argument. And if the function (or any local object) as been created already, you can read http://stackoverflow.com/questions/1142068/how-to-modify-the-local-namespace-in-python – Mazdak Aug 28 '16 at 14:31
2

If this is a code golf thing so it must be a single statement, then this works in Python 2:

print[zip(l,l[1:])for l in[[1,2,3,4,5]]][0]

output

[(1, 2), (2, 3), (3, 4), (4, 5)]

Otherwise,

l=[1,2,3,4,5];print zip(l,l[1:])

is shorter, and far more sensible than the list comprehension abuse shown above.

Many languages in the C family permit assignment to variables inside expressions. This can be convenient but it has also led to numerous bugs, and most modern compilers will generate warnings if an assignment is detected inside an if condition (for example).

It was an intentional design decision to not allow that sort of thing in Python. Thus a Python assignment statement is not an expression, and so it doesn't have a value.

BTW, the Python data model is quite different to that of many other languages. Python doesn't really have variables that are containers for values, it has objects that may be bound to names.


Note that in Python 3 zip returns an iterator, not a list, so if you want to produce a list you'd need to wrap the zip call with list().

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • Gonna keep the accepted to Kasramvd, since his solution is more generally applied, but yours is far better regarding lists. – Noob Doob Aug 28 '16 at 13:01
  • 1
    @NoobDoob: No worries, but as Kasra & Łukasz have already said, doing stupid tricks like that with `globals()` is **not** a good idea. – PM 2Ring Aug 28 '16 at 13:08
2

With Python 3.8's the introduction of [PEP 572] Assignment Expressions you are now allowed to assign and use a variable on the same line with the syntax of NAME := EXPR:

zip(l:=[1, 2, 3, 4, 5], l[1:]) 

This sets the value of l to [1, 2, 3, 4, 5] before running zip(l, l[1:]) without having to do the long way of:

l = [1, 2, 3, 4, 5]
zip(l, l[1:])
elkshadow5
  • 369
  • 2
  • 4
  • 17
1

Of course, you can always do this:

l = range(1, 6); zip(l, l[1:])

but I guess that's not what you wanted. :-)

There is a relatively clean way

(lambda l: zip(l, l[1:]))(range(1, 6))

BTW that function is defined in itertools recipes as pairwise, so pairwise(range(1, 6)) is probably the most direct way. You only need to write an import hook that imports Python functions from web pages. :-D

And there is a nice convoluted way

next(zip(l, l[1:]) for l in [range(1, 6)])

If you want more ideas, just say so. :-)

Veky
  • 2,646
  • 1
  • 21
  • 30
  • Didn't have a real need to accomplish through this question, but I'm glad it resulted in many nice ideas being presented :) I learned a good bit of information and new ways with this – Noob Doob Aug 28 '16 at 13:22