Рубрики
Без рубрики

Интерфейсы Pythonic в Go Generators

Одна из удивительных вещей о Python заключается в том, что когда-то вы воплощаете так называемый дзен Питона, независимо от … Помечено с Python, иди.

Одна из удивительных вещей о Python – это то, что как только вы воплощаете так называемую Дзен Питона , независимо от того, какой язык вы используете, философия будет преобладать. Или, другими словами, даже если вы изучаете язык Go, степень этого эмофола Pythonistas, вероятно, найдет свой путь. Итак, для того, чтобы немного контекстуазировать, этот пост будет останавливаться на реализации механизма оценки Lazy List, эквивалентный генераторам Python, на языке Go.

Среди Питон Многие сверхспосовы, генераторы явно являются крупным. Привезены с функциональных языков, как Haskell. , которые продемонстрировали, насколько лучше ленивы с точки зрения скорости и управления памятью, особенно когда размер коллекций может расти бесконечно.

В Python Кроме того, помимо понимания списка, есть также менее известный словарь и ценители генератора. Быть позже, чем мы заинтересованы в объеме этого поста. Таким образом, учитывая, что мы хотим программа, которая получает пользовательский ввод, а затем распечатает все кратные 2 до определенного предела, неизвестен априори. Для таких, мы могли бы:

from itertools import (count, takewhile)

limit = int(input())
multiples_of_2 = takewhile(lambda x: x <= limit, (x*2 for x in count()))

for x in multiples_of_2:
    print(x)

Для простоты обратите внимание, что в предыдущем примере не было выполнено никакая проверка ошибок, касающихся пользовательского ввода. То же правило будет применяться к следующим примерам. Несмотря на это, можно использовать оператор доходности вместо использования генератора:

from itertools import count

def multiples_of_2(limit):
    for x in (x*2 for x in count()):
        if limit > 25:
            raise StopIteration
        yield x

limit = int(input())

for x in multiples_of_2(limit):
    print(x)

Для вашей информации эти примеры Python были предназначены для Python 3 Как некоторые из вас могут знать, функция ввода (), в Python 2, также уклоняется от входной строки, поведение, которое может привести к серьезным недостаткам безопасности. Поэтому, если вы все еще используете Python 2, вместо этого одолжите функцию RAW_INPUT ().

Хотя у нас нет той же конструкции, мы все еще можем использовать Идти Каналы до конца с очень похожим эффектом. В таких усилиях можно использовать два канала. Один для передачи данных как SE, а другой, чтобы сигнализировать, что верхний граничный предел был достигнут, поэтому закрывая канал данных. Это нужно для эмуляции Python Исключение задержания, которое сигнализирует о том, что генератор теперь пуст. Итак, без дальнейшего ADO:

package main

import "fmt"

func multiples_of_2(c chan int, quit chan struct{}, limit int) {
    for x := 0; true; x += 2 {
        if x > limit {
            quit <- struct{}{}
            break
        }

        c <- x
    }
}

func main() {
    var limit int
    fmt.Scan(&limit)

    c := make(chan int)
    quit := make(chan struct{})

    defer close(c)
    defer close(quit)

    go multiples_of_2(c, quit, limit)
    for {
        select {
        case x := <-c:
            fmt.Println(x)
        case <-quit:
            return
        }
    }
}

Обратите внимание, что канал Quit использует пустую структуру. Причина в два раза. Во-первых, пустые структуры не занимают пространство памяти, сумма, которая может быть существенной в масштабе. Во-вторых, как Дзэн Питона Государства: «Явнее лучше, чем неявное». Итак, путем прохождения пустой структуры, мы проясним, что вся точка этого конкретного канала предназначена только для сигнализации, поэтому избегая пользователей, чтобы удивляться, если существует разница между True и False, если, в противном случае, мы объявили, что канал как лол Канал, например.

Кроме того, интерфейс Multiples_of_2 очень много разоблачает бизнес-логику нашего пользовательского генератора. Кроме того, весь процесс инициализации/закрытия канала довольно повторяется. И Как Сухой Принцип проповедует, повторение – это корень всего зла. Не говоря уже о том, что мы могли бы решить эту проблему с одним каналом вместо двух. Но не бойтесь, что требуемый канал может быть инкапсулирован внутри multiples_of_2, что приводит к интерфейсу, которое очень похоже на Pythonic.

package main

import "fmt"

func multiples_of_2(limit int) (chan int) {
    c := make(chan int)

    go func() {
        defer close(c)
        for x := 0 ; true; x+=2 {
            if x > limit { break }

            c <- x
        }
    }()

    return c
}

func main() {
    var limit int
    fmt.Scan(&limit)

    for x:= range multiples_of_2(limit) {
        fmt.Println(x)
    }
}

Так что это все. За счет некоторой дополнительной работы в наших API, мы можем предоставить очень пифитонные интерфейсы для ленивых оценочных списков в Идти Отказ Теперь без необходимости вообще беспокоиться о каналах или параллелизме. На самом деле, Synchronousapis, как и последний пример, следует любить в Идти , с использованием синхронеусаписов в асинхронном виде легко в Идти , пока наоборот нет.

Оригинал: “https://dev.to/x8lucas8x/pythonic-interfaces-in-go-generators-6eo”