I have a list where I want to replace values with None where condition() returns True.

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

For example, if condition checks bool(item%2) should return:

[None, 1, None, 3, None, 5, None, 7, None, 9, None]

What is the most efficient way to do this?

Build a new list with a list comprehension:

new_items = [x if x % 2 else None for x in items]

You can modify the original list in-place if you want, but it doesn’t actually save time:

items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for index, item in enumerate(items):
    if not (item % 2):
        items[index] = None

Here are (Python 3.6.3) timings demonstrating the non-timesave:

In [1]: %%timeit
   ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   ...: for index, item in enumerate(items):
   ...:     if not (item % 2):
   ...:         items[index] = None
   ...:
1.06 µs ± 33.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [2]: %%timeit
   ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   ...: new_items = [x if x % 2 else None for x in items]
   ...:
891 ns ± 13.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

And Python 2.7.6 timings:

In [1]: %%timeit
   ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   ...: for index, item in enumerate(items):
   ...:     if not (item % 2):
   ...:         items[index] = None
   ...: 
1000000 loops, best of 3: 1.27 µs per loop
In [2]: %%timeit
   ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   ...: new_items = [x if x % 2 else None for x in items]
   ...: 
1000000 loops, best of 3: 1.14 µs per loop

ls = [x if (condition) else None for x in ls]

Here’s another way:

>>> L = range (11)
>>> map(lambda x: x if x%2 else None, L)
[None, 1, None, 3, None, 5, None, 7, None, 9, None]

Riffing on a side question asked by the OP in a comment, i.e.:

what if I had a generator that yields
the values from range(11) instead of a
list. Would it be possible to replace
values in the generator?

Sure, it’s trivially easy…:

def replaceiniter(it, predicate, replacement=None):
  for item in it:
    if predicate(item): yield replacement
    else: yield item

Just pass any iterable (including the result of calling a generator) as the first arg, the predicate to decide if a value must be replaced as the second arg, and let ‘er rip.

For example:

>>> list(replaceiniter(xrange(11), lambda x: x%2))
[0, None, 2, None, 4, None, 6, None, 8, None, 10]

>>> L = range (11)
>>> [ x if x%2 == 1 else None for x in L ]
[None, 1, None, 3, None, 5, None, 7, None, 9, None]

In case you want to replace values in place, you can
update your original list with values from a list
comprehension by assigning to the whole slice of the original.

data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
id_before = id(data)
data[:] = [x if x % 2 else None for x in data]
data
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None]
id_before == id(data)  # check if list is still the same
# Out: True

If you have multiple names pointing to the original list,
for example you wrote data2=data before changing the list
and you skip the slice notation for assigning to data,
data will rebind to point to the newly created list while data2 still points to the original unchanged list.

data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data2 = data
id_before = id(data)
data = [x if x % 2 else None for x in data]  # no [:] here
data
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None]
id_before == id(data)  # check if list is still the same
# Out: False
data2
# Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Note: This is no recommendation for generally preferring one over the other
(changing list in place or not), but behavior you should be aware of.

This might help…

test_list = [5, 8]
test_list[0] = None
print test_list
#prints [None, 8]