簡體   English   中英

在python函數中使用True,False和None作為返回值

[英]Use of True, False, and None as return values in python functions

我認為我完全理解這一點,但我只是想確保,因為我一直看到人們說永遠不會對TrueFalseNone 他們建議例程應該引發錯誤而不是返回False或None。 無論如何,我有很多情況我只想知道是否設置了一個標志,所以我的函數返回True或False。 如果沒有有用的結果,還有其他情況我有一個函數返回None。 從我的想法來看,只要我意識到我永遠不應該使用,就不會有問題:

if foo == True
if foo == False
if foo == None

而應該使用:

if foo is True
if foo is False
if foo is None

因為True,False和None都是單例,並且總是會在使用“is”而不是“==”時評估我的預期方式。 我錯了嗎?

沿着相同的路線,修改有時返回None的函數會更加pythonic,以便它們引發錯誤嗎? 假設我有一個名為“get_attr()”的實例方法,它從某個文件中檢索屬性。 如果它發現我請求的屬性不存在則返回None是否合適? 讓他們提出錯誤並在以后捕獲它會更好嗎?

建議不是你永遠不應該使用 TrueFalseNone 只是你不應該使用if x == True

if x == True是愚蠢的,因為==只是一個二元運算符! 它的返回值為TrueFalse ,具體取決於其參數是否相等。 如果condition為真, if condition將繼續。 所以,當你寫的if x == True Python是要首先評估x == True ,這將成為True ,如果xTrueFalse ,否則,然后進行如果這個結果是真實的。 但是,如果您期望xTrueFalse ,為什么不直接使用if x

同樣, x == False通常可以替換為not x

在某些情況下,您可能希望使用x == True 這是因為if語句條件是“在布爾上下文中計算”以查看它是否“真實”而不是完全針對True進行測試。 例如,非空字符串,列表和字典都被if語句認為是真實的,以及非零數字值,但這些都不等於True 因此,如果你想測試一個任意值是否恰好True值,而不僅僅是它是否真實,當你使用if x == True 但我幾乎從來沒有看到過這方面的用途。 如果您確實需要編寫它,那么值得添加評論是非常罕見的,因此未來的開發人員(包括可能是您自己)不僅僅假設== True是多余的並將其刪除。


使用x is True而實際上更糟糕。 你永遠不應該使用is基本的內置不可變的類型,如布爾( TrueFalse ),數字和字符串。 原因是對於這些類型我們關心的是價值觀 ,而不是身份 ==測試,值對於這些類型相同的,而is總測試身份。

測試身份而不是值是不好的,因為理論上實現可以構造新的布爾值而不是找到現有的布爾值,從而導致您有兩個具有相同值的True值但存儲在內存中的不同位置且具有不同的身份。 在實踐中,我非常確定Python解釋器總是重用TrueFalse ,所以這不會發生,但這確實是一個實現細節。 這個問題一直伴隨着字符串,因為直接出現在程序源中的短字符串和文字字符串被Python回收,所以'foo' is 'foo'總是返回True 但是以兩種不同的方式構造相同的字符串很容易,Python讓它們具有不同的身份。 請注意以下事項:

>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True

編輯:事實證明,Python在布爾值上的平等有點出乎意料(至少對我而言):

>>> True is 1
False
>>> True == 1
True
>>> True == 2
False
>>> False is 0
False
>>> False == 0
True
>>> False == 0.0
True

正如在Python 2.3.5中引入bool的注釋中所解釋的那樣,基本原理是使用整數1和0來表示True和False的舊行為是好的,但我們只是想要更多描述性的名稱來表示我們想要的數字代表真理價值觀。

實現這一目標的一種方法是在內置False = 0簡單地使用True = 1False = 0 ; 然后1和True真的無法區分(包括is )。 但這也意味着返回True的函數將在交互式解釋器中顯示1 ,因此所做的是創建bool作為int的子類型。 bool唯一不同的是strrepr ; bool實例仍然具有與int實例相同的數據,並且仍然以相同的方式比較相等,因此True == 1

所以這是錯誤的,使用x is True時, x可能已經被一些代碼,希望“真正的又是另一種拼寫1”設置,因為有很多方法來構建等於值True ,但不具備同樣的身份:

>>> a = 1L
>>> b = 1L
>>> c = 1
>>> d = 1.0
>>> a == True, b == True, c == True, d == True
(True, True, True, True)
>>> a is b, a is c, a is d, c is d
(False, False, False, False)

x可以是任意Python值並且你只想知道它是否是布爾值True時,使用x == True是錯誤的。 我們唯一確定的是,當你只想測試“真實性”時,只使用x是最好的。 值得慶幸的是,這通常都是必需的,至少在我寫的代碼中!

更確定的方法是x == True and type(x) is bool 但對於一個相當模糊的案例來說,這個問題變得非常冗長。 通過進行明確的類型檢查,它看起來也不像Pythonic ......但是當你試圖精確測試True而不是True時,這就是你正在做的事情。 duck typing方式是接受truthy值並允許任何用戶定義的類聲明自己是真實的。

如果你正在處理這個非常精確的真理概念,你不僅不認為非空集合是真的,而且也不認為1是真的,那么只使用x is True可能是好的,因為大概然后你知道x不是來自認為1為真的代碼。 我不認為有任何純粹的python方式來提出另一個存在於不同內存地址的True (盡管你可以從C中做到這一點),所以盡管理論上這是“錯誤”的事情,但這不應該打破去做。

而我以前認為布爾很簡單!

結束編輯


但是,在None的情況下, if x is None ,則使用成語。 在許多情況下, if not xif not x可以使用,因為Noneif語句的“falsey”值。 但是,如果您希望以相同的方式處理所有虛假值(零值數字類型,空集合和None ),則最好只執行此操作。 如果您正在使用或者是一些其他可能的值或值處理None表示“沒有價值”(如當函數返回None失敗),那么它的更好if x is None ,這樣你不當它碰巧返回一個空列表或數字0時,意外地認為該功能失敗了。

我使用的參數==而不是is不可變的值類型會建議你應該使用if x == None ,而不是if x is None 但是,在None的情況下,Python確實明確保證整個Universe中只有一個None ,而正常的慣用Python代碼使用的is


關於是返回None還是引發異常,它取決於上下文。

對於類似你的get_attr示例的東西,我希望它引發一個異常,因為我將像do_something_with(get_attr(file))一樣調用它。 調用者的正常期望是他們將獲得屬性值,並讓他們獲得None並假設屬性值比忘記處理異常更危險,如果屬性不能實際繼續被發現。 另外,返回None表示失敗意味着None不是屬性的有效值。 在某些情況下這可能是個問題。

對於像see_if_matching_file_exists這樣的虛函數,我們提供了一個模式,它檢查了幾個地方以查看是否存在匹配,如果找到匹配則返回匹配,否則返回None 但另外它可以返回一個匹配列表; 然后沒有匹配只是空列表(這也是“假的”;這是我只是使用if x ,看看我有什么回來的情況之一)。

因此,當在異常和None選擇之間進行選擇以指示失敗時,您必須確定None是否是預期的非失敗值,然后查看調用該函數的代碼的期望。 如果“正常”期望是返回有效值,並且只是偶爾調用者能夠正常工作,無論是否返回有效值,那么您應該使用異常來指示失敗。 如果沒有有效值是很常見的,那么調用者將期望處理這兩種可能性,然后你可以使用None

使用if foo或者if not foo ,就沒有必要對任何==或者is用於這一點。

要檢查None,建議使用is Noneis not None 這允許您將其與False(或評估為False的事物,如""[] )區分開來。

get_attr是否應返回None取決於上下文。 您可能有一個值為None的屬性,您將無法執行此操作。 我會將None解釋為“unset”,而KeyError意味着該文件中不存在該鍵。

如果檢查真相:

if foo

為假:

if not foo

沒有:

if foo is None

對於非人:

if foo is not None

對於getattr() ,正確的行為不是返回None而是引發AttributError錯誤 - 除非你的類類似於defaultdict

關於是否提出異常或返回None :這取決於用例。 兩者都可以是pythonic。 看python的dict類,例如, x[y]掛鈎到dict.__getitem__和它提出了一個KeyError如果密鑰不存在。 但是如果key不存在,則dict.get方法返回第二個參數(默認為None )。 它們都很有用。

要考慮的最重要的事情是在docstring中記錄該行為,並確保您的get_attr()方法執行它所說的功能。

要解決您的其他問題,請使用以下約定:

if foo:
    # for testing truthiness

if not foo:
    # for testing falsiness

if foo is None:
    # testing .. Noneliness ?

if foo is not None:
    # check explicitly avoids common bugs caused by empty sequences being false

返回TrueFalse函數應該有一個名稱,可以明顯改善代碼的可讀性

def is_running_on_windows():
    return os.name == 'nt'

在python3中你可以“輸入提示”:

>>> def is_running_on_windows() -> bool:
...     return os.name == 'nt'
... 
>>> is_running_on_windows.__annotations__
{'return': bool}

PEP 8(Python代碼樣式指南)文檔中的示例中,我看到foo is Nonefoo is not None而不是foo == Nonefoo != None if boolean_value在本文檔中推薦使用if boolean_value ,而不是if boolean_value == True或者if boolean_value is True 所以我認為如果這是官方的Python方式,我們Python的人也應該這樣做。

問候。

您可以直接檢查該變量是否包含值, if varnot var

要確保的一件事是沒有任何東西可以重新分配你的變量。 如果它最終不是布爾值,依賴真實性將導致錯誤。 動態類型語言中條件編程的美妙:)。

以下打印“ ”。

x = False
if x:
    print 'yes'
else:
    print 'no'

現在讓我們改變x

x = 'False'

現在語句打印“ ”,因為字符串是真的。

if x:
    print 'yes'
else:
    print 'no'

但是,該陳述正確地輸出“ ”。

if x == True:
    print 'yes'
else:
    print 'no'

對於虛構的getattr函數,如果請求的屬性始終可用但不是,則拋出錯誤。 如果屬性是可選的,則返回None

為真,而不是沒有:

if foo:

為假,沒有:

if not foo:

暫無
暫無

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

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