簡體   English   中英

Python 中的 + (pos) 一元運算符的目的是什么?

[英]What's the purpose of the + (pos) unary operator in Python?

一般來說,Python中的一元+應該做什么?

我問是因為到目前為止,我從未見過這樣的情況:

+obj != obj

其中obj是實現__pos__()的通用 object 。

所以我想知道:為什么+__pos__()存在? 你能提供一個真實的例子,上面的表達式計算為True嗎?

這是來自decimal包的“真實世界”示例:

>>> from decimal import Decimal
>>> obj = Decimal('3.1415926535897932384626433832795028841971')
>>> +obj != obj  # The __pos__ function rounds back to normal precision
True
>>> obj
Decimal('3.1415926535897932384626433832795028841971')
>>> +obj
Decimal('3.141592653589793238462643383')

在 Python 3.3 及更高版本中, collections.Counter使用+運算符來刪除非正數。

>>> from collections import Counter
>>> fruits = Counter({'apples': 0, 'pears': 4, 'oranges': -89})
>>> fruits
Counter({'pears': 4, 'apples': 0, 'oranges': -89})
>>> +fruits
Counter({'pears': 4})

因此,如果Counter有負數或零計數,則會出現+obj != obj

>>> obj = Counter({'a': 0})
>>> +obj != obj
True

我相信 Python 運算符的靈感來自 C,其中引入了+運算符以實現對稱(還有一些有用的技巧,請參閱注釋)。

在弱類型語言(如 PHP 或 Javascript)中,+ 告訴運行時將變量的值強制轉換為數字。 例如,在 Javascript 中:

   +"2" + 1
=> 3
   "2" + 1
=> '21'

Python 是強類型的,因此字符串不能用作數字,因此不實現一元加號運算符。

當然可以實現一個 +obj != obj 的對象:

>>> class Foo(object):
...     def __pos__(self):
...        return "bar"
... 
>>> +Foo()
'bar'
>>> obj = Foo()
>>> +"a"

至於實際有意義的示例,請查看超現實數字 它們是實數的超集,包括無窮小的值 (+ epsilon, - epsilon),其中 epsilon 是一個正值,它小於任何其他正數,但大於 0; 和無窮大(+無窮大,-無窮大)。

您可以定義epsilon = +0-epsilon = -0

雖然1/0仍未定義,但1/epsilon = 1/+0+infinity ,而1/-epsilon = -infinity x從右邊 (+) 或從左邊 (-) 趨近0 ,它只不過是取1/x極限。

由於0+0行為不同,因此0 != +0是有道理的。

對於對稱,因為一元減號是一個運算符,所以一元加號也必須是。 在大多數算術情況下,它不做任何事情,但請記住,用戶可以定義任意類並將這些運算符用於他們想要的任何東西,即使它不是嚴格的代數。

我知道這是一個舊線程,但我想擴展現有答案以提供更廣泛的示例:

  • +可以斷言肯定性,如果不是,則拋出異常 - 對於檢測極端情況非常有用。
  • 該對象可能是多值的(將±sqrt(z)視為單個對象——用於求解二次方程、多分支分析函數、任何可以將雙值函數“折疊”為帶有符號的分支的任何東西。這包括 ±0 vlopez 提到的案例。
  • 如果您進行惰性求值,這可能會創建一個函數對象,將某些內容添加到應用於其他內容的任何內容中。 例如,如果您以增量方式解析算術。
  • 作為身份函數作為參數傳遞給某些函數。
  • 對於符號累積的代數結構——梯形運算符等。 當然,它可以用其他函數來完成,但可以想象看到像y=+++---+++x這樣的東西。 更重要的是,他們不必通勤。 這構建了一組可能有用的免費加號和減號。 即使在正式的語法實現中。
  • 瘋狂用法:它可以在某種意義上將計算中的一個步驟“標記”為“活動”。 收割/播種系統——每一個加號都會記住價值,最后,你可以收集收集到的中間體......因為為什么不呢?

那,加上其他人提到的所有類型轉換原因。

畢竟……如果您需要的話,再多一個操作員就好了。

這里的很多例子看起來更像是錯誤。 不過,這實際上是一個功能:

+運算符意味着一個副本

這在為標量和數組編寫通用代碼時非常有用。

例如:

def f(x, y):
    z = +x
    z += y
    return z

此功能上標量NumPy的陣列工作未做額外的副本並沒有改變對象的類型,無需任何外部依賴!

如果您使用numpy.positive或類似的東西,您將引入 NumPy 依賴項,並且您將強制數字為 NumPy 類型,這可能是調用者不希望的。

如果你做了z = x + y ,你的結果將不再一定是與x相同的類型。 在許多情況下這很好,但如果不是,則不是一種選擇。

如果你做了z = --x ,你會創建一個不必要的副本,這很慢。

如果你做了z = 1 * x ,你會執行一個不必要的乘法,這也很慢。

如果你做了copy.copy ......我想那會起作用,但它很麻煩。

Unary +是一個非常好的選擇。

__pos__()存在於Python 中,為程序員提供與C++語言類似的可能性——重載運算符,在這種情況下是一元運算符+

重載運算符意味着為不同的對象賦予它們不同的含義,例如二進制+數字字符串的行為不同——在連接字符串時添加數字。)

對象可以實現(除其他之外)這些模擬數字類型的函數(方法):

    __pos__(self)             # called for unary +
    __neg__(self)             # called for unary -
    __invert__(self)          # called for unary ~

所以+objectobject.__pos__()意思相同——它們可以互換。

然而, +object更容易被人看到。

特定對象的創建者可以自由地按照自己的意願實現這些功能——正如其他人在他們現實世界的例子中所展示的那樣。

還有我的貢獻——開個玩笑: ++i != +i in C/C++

一元+實際上是查看值是否為數字的最快方法(如果不是則引發異常)! 它是字節碼中的一條指令,其中諸如 isinstance(i, int) 之類的東西實際上查找並調用了isinstance函數!

暫無
暫無

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

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