It is pythonic. Already.
But if you worry about this goes to 10+ levels deep, with only the innermost loop has anything interesting, one thing you can consider is to create a generator. Your code can become:
def get_command(jobs):
for job in jobs:
for task in job.tasks:
for command in task.commands:
yield command
for command in get_command(jobs):
print command.actual_cmd
So the whole purpose is to avoid excessive indentation.
To make it generic for multiple level, so you don't worry even if it is 100+ levels deep:
def get_nested(objlist, attribs):
for x in objlist:
if len(attribs) == 0:
yield x
else:
x_dot_attr = getattr(x, attribs[0])
for y in get_nested(x_dot_attr, attribs[1:]):
yield y
for command in get_nested(jobs, ["tasks", "commands"]):
print command.actual_cmd
But no, this generalization doesn't make it more pythonic. It only avoids excessive indentation.
for command in task.commands: print command.actual_cmd), there's nothing wrong with what you have, unless perhaps you have many different object structures with similar loops over them, in which case you could write a function that's more generic - but since you're just printing, that seems unlikely.