2016-11-17 87 views
2

基本上,如果我寫變回元素的功能,就像這樣:列表理解基礎上的選擇

def func(elem1=True, elem2=True, elem3=True, elem4=False): 
    x = MyClass() 
    ret = [] 
    if elem1: 
     ret.extend([x.func1()]) 
    if elem2: 
     ret.extend([x.obj1]) 
    if elem3: 
     ret.extend([x.func2().attr1]) 
    if elem4: 
     ret.extend(x.list_obj3) 
    return ret 

事情變得很長,多風。也許有可能做這樣的事情:

def func(elem1=True, elem2=True, elem3=True, elem4=False): 
    x = MyClass() 
    return [x.func1() if elem1, 
      x.obj1 if elem2, 
      x.func2().attr1 if elem3, 
      x.list_obj3 if elem4] 

這是多麼的完美!

我知道這是可以做到:

def func(elem1=True, elem2=True, elem3=True, elem4=False): 
    x = MyClass() 
    ret = [x.func1(), x.obj1, x.func2().attr1, x.list_obj3] 
    choices = [elem1, elem2, elem3, elem4] 
    return [r for i, r in enumerate(ret) if choices[i]] 

,但我想不計算元素;如果用戶不希望他們。計算它們中的一些是有點昂貴的。

回答

5

如果您在lambda表達式隱藏你的操作,那麼您可以使用懶評價:

def func(elem1=True, elem2=True, elem3=True, elem4=False): 
    x = MyClass() 
    return [L() for inc,L in (
      (elem1, lambda: x.func1()), 
      (elem2, lambda: x.obj1), 
      (elem3, lambda: x.func2().attr1), 
      (elem4, lambda: x.list_obj3), 
      ) if inc] 
1

問一個稍微不同的問題,你可以像MATLAB /八度,在這裏只計算前兩個結果的行爲,如果你分配給兩個變量,而不計算結果3和4?

例如:

a, b = func() 

Python中不能完全做到這一點,因爲FUNC()不知道有多少返回值就是了,但你可以使用接近:

from itertools import islice 
def func(): 
    x = MyClass() 
    yield x.fun c1() 
    yield x.obj1 
    yield x.func2().attr1 
    yield x.list_obj3 

a, b = islice(func(), 2) 

我不確定這是否更好,但是您可以使用裝飾器添加數組索引語義,這將允許您編寫:

@sliceable 
def func(): 
    ... 
a, b = func()[:2] 

這是很容易實現:

from itertools import islice 
class SlicedIterator(object): 
    def __init__(self, it): 
     self.it = it 
    def __iter__(self): 
     return self.it 
    def __getitem__(self, idx): 
     if not isinstance(idx, slice): 
      for _ in range(idx): next(self.it) 
      return next(self.it) 
     return list(islice(self.it, idx.start, idx.stop, idx.step)) 
def sliceable(f): 
    def wraps(*args, **kw): 
     return SlicedIterator(f(*args, **kw)) 
    return wraps 

測試:

@sliceable 
def f(): 
    print("compute 1") 
    yield 1 
    print("compute 2") 
    yield 2 
    print("compute 3") 
    yield 3 
    print("compute 4") 
    yield 4 

print("== compute all four") 
a, b, c, d = f() 
print("== compute first two") 
a, b = f()[:2] 
print("== compute one only") 
a = f()[0] 
print("== all as a list") 
a = f()[:] 

給出:

== compute all four 
compute 1 
compute 2 
compute 3 
compute 4 
== compute first two 
compute 1 
compute 2 
== compute one only 
compute 1 
== all as a list 
compute 1 
compute 2 
compute 3 
compute 4