You can make this a little shorter by using an if expression:
def f(objects):
list_type = "string_x"
other = "string_y"
hold = []
for x in objects:
hold.append((list_type if isinstance(x[1], list) else other, x[1]))
return hold
And then it's pretty easy to turn into a comprehension, which is even shorter, and probably more readable, and a little faster:*
def f(objects):
list_type = "string_x"
other = "string_y"
return [(list_type if isinstance(x[1], list) else other, x[1])
for x in objects]
And really, I'm not sure those local variables are making things any clearer:**
def f(objects):
return [("string_x" if isinstance(x[1], list) else "string_y", x[1])
for x in objects]
Meanwhile, if the only thing you're going to do with the returned list is to iterate over it (e.g., because this is just one in a chain of transformations), you shouldn't be returning a list at all. Either yield each value, return a genexpr instead of a listcomp, or (if you have Python 3.3+) get the best of both worlds:
def f(objects):
yield from (("string_x" if isinstance(x[1], list) else "string_y", x[1])
for x in objects)
* You are still doing the exact same loop, so you have the exact same algorithmic complexity. However, both the looping and the list appending, are happening with custom bytecodes that take some shortcuts, making each iteration a bit more efficient. (The "custom bytecodes" detail is of course specific to CPython and other bytecode-compatible implementations like PyPy, but in general, any implementation at least could take shortcuts on list comprehensions.)
** This last very might be slightly faster, because it's loading a constant onto the stack instead of a local variable. Then again, it might also have slightly worse cache locality. If it really matters, test it and see.
objects?