2014-02-06 47 views
4

[由this question啓發]函數樣可變

假設我有兩個列表:

list1 = ['tom', 'mary', 'frank', 'joe', 'john', 'barry'] 
list2 = [1, 2, 3, 4] 

我想每名list1list2一個數量相匹配。由於list2中有四個數字,因此我想將前四個名稱中的每一個與list2中的相應數字進行配對,並將隨機數字分配給list1中的其餘名稱。

我知道我可以使用for循環與enumeraterandom.choice解決此問題。事實上,我提供了such a solution來解決原始問題。
我想不過要知道,如果有可能做這樣的事情:

for name, number in itertools.izip_longest(list1, list2, fillvalue=MAGIC): 
    print name, number 

本來,我想用這樣的事情的:

MAGIC = random.choice(list1) 

但是,執行random.choice(list1)第一,然後將該答案用作壓縮操作的fillvalue。這是沒有吸引力的,因爲它不會爲每一對拉值選擇一個新的隨機值。因此很明顯,itertools.izip_longest要求它的fillvalue,它本身具有價值,它不稱之爲。事實上,如果我要提供一個函數,它將產生一個由名稱和可調用函數組成的對,這也是不足的。出於這個原因,lambda函數是不可行的解決方案。

我該如何去創建一個變量來調用某個函數? itertools.izip_longest如何使用fillvalue變量?該變量的__repr__被稱爲?如果是這樣,我可以用__repr__做一個類,它在裏面調用一個函數嗎?

+2

「如何創建一個在調用某個函數時調用某個函數的變量?」 - 你不會的。你會調用一個函數。 – user2357112

+0

您可以使用屬性來獲得對象屬性所需的內容,並且在Python 3中,您可以使用令人討厭的元類魔術獲得想要的類,但是對於常規變量,您不能這樣做。 – user2357112

+0

@ user2357112:是的,但許多類的實例在「被調用」時顯示它們的__repr__值。因此,如果'__repr__'要調用某個外部函數,那麼突然之間,您將擁有一個變量,該變量包含一個實例,該實例的值由函數確定。否則,我確實很熟悉變量和函數之間的區別。 – inspectorG4dget

回答

8

在這裏似乎最簡單的方法是創建一個發生器產生的所有永恆的填充值,然後在列表2屈服值連鎖這樣的:

def inf_gen(f): 
    while True: 
     yield f() 

注意inf_gen(f)實際上相當於iter(f, None),因爲f永遠不會返回。帶有兩個參數的iter調用第一個參數,直到它返回第二個參數。通過使用一臺發電機理解與itertools.count

>>> from itertools import izip, chain 
>>> for name, number in izip(list1,chain(list2, iter(lambda: random.choice(list2), None))): 
    print name, number 

tom 1 
mary 2 
frank 3 
joe 4 
john 1 
barry 4 

你也可以這樣做只是itertools的東西,而定義一個單獨的功能:如果你想讓它

>>> from itertools import izip, chain, count 
>>> for name, number in izip(list1, chain(list2, (random.choice(list2) for _ in count()))): 
    print name, number 
+0

「iter」的雙參數形式本質上就是'inf_gen'。 – chepner

+0

@chepner:哦,真好!完全忘了它。將更新答案 – Claudiu

3

然後使用它是這樣爲了「縮放」到多個迭代器,您可以通過對http://docs.python.org/2.7/library/itertools.html?highlight=izip_longest#itertools.izip_longest中給出的代碼稍作修改來完成:

from itertools import repeat, chain, count 

class ZipExhausted(Exception): 
    pass 

def izip_longest2(*args, **kwds): 
    fillvalue = kwds.get('fillvalue') 
    fillgen = kwds.get('fillgen', repeat(fillvalue)) # added 
    counter = [len(args) - 1] 
    def sentinel(): 
     if not counter[0]: 
      raise ZipExhausted 
     counter[0] -= 1 
     yield next(fillgen) # modified 
    iterators = [chain(it, sentinel(), fillgen) for it in args] # modified 
    try: 
     while iterators: 
      yield tuple(map(next, iterators)) 
    except ZipExhausted: 
     pass 


a = ['bob', 'mary', 'paul'] 
b = ['eggs', 'spam'] 
c = ['a', 'b', 'c', 'd'] 

for x in izip_longest2(a, b, c, fillgen=count()): 
    print '\t'.join(map(str, x)) 

# output: 
# bob eggs a 
# mary spam b 
# paul 0 c 
# 1 2 d 
+1

請修復您的縮進? – inspectorG4dget

+0

編輯:固定縮進,感謝指出,@ inspectorG4dget –

+0

這實際上相當輝煌!謝謝 :) – inspectorG4dget