Как перебрать атрибуты данных объекта экземпляра, возвращая два значения одновременно? - PullRequest
2 голосов
/ 13 апреля 2010

Мне нужно возвращать два значения за раз, поэтому у меня есть:

class IterableObject(object):
  def __iter__(self):
    for item in self.__dict__:
      return  self.__dict__[item + 1], self.__dict__[item]

Так что я могу иметь:

myObj1, myObj2 = IterableObject()

value = myObj1.balance - myObj2.balance

Конечно, это не сработало. Что я делаю неправильно? Я думаю, что не могу добавить ценность к такому предмету.

Ответы [ 3 ]

5 голосов
/ 13 апреля 2010

В документации itertools есть пример функции pairwise, которую вы можете скопировать в свой проект:

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

Используйте ее как:

for x1, x2 in pairwise(some_iterable):
    # etc..

Обратите внимание, что когда вы перебираете dict, элементы не обязательно возвращаются по порядку, поэтому вы должны сначала отсортировать.

1 голос
/ 19 апреля 2010

Небольшое изменение вашего собственного примера должно дать вам то, что вы хотите. Ваш оригинальный пример показывает, что вы не знаете, что итерация по словарю дает вам ключи словаря. "aproprty_name" + 1 почти никогда не даст вам то, что вы хотите.

class IterableObject:
  def __iter__(self):
    properties = (i for i in self.__dict__)
    While True:
      a = properties.next()
      try:
        b = properties.next()
      except StopIteration:
        yield (getattr(self,a), ) #for the odd number of properties case
        raise StopIteration
      yield getattr(self, a), getattr(self, b)

Это не будет работать в приведенном вами примере. Вы не можете слепо предвидеть, что значения находятся в каком-либо порядке, который имел бы смысл вычитать одно из другого.

Что вам, вероятно, нужно, это объект, который возвращает следующие два значения из списка значений, которые, как вы знаете, являются четным числом значений. Вы должны будете установить этот список в объекте. Таким образом, парная последовательность заказов будет возвращена в том же порядке.

class PairedList:
  def __iter__(self):
    balances = iter(self.balances)
    while True:
      yield balances.next(), balances.next()

>>> b = PairedList()
>>> b.balances = (2000, 151, 1000, 255, 600, 150, 0, 20, 30, 30, 50, 10)
>>> [i for i in b]
[(2000, 151), (1000, 255), (600, 150), (0, 20), (30, 30), (50, 10)]
>>> [(balance-withdrawal, balance, withdrawal) for balance, withdrawal in b]
[(1849, 2000, 151), (745, 1000, 255), (450, 600, 150), (-20, 0, 20), (0, 30, 30), (40, 50, 10)]

Возможно, вы захотите перечитать свой вопрос и пример и перефразировать их, потому что, как написано, вы создаете новый объект и ожидаете, что он уже будет содержать ваши значения. Пример использования моего класса PairedList, который сделает это для вас, будет:

>>> PairedList.balances = b.balances
>>> [(balance-withdrawal, balance, withdrawal) for balance, withdrawal in PairedList()]
[(1849, 2000, 151), (745, 1000, 255), (450, 600, 150), (-20, 0, 20), (0, 30, 30), (40, 50, 10)]

Но это почти наверняка не то, что вы хотите. По умолчанию это будет ограничивать вас только одним набором весов, который вы можете перебрать. И создаст набор балансов по умолчанию для каждого объекта PairedList, который в конечном итоге вернется, чтобы укусить вас за задницу.

1 голос
/ 13 апреля 2010

Возможное решение без itertools:

def pairwise(iterable):
    it = iter(iterable)
    try:
        while True:
            yield it.next(), it.next()
    catch StopIteration:
        pass

>>> list(pairwise(range(6))
[(0, 1), (2, 3), (4, 5)]
>>> list(pairwise(range(5))
[(0, 1), (2, 3)]

Это отличается от решения в документации itertools в том смысле, что последний элемент никогда не возвращается из итерируемого, если он содержит нечетное количество элементов. Но я думаю, что решение в itertools примерах лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...