2012-06-14 20 views
1

我有這樣的代碼:隱式調用的對象結合實例

class LFSeq: # lazy infinite sequence with new elements from func 
    def __init__(self, func): 
     self.evaluated = [] 
     self.func = func 
    class __iter__: 
     def __init__(self, seq): 
      self.index = 0 
      self.seq = seq 
     def next(self): 
      if self.index >= len(self.seq.evaluated): 
       self.seq.evaluated += [self.seq.func()] 
      self.index += 1 
      return self.seq.evaluated[self.index - 1] 

而且我明確地想要那個LFSeq.__iter__界變得像任何其它用戶定義的函數本來的LFSeq一個實例。

雖然這種方式不起作用,因爲只有用戶定義的函數是有界的而不是類。

當我介紹一個函數裝飾像

def bound(f): 
    def dummy(*args, **kwargs): 
     return f(*args, **kwargs) 
    return dummy 

然後我可以裝點通過它__iter__和它的作品:

... 
@bound 
class __iter__: 
    ... 

這在某種程度上但是感覺哈克和不一致。有沒有其他方法?應該是這樣嗎?

我想是的,因爲否則LFSeq.__iter__LFSeq(None).__iter__不會再是同一個對象(即類對象)。也許關於有界函數的整個事情應該是語法糖,而不是在運行時使用它。但是,另一方面,語法糖不應該依賴於內容。我想在某個地方必須有一些權衡。

回答

3

爲你正在嘗試做的最簡單的方法是定義你的__iter__()方法作爲發電機功能:

class LFSeq(object): 
    def __init__(self, func): 
     self.evaluated = [] 
     self.func = func 
    def __iter__(self): 
     index = 0 
     while True: 
      if index == len(self.evaluated): 
       self.evaluated.append(self.func()) 
      yield self.evaluated[index] 
      index += 1 

你的方法必須處理大量的Python對象模型的細微之處,並有沒有理由走這條路。

2

在我看來,最好的解決方案是@Sven one,毫無疑問。也就是說,你試圖做的事情看起來非常黑客 - 我的意思是,將__iter__定義爲一個類。它不會工作,因爲在另一個類中聲明一個類不像定義方法,而是它就像定義屬性一樣。該代碼

class LFSeq: 
    class __iter__: 

大致相當於歸屬,將創建一個類字段:

class LFSeq: 
    __iter__ = type('__iter__',(), ...) 

然後,每次你定義一個類內部的屬性,這勢必類本身,而不是特定的實例。

我認爲你應該遵循@Sven解決方案,但是如果你真的想爲任何其他原因定義一個類,看起來你很幸運,因爲你的生成器類不依賴於LFSeq實例本身。外面定義迭代器類:

class Iterator(object): 
    def __init__(self, seq): 
     self.index = 0 
     self.seq = seq 
    def next(self): 
     if self.index >= len(self.seq.evaluated): 
      self.seq.evaluated += [self.seq.func()] 
     self.index += 1 
     return self.seq.evaluated[self.index - 1] 

並創建實例裏面LFSeq.__iter__()方法:

class LFSeq(object): # lazy infinite sequence with new elements from func 
    def __init__(self, func): 
     self.evaluated = [] 
     self.func = func 
    def __iter__(self): 
     return Iterator(self) 

如果最終需要迭代器類綁定到該實例,你可以定義裏面LFSeq.__init__()迭代器類,把它放在一個self屬性和實例化它在LFSeq.__iter__()

class LFSeq(object): # lazy infinite sequence with new elements from func 
    def __init__(self, func): 

     lfseq_self = self # For using inside the iterator class 

     class Iterator(object): # Iterator class defined inside __init__ 
      def __init__(self): 
       self.index = 0 
       self.seq = lfseq_self # using the outside self 
      def next(self): 
       if self.index >= len(self.seq.evaluated): 
        self.seq.evaluated += [self.seq.func()] 
       self.index += 1 
       return self.seq.evaluated[self.index - 1] 

     self.iterator_class = Iterator # setting the itrator 
     self.evaluated = [] 
     self.func = func 

    def __iter__(self): 
     return self.iterator_class() # Creating an iterator 

正如我甲肝e說,然而,@Sven解決方案似乎更好。我只是回答了一些問題,試圖解釋爲什麼你的代碼沒有按照你的預期行事,並提供一些你想做的事情的信息 - 儘管如此,這些信息可能有用。