В python есть более простой способ написать 6 вложенных циклов for?
эта проблема добирается до меня в течение некоторого времени. Есть ли более простой способ написания вложенных for петли в python? Например, если мой код что-то вроде этого:
  for y in range(3):
    for x in range(3):
      do_something()
      for y1 in range(3):
        for x1 in range(3):
          do_something_else()
будет ли более простой способ сделать это? Я знаю, что этот код работает, но при понижении уровня вместо 2 места, как я, это может стать проблемой.
О в Примере было только 4 вложенных for петли, чтобы сделать вещи проще.
11 ответов
Если вы часто повторяете декартово произведение, как в вашем примере, вы можете исследовать itertools Python 2.6.продукт -- или напишите свой собственный, если вы находитесь в более раннем Python.
from itertools import product
for y, x in product(range(3), repeat=2):
  do_something()
  for y1, x1 in product(range(3), repeat=2):
    do_something_else()
Это довольно распространено при циклическом выполнении многомерных пространств. Мое решение:
xy_grid = [(x, y) for x in range(3) for y in range(3)]
for x, y in xy_grid:
    # do something
    for x1, y1 in xy_grid:
        # do something else
столкнувшись с такого рода программной логикой, я, вероятно, разбил бы последовательность циклов на две или более отдельных функций.
другой метод в Python-использовать списочные включения там, где это возможно, вместо петли.
предполагая, что каждый цикл имеет какое-то независимое значение, разбейте их на именованные функции:
def do_tigers():
    for x in range(3):
        print something
def do_lions():
    do_lionesses()
    for x in range(3):
        do_tigers()
def do_penguins():
    for x in range(3):
        do_lions()
..etc.
возможно, я мог бы выбрать лучшие имена. 8-)
 технически, вы можете использовать itertools.product чтобы получить декартово произведение N последовательностей и повторить это:
 for y, x, y1, x1 in itertools.product(range(3), repeat=4):
   do_something_else()
но я не думаю, что на самом деле выигрывает у вас что-нибудь читабельность.
итераторы Python и генераторы, в частности, существуют именно для того, чтобы обеспечить хороший рефакторинг в противном случае сложных циклов.  Конечно, трудно получить абстракцию из простого примера, но предполагая 3 должен быть параметром (возможно, целым range(3) должно быть?), и две функции, которые вы вызываете, нуждаются в некоторых параметрах, которые являются переменными цикла, вы можете рефакторировать код:
  for y in range(3):
    for x in range(3):
      do_something(x, y)
      for y1 in range(3):
        for x1 in range(3):
          do_something_else(x, y, x1, y1)
, например:
def nestloop(n, *funcs):
  head = funcs[0]
  tail = funcs[1:]
  for y in range(n):
    for x in range(n):
      yield head, x, y
      if tail:
        for subtup in nestloop(n, *tail):
           yield subtup[:1] + (x, y) + subtup[1:]
for funcandargs in nestloop(3, do_something, do_something_else):
  funcandargs[0](*funcandargs[1:])
точный вид рефакторинг, несомненно, нужно будет настроить для ваших точных целей, но общий момент, что итераторы (и, как правило, просто простые генераторы) позволяют очень хорошие рефакторинги циклов остается-вся логика цикла идет внутри генератора, и код уровня приложения остается с простым for петли и фактическое применение-соответствующая обработка элементов, полученных в циклах for.
моим личным аргументом было бы то, что вы, вероятно, делаете что-то неправильно, если у вас есть 6 вложенных циклов...
тем не менее, функциональная декомпозиция-это то, что вы ищете. Рефакторинг, поэтому некоторые из циклов происходят в отдельных вызовах функций, а затем вызывают эти функции.
из вашего кода похоже, что вы хотите выполнить операцию с каждой возможной парой точек, где x и y находятся в диапазоне 0..2.
для этого:
for x1,y1,x2,y2 in itertools.product(range(3), repeat=4):
    do_something_with_two_points(x1,y1,2,y2)
операция do_something_with_two_points будет вызываться 81 раз-один раз для каждой возможной комбинации точек.   
вы заглянули в Списочные Включения?
что-то типа:
[do_something() for x in range(3) for y in range(3)]
этот путь выглядит довольно просто и легко. Вы говорите, что хотите обобщить на несколько слоев циклов.... можете ли вы привести реальный пример?
другой вариант, о котором я мог бы подумать, - использовать функцию для генерации параметров, а затем просто применить их в цикле
def generate_params(n):
    return itertools.product(range(n), range(n))
for x,y in generate_params(3):
    do_something()
