Как мы можем использовать пользовательские итерации с помощью string.join ()? [Дубликат]

По состоянию на декабрь 2016 года существует очень простой, не хакерский способ сделать это, который все еще работает сейчас (июль 2018).

FirebaseOptions options = new FirebaseOptions.Builder()
       .setApplicationId("1:something:android:something_else") // Required for Analytics.
       .setApiKey("your apikey") // Required for Auth.
       .setDatabaseUrl("https://your-database.firebaseio.com/") // Required for RTDB.
       .build();
FirebaseApp.initializeApp(this /* Context */, options, "secondary");

Источник: Официальный блог Firebase

455
задан user2357112 27 July 2016 в 21:57
поделиться

9 ответов

Объекты Iterator в python соответствуют протоколу итератора, что в основном означает, что они предоставляют два метода: __iter__() и next(). __iter__ возвращает объект итератора и неявно вызывается в начале циклов. Метод next() возвращает следующее значение и неявно вызывается при каждом приращении цикла. next() вызывает исключение StopIteration, когда больше нет значения для возврата, которое неявно захватывается конструкциями цикла, чтобы остановить итерацию.

Вот простой пример счетчика:

class Counter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def next(self): # Python 3: def __next__(self)
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1


for c in Counter(3, 8):
    print c

Это будет печатать:

3
4
5
6
7
8

Это проще записать с использованием генератора, как описано в предыдущем ответе:

def counter(low, high):
    current = low
    while current <= high:
        yield current
        current += 1

for c in counter(3, 8):
    print c

Печатный вывод будет таким же. Под капотом объект-генератор поддерживает протокол итератора и делает что-то примерно похожее на класс Counter.

Статья Дэвида Мерца, Итераторы и простые генераторы - довольно хорошее введение.

537
ответ дан Matt Gregory 19 August 2018 в 05:25
поделиться
  • 1
    Обратите внимание, что функция next() не имеет значений yield, она return s. – John Mee 17 October 2012 в 08:03
  • 2
    Это недопустимо в Python 3 --- оно должно быть __next__(). – Aerovistae 23 September 2013 в 04:42
  • 3
    Это, в основном, хороший ответ, но тот факт, что он возвращает себя, немного не оптимален. Например, если вы использовали один и тот же объект-счетчик в цикле с двойной вставкой, вы, вероятно, не получите того поведения, которое вы имели в виду. – Casey Rodarmor 7 February 2014 в 01:33
  • 4
    Нет, итераторам СЛЕДУЕТ вернуться. Итераторы возвращают итераторы, но iterables не должны реализовывать __next__. counter является итератором, но это не последовательность. Он не сохраняет свои значения. Например, вы не должны использовать счетчик в двойном вложенном цикле for-loop. – leewz 21 February 2014 в 10:42
  • 5
    В примере счетчика self.current следует назначать в __iter__ (в дополнение к __init__). В противном случае объект может быть повторен только один раз. Например, если вы скажете ctr = Counters(3, 8), то вы не сможете использовать for c in ctr более одного раза. – Curt 5 April 2016 в 23:00

Вдохновленный ответом Мэтта Грегори, здесь немного сложнее итератор, который вернет a, b, ..., z, aa, ab, ..., zz, aaa, aab, ..., zzy, zzz

    class AlphaCounter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def __next__(self): # Python 3: def __next__(self)
        alpha = ' abcdefghijklmnopqrstuvwxyz'
        n_current = sum([(alpha.find(self.current[x])* 26**(len(self.current)-x-1)) for x in range(len(self.current))])
        n_high = sum([(alpha.find(self.high[x])* 26**(len(self.high)-x-1)) for x in range(len(self.high))])
        if n_current > n_high:
            raise StopIteration
        else:
            increment = True
            ret = ''
            for x in self.current[::-1]:
                if 'z' == x:
                    if increment:
                        ret += 'a'
                    else:
                        ret += 'z'
                else:
                    if increment:
                        ret += alpha[alpha.find(x)+1]
                        increment = False
                    else:
                        ret += x
            if increment:
                ret += 'a'
            tmp = self.current
            self.current = ret[::-1]
            return tmp

for c in AlphaCounter('a', 'zzz'):
    print(c)
0
ответ дан Ace.Di 19 August 2018 в 05:25
поделиться

Этот вопрос касается истребимых объектов, а не об итераторах. В Python последовательности также повторяются, поэтому один из способов сделать итерируемый класс - заставить его вести себя как последовательность, т. Е. Дать ему методы __getitem__ и __len__. Я тестировал это на Python 2 и 3.

class CustomRange:

    def __init__(self, low, high):
        self.low = low
        self.high = high

    def __getitem__(self, item):
        if item >= len(self):
            raise IndexError("CustomRange index out of range")
        return self.low + item

    def __len__(self):
        return self.high - self.low


cr = CustomRange(0, 10)
for i in cr:
    print(i)
8
ответ дан aq2 19 August 2018 в 05:25
поделиться

Если вы ищете что-то короткое и простое, возможно, этого вам будет достаточно:

class A(object):
    def __init__(self, l):
        self.data = l

    def __iter__(self):
        return iter(self.data)

пример использования:

In [3]: a = A([2,3,4])

In [4]: [i for i in a]
Out[4]: [2, 3, 4]
1
ответ дан Daniil Mashkin 19 August 2018 в 05:25
поделиться

Существует четыре способа создания итеративной функции:

  • создать генератор (использует ключевое слово yield )
  • использовать выражение генератора ( genexp )
  • создает итератор (определяет __iter__ и __next__ (или next в Python 2.x))
  • создает функцию, которую Python может выполнять самостоятельно самостоятельно ( определяет __getitem__ )

Примеры:

# generator
def uc_gen(text):
    for char in text:
        yield char.upper()

# generator expression
def uc_genexp(text):
    return (char.upper() for char in text)

# iterator protocol
class uc_iter():
    def __init__(self, text):
        self.text = text
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        try:
            result = self.text[self.index].upper()
        except IndexError:
            raise StopIteration
        self.index += 1
        return result

# getitem method
class uc_getitem():
    def __init__(self, text):
        self.text = text
    def __getitem__(self, index):
        result = self.text[index].upper()
        return result

Чтобы увидеть все четыре метода в действии:

for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
    for ch in iterator('abcde'):
        print ch,
    print

В результате:

A B C D E
A B C D E
A B C D E
A B C D E

Примечание:

Два типа генератора (uc_gen и uc_genexp) не может быть reversed(); для простого итератора (uc_iter) понадобится магический метод __reversed__ (который должен возвращать новый итератор, который идет назад); и итеративный getitem (uc_getitem) должен иметь магический метод __len__:

    # for uc_iter
    def __reversed__(self):
        return reversed(self.text)

    # for uc_getitem
    def __len__(self)
        return len(self.text)

Чтобы ответить на второстепенный вопрос полковника Паника о бесконечно лениво оцененном итераторе, вот эти примеры, используя каждый из четырех вышеперечисленных методов:

# generator
def even_gen():
    result = 0
    while True:
        yield result
        result += 2


# generator expression
def even_genexp():
    return (num for num in even_gen())  # or even_iter or even_getitem
                                        # not much value under these circumstances

# iterator protocol
class even_iter():
    def __init__(self):
        self.value = 0
    def __iter__(self):
        return self
    def __next__(self):
        next_value = self.value
        self.value += 2
        return next_value

# getitem method
class even_getitem():
    def __getitem__(self, index):
        return index * 2

import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
    limit = random.randint(15, 30)
    count = 0
    for even in iterator():
        print even,
        count += 1
        if count >= limit:
            break
    print

Это приводит к (по крайней мере, для моего прогона пробела):

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
334
ответ дан Ethan Furman 19 August 2018 в 05:25
поделиться
  • 1
    Мне нравится это резюме, потому что оно завершено. Эти три способа (выход, выражение генератора и итератор) по существу одинаковы, хотя некоторые из них более удобны, чем другие. Оператор yield захватывает "продолжение" который содержит состояние (например, индекс, который мы делаем до). Информация сохраняется в "закрытии" продолжения. Итератор способ сохраняет одну и ту же информацию внутри полей итератора, что по сути является тем же, что и закрытие. Метод getitem немного отличается, поскольку он индексируется в содержимое и не является итеративным по своей природе. – Ian 5 July 2013 в 02:04
  • 2
    Вы не увеличиваете индекс в своем последнем подходе, uc_getitem(). Фактически при отражении он не должен увеличивать индекс, потому что он не поддерживает его. Но это также не способ абстрагировать итерацию. – Terrence Brannon 5 November 2013 в 17:25
  • 3
    @metaperl: Собственно, это так. Во всех четырех случаях вы можете использовать один и тот же код для итерации. – Ethan Furman 5 November 2013 в 18:37
  • 4
    @EthanFurman Я не эксперт, но не должно быть сброса индекса в классе uc_iter? То есть внутри метод iter устанавливает self.index в 0, так что следующий вызов итератора работает – Asterisk 19 April 2018 в 09:30
  • 5
    @Asterisk: Нет, экземпляр uc_iter должен истечь, когда это будет сделано (иначе это будет бесконечно); если вы хотите сделать это снова, вам нужно получить новый итератор, снова позвонив uc_iter(). – Ethan Furman 19 April 2018 в 16:13

Все ответы на этой странице действительно великолепны для сложного объекта. Но для тех, которые содержат встроенные типы итераторов как атрибуты, такие как str, list, set или dict или любая реализация collections.Iterable, вы можете опустить некоторые вещи в своем классе.

class Test(object):
    def __init__(self, string):
        self.string = string

    def __iter__(self):
        # since your string is already iterable
        return (ch for ch in string)

Его можно использовать как:

for x in Test("abcde"):
    print(x)

# prints
# a
# b
# c
# d
# e
0
ответ дан John Strood 19 August 2018 в 05:25
поделиться

В первую очередь модуль itertools невероятно полезен для всех случаев, когда итератор был бы полезен, но вот все, что вам нужно для создания итератора в python:

< blockquote>

yield

Разве это не круто? Выход можно использовать для замены нормального возврата в функции. Он возвращает объект одинаково, но вместо уничтожения состояния и выхода он сохраняет состояние, когда вы хотите выполнить следующую итерацию. Вот пример этого в действии, вытащенный непосредственно из списка функций itertools :

 def count(n=0):
     while True:
         yield n
         n += 1

Как указано в описании функций (это функция count () из модуля itertools ...), он создает итератор, который возвращает последовательные целые числа, начиная с n.

. Выражения генератора - это целая другая червь червей (удивительные черви!). Они могут использоваться вместо List Consrehension для сохранения памяти (для понимания списка создается список в памяти, который уничтожается после использования, если не назначен переменной, но выражения генератора могут создавать объект Generator. который является причудливым способом сказать Итератор). Ниже приведен пример определения выражения генератора:

gen = (n for n in xrange(0,11))

Это очень похоже на наше определение итератора выше, за исключением того, что полный диапазон задан в пределах от 0 до 10.

I только что нашел xrange () (удивил, что я не видел его раньше ...) и добавил его к приведенному выше примеру. xrange () - это итерируемая версия range (), которая имеет то преимущество, что не создала список. Было бы очень полезно, если бы у вас был гигантский массив данных для перебора и у него было столько памяти, чтобы сделать это.

98
ответ дан Jonathan 19 August 2018 в 05:25
поделиться
  • 1
    с python 3.0 больше нет xrange (), и новый диапазон () ведет себя как старый xrange () – user 18 December 2008 в 18:30
  • 2
    Вы все равно должны использовать xrange в 2._, потому что 2to3 переводит его автоматически. – Phob 22 July 2011 в 19:03

Я вижу, что некоторые из вас делают return self в __iter__. Я просто хотел бы отметить, что сам __iter__ может быть генератором (таким образом устраняя необходимость в __next__ и сбоях StopIteration)

class range:
  def __init__(self,a,b):
    self.a = a
    self.b = b
  def __iter__(self):
    i = self.a
    while i < self.b:
      yield i
      i+=1

Конечно, здесь можно было бы также сделать генератор, но для более сложных классов это может быть полезно.

84
ответ дан Manux 19 August 2018 в 05:25
поделиться
  • 1
    Большой! Это так скучно писать только return self в __iter__. Когда я попытался использовать yield, я обнаружил, что ваш код делает именно то, что я хочу попробовать. – Ray 5 February 2013 в 21:32
  • 2
    Но в этом случае, как реализовать next()? return iter(self).next()? – Lenna 5 April 2013 в 20:52
  • 3
    @Lenna, он уже «реализован». потому что iter (self) возвращает итератор, а не экземпляр диапазона. – Manux 7 April 2013 в 18:31
  • 4
    @Manux iter(range(5,10)).next() немного громоздко. По общему признанию, это плохой пример поведения next. Меня все еще интересует, как указать экземпляр диапазона next. – Lenna 24 April 2013 в 20:06
  • 5
    Это самый простой способ сделать это и не требует отслеживания, например, self.current или любой другой счетчик. Это должен быть голосовой ответ! – astrofrog 31 March 2014 в 14:35

Это итеративная функция без yield. Он использует функцию iter и замыкание, которое удерживает его состояние в изменяемом (list) в охватывающей области для python 2.

def count(low, high):
    counter = [0]
    def tmp():
        val = low + counter[0]
        if val < high:
            counter[0] += 1
            return val
        return None
    return iter(tmp, None)

Для Python 3 состояние закрытия сохраняется в неизменяемом в охватывающей области, а nonlocal используется в локальной области для обновления переменной состояния.

def count(low, high):
    counter = 0
    def tmp():
        nonlocal counter
        val = low + counter
        if val < high:
            counter += 1
            return val
        return None
    return iter(tmp, None)  

Тест;

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9
3
ответ дан Nizam Mohamed 19 August 2018 в 05:25
поделиться
  • 1
    Я всегда ценю умное использование двух-arg iter, но просто для того, чтобы быть ясным: это более сложный и менее эффективный, чем просто использование функции генератора на основе yield; Python имеет тонну поддержки интерпретатора для функций генератора на основе yield, которые вы не можете использовать здесь, делая этот код значительно медленнее. Тем не менее, проголосовали. – ShadowRanger 24 February 2018 в 02:30
Другие вопросы по тегам:

Похожие вопросы: