12

I saw a one liner code that is claimed to remove duplicates from a sequence:

u = [x for x in seq if x not in locals()['_[1]']]

I tried that code in ipython (with Python 2.7), it gave KeyError: '_[1]'

Does ['_[1]'] mean something special in Python?

Mert Nuhoglu
  • 9,695
  • 16
  • 79
  • 117

4 Answers4

10

locals()['_[1]'] is a way to access a reference to list comprehension (or generator) current result inside that list comprehension.

It is quite an evil, but can produce funny results:

>> [list(locals()['_[1]']) for x in range(3)]
[[], [[]], [[], [[]]]]

See more details here: the-secret-name-of-list-comprehensions.

Roman Bodnarchuk
  • 29,461
  • 12
  • 59
  • 75
  • 10
    Not only is it an evil implementation detail, it was removed in Python 2.7. Don't use it. – Duncan Mar 09 '12 at 10:06
8

It is a temporary name used in a list comprehension by Python 2.6 and earlier. Python 2.7 and Python 3.x fixed this wart: the list being created is no longer accessible until creation has finished.

Or in short it was an implementation detail that nobody should ever have relied on.

Here you can see that Python 2.7 leaves locals() unchanged while Python 2.6 creates a short live temporary:

Python 2.7.2 (default, Jan  5 2012, 16:24:09)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo():
        t = [list(locals().keys()) for x in range(1) ]
        print(locals())
        print(t[0])

>>> foo()
{'x': 0, 't': [['x']]}
['x']
>>>

Python 2.6.7 (r267:88850, Jan  5 2012, 16:18:48)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo():
        t = [list(locals().keys()) for x in range(1) ]
        print(locals())
        print(t[0])

>>> foo()
{'x': 0, 't': [['_[1]', 'x']]}
['_[1]', 'x']
>>>

Python 3.x introduces a new short lived temporary for list comprehensions called .0. Don't be tempted to use that for anything either. Also the whole list comprehension runs in a separate namespace so the loop variables aren't accessible outside the loop either:

Python 3.2 (r32:88445, Jan  5 2012, 16:29:57)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-51)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo():
        t = [list(locals().keys()) for x in range(1) ]
        print(locals())
        print(t[0])

>>> foo()
{'t': [['.0', 'x']]}
['.0', 'x']
Duncan
  • 92,073
  • 11
  • 122
  • 156
3

Wow! That's nastily cryptic code. Took a bit of research to find the answer.

Basically the list comprehension is building a new list. It names this temporary list _[1]. The locals() part is just using the locals() dictionary to look up that name, as it's not accessible otherwise. So that line is saying...

[x for x in seq if x not in this_list]

Cryptic.

The found information on this here

Paul S
  • 7,645
  • 2
  • 24
  • 36
1

locals() from Python docs:

Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.

I can't see why locals() is used in that one liner, maybe it's not as general as you want.

If you're trying to remove duplicates from a list I think the best choice is convert it to a set:

In [2]: l = [1,1,3,4,2,4,6]
In [4]: set(l)
Out[4]: set([1, 2, 3, 4, 6])

If you want a list again:

In [5]: list(set(l))
Out[5]: [1, 2, 3, 4, 6]
Diego Navarro
  • 9,316
  • 3
  • 26
  • 33