簡體   English   中英

如何使用遞歸創建一個生成器?

[英]How to create a generator with recursion?

Hacker's Delight 2nd Edition中的算法

移植到python

一個簡單的希爾伯特曲線類。

class Hilbert():

    def __init__(self,order=1):

            self.x = -1 
            self.y = 0     
            self._step(0)
            self._hil(0, 1, order)

    def _hil(self, dirs, rot, order):
        if (order == 0): 
            return

        dirs += rot
        self._hil(dirs, -rot, (order-1))
        self._step(dirs)
        dirs -= rot
        self._hil(dirs, rot, (order-1))
        self._step(dirs)
        self._hil(dirs, rot, (order-1))
        dirs -= rot
        self._step(dirs)
        self._hil(dirs, -rot, (order-1))


    def _step(self, dirs):
        dirs %= 4

        if dirs == 0:
            self.x += 1
        elif dirs == 1:
            self.y += 1
        elif dirs == 2:
            self.x -= 1
        else:
            self.y -= 1 
        #prints all points 
        #print(self.x,self.y)
        #Could I "iterate" from here.

所以我想要的是每次調用next()都給出(x,y)的東西。 我自己嘗試過執行此操作,但無法使其正常工作,因此將不勝感激。 我必須重寫此代碼才能使用生成器嗎? 資源

我想你想做些什么,至少部分是把_hil變成發電機的功能,其產生x, y對每次通話后_step 如果是這樣,那很容易。

困難的部分是那些遞歸調用。 但這一點都不難。 這正是yield from目的:*進行一些迭代器(例如對生成器函數的遞歸調用)並產生其每個值。**

然后是簡單的部分,每次調用_step之后, x, y對的非遞歸產生。 您可以在每次調用后使用明確的yield self.x, self.y來實現。 或者,您可以更改_step來添加return self.x, self.y ,因此只需yield self._step(dirs) 但是,您也可以將_step更改為僅迭代一個值的迭代器,然后也可以從中進行yield from (這里並沒有真正的優勢,但是我認為值得展示,因此您可以仔細考慮它的工作方式-特別是因為您在_step詢問了“我可以從這里進行迭代嗎?”。)

def _hil(self, dirs, rot, order):
    if (order == 0): 
        return

    dirs += rot
    yield from self._hil(dirs, -rot, (order-1))
    yield from self._step(dirs)
    dirs -= rot
    yield from self._hil(dirs, rot, (order-1))
    yield from self._step(dirs)
    yield from self._hil(dirs, rot, (order-1))
    dirs -= rot
    yield from self._step(dirs)
    yield from self._hil(dirs, -rot, (order-1))

def _step(self, dirs):
    # existing code
    yield self.x, self.y

但是現在您有了__init___hil調用_hil而對結果不執行任何操作。 那不是很有用。 也許您正在嘗試將Hilbert類本身變成迭代器類?

在這種情況下,最簡單的方法是存儲生成器迭代器並將其委托給它:

def __init__(self, order=1):
    self.x = -1 
    self.y = 0     
    self._step(0)
    self.iter = self._hil(0, 1, order)

def __iter__(self):
    return self

def __next__(self):
    return next(self.iter)

但是,在這一點上,我不確定為什么您需要將它作為一堂課。 xy是不是真的對象的狀態的一部分,他們是發電機狀態,它是由Python將采取的神奇護理的一部分,如果你只是用在局部變量_hil (和正常的參數和返回傳遞_step ) 。 而唯一的其他狀態是self.iter ,這僅是必需的,因為您是在編寫類而不是函數。


*實際上,正如格雷格·尤因Greg Ewing)驚人地描述的那樣,事實證明,它所帶來的好處遠不止這些; 沒有它,我們將不會有asyncio 但是將其添加到語言的最初原因是“委派給子生成器的語法”。

**請注意,這僅在您yield from – 3.3或更高版本的Python中獲得 yield from時才有效。 如果您仍在使用Python 2.x,並且yield from不足以使您升級,則可以通過將每種yield from eggs轉換for egg in eggs: yield egg來模擬它的某些用途(包括此用途) for egg in eggs: yield egg 它不會像以前那樣可讀,而且速度會慢得多,但是會起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM