2013-10-04 47 views
1

operator模塊可以很容易地避免這樣的情況中不必要的功能和lambda表達式 :爲什麼操作員模塊缺少`and`和`or`?

import operator 

def mytest(op, list1, list2): 
    ok = [op(i1, i2) for i1, i2 in zip(list1, list2)] 
    return all(ok) 

mytest(operator.eq, [1, 2, 3], [1, 2, 3])   # True 
mytest(operator.add, [-1, 2, -3], [1, -2, 33]) # False 

好了,現在我需要做的i1 and i2,但讓我驚訝的是,我不能操作模塊中找到and !這同樣適用於or!我知道,and是不完全操作,這是一個關鍵字,但not,與is甚至del一起,是所有關鍵字,所有都包括在內。

那麼故事是怎麼回事?他們爲什麼失蹤?

+2

operator.and_和operator.or_都在那裏。其他關鍵字操作符也一樣,您需要_。 – tdelaney

+1

'operator.and_'和'operator.or_'是按位運算符'&'和'|',而不是邏輯'和'和'or'。 – kindall

+1

作爲一個方面說明,你並不需要'ok'來成爲一個列表。如果'list1'和'list2'可以非常大,尤其是如果可能在列表中顯示錯誤,那麼使用生成器表達式而不是listcomp會好得多(並且,如果'重新使用2.x,'itertools.izip'而不是'zip')。 – abarnert

回答

7

因爲你不能將布爾運算符轉換成python函數。函數總是評估它們的參數,布爾運算符不會。將andor添加到運算符模塊還需要添加一些特殊類型的函數(如lisp「宏」),以根據需要評估它們的參數。顯然,這不是蟒蛇設計師想要的東西。考慮:

if obj is not None and obj.is_valid(): 
    .... 

你不能以功能性的形式寫這個。如果obj實際上是None

if operator.xyz(obj is not None, obj.is_valid()) 

試圖將失敗。

+0

在許多情況下,您正在尋找類似'和'或'或'的東西,但不會短路。在這種情況下,你可以寫一個單行函數(非行或lambda)並使用它。它不包含在'operator'中的原因是它與'和'不同(因爲它不會短路),這意味着(a)它可能誤導人們認爲它是,(b)它會破壞「運營商完全映射到運營商功能」的漂亮設計。 – abarnert

2

你可以自己寫這些,但是假設通常的短路行爲對你很重要,你需要爲第二個參數傳遞一個函數(例如lambda)以防止它在通話時被評估。

def func_or(val1, fval2): 
    return val1 or fval2() 

def func_and(val1, fval2): 
    return val1 and fval2() 

用法:

func_or(False, lambda: True) 
func_and(True, lambda: False) 
1

之所以沒有operator.andand是一個關鍵字,所以這將是一個SyntaxError

由於tgh435解釋,有一個在operator沒有改名and功能的原因是,它會產生誤導:函數調用始終計算它的操作數,但and運營商沒有。 (這也將是一個例外,否則一致和簡單的規則。)


在你的情況下,它看起來像你不真正關心短路可言,所以可以平凡建立你自己的版本:

def and_(a, b): 
    return a and b 

或者,如果你只是使用它,甚至一度聯:

mytest(lambda a, b: a and b, [-1, 2, -3], [1, -2, 33]) 

在某些情況下,它的w ^正看着all(和or,any)。它被有效地短路and擴展爲任意操作數。當然,它具有與operator函數不同的API,只需要一個操作數的迭代而不是兩個單獨的操作數。而它短路的方式是不同的;它只是停止迭代迭代器,這隻有在你設置好的時候纔會有幫助,所以迭代器只根據需要進行評估。所以,它通常不可用作插入式替代品,但如果重構代碼有時可用。