簡體   English   中英

你如何根據數據類型在python中設置條件?

[英]How do you set a conditional in python based on datatypes?

這個問題看起來很簡單,但我想不通。 我知道您可以在 python 中檢查數據類型,但是如何根據數據類型設置條件? 例如,如果我必須編寫一個對字典/列表進行排序並將所有整數相加的代碼,我如何隔離搜索以僅查找整數?

我想一個簡單的例子看起來像這樣:

y = []
for x in somelist:
    if type(x) == <type 'int'>:  ### <--- psuedo-code line
    y.append(x)
print sum(int(z) for z in y)

那么對於第 3 行,我將如何設置這樣的條件?

怎么樣,

if isinstance(x, int):

但更清潔的方法就是

sum(z for z in y if isinstance(z, int))

域名注冊地址:

  • 使用if isinstance(x, int):除非你有理由不這樣做。
  • if type(x) is int:如果您需要精確的類型相等而不是其他任何東西。
  • 如果您可以轉換為目標類型,請使用try: ix = int(x)

在 Python 中進行類型檢查有一個非常大的“取決於”。 處理類型的方法有很多種,各有優缺點。 在 Python3 中,出現了更多。

顯式類型相等

類型是一流的對象,您可以像對待任何其他值一樣對待它們。 因此,如果您希望某事物的類型等於int ,只需對其進行測試:

if type(x) is int:

這是最嚴格的測試類型:它需要精確的類型相等。 通常,這不是您想要的:

  • 它排除了替代類型: float是無效的,即使它在許多用途上表現得像一個int
  • 它排除了子類和抽象類型:即使它們在邏輯上是整數,也會拒絕打印漂亮的int子類或enum
    • 這嚴重限制了便攜性:Python2字符串可以strunicode ,並且整數可以intlong

需要注意的是顯式類型的平等其低級別操作的用途:

  • 某些類型不能被子類化,例如slice 明確的檢查在這里更明確。
  • 一些低級操作,例如序列化或 C-API,需要特定類型。

變體

也可以對__class__屬性進行比較:

if x.__class__ is int:

請注意,如果類定義了__class__屬性,則這與type(x)

當有多個類要檢查時,使用dict來分派動作比顯式檢查更具可擴展性並且可以更快(≥5-10 類型)。 這對於轉換和序列化特別有用:

dispatch_dict = {float: round, str: int, int: lambda x: x}
def convert(x):
    converter = self.dispatch_dict[type(x)]  # lookup callable based on type
    return converter(x)

顯式類型的實例檢查

慣用類型測試使用isinstance內置

if isinstance(x, int):

這種檢查既准確又高效。 這通常是人們想要檢查類型的內容:

  • 它正確處理子類型。 打印漂亮的int子類仍將通過此測試。
  • 它允許一次檢查多種類型。 在 Python2 中,執行isinstance(x, (int, long))可以獲得所有內置整數。

最重要的是,在大多數情況下,缺點可以忽略不計:

  • 它仍然接受行為怪異的時髦子類。 由於任何事物都可能以奇怪的方式運行,因此無法防范。
  • 它很容易變得過於嚴格:許多人在任何序列(例如tuple )甚至可迭代(例如generator )也可以這樣做時檢查isinstance(x, list) 對於通用庫而言,這比腳本或應用程序更值得關注。

變體

如果您已經有一個類型,則issubclass行為相同:

if issubclass(x_type, int):

抽象類型的實例檢查

Python 有一個抽象基類的概念。 粗略地說,這些表達了類型的含義,而不是它們的層次結構:

if isinstance(x, numbers.Real):  # accept anything you can sum up like a number

換句話說, type(x) 不一定從numbers.Real繼承,但必須表現得像它。 盡管如此,這是一個非常復雜和困難的概念:

  • 如果您正在尋找基本類型,這通常是矯枉過正。 大多數情況下,Integer 只是一個int
  • 來自其他語言的人經常混淆它的概念。
    • 將其與例如 C++ 區分開來,重點是抽象基類而不是抽象基類。
    • ABC 可以像 Java 接口一樣使用,但可能仍然具有具體的功能。

但是,它對於通用庫和抽象非常有用。

  • 許多函數/算法不需要顯式類型,只需要它們的行為。
    • 如果您只需要按鍵查找內容, dict您限制為特定的內存類型。 相比之下, collections.abc.Mapping還包括數據庫包裝器、大型磁盤支持的字典、惰性容器、... - 和dict
  • 它允許表達部分類型約束。
    • 沒有嚴格的基本類型實現迭代。 但是如果你根據collections.abc.Iterable檢查對象,它們都在for循環中工作。
  • 它允許創建單獨的、優化的實現,這些實現顯示為相同的抽象類型。

雖然一次性腳本通常不需要它,但我強烈建議將它用於除幾個 Python 版本之外的任何內容。

暫定轉換

處理類型的慣用方式不是測試它們,而是假設它們是兼容的。 如果您已經預料到輸入中有一些錯誤的類型,只需跳過所有不兼容的內容:

try:
    ix = int(x)
except (ValueError, TypeError):
    continue  # not compatible with int, try the next one
else:
    a.append(ix)

這實際上不是類型檢查,但通常用於相同的目的。

  • 保證您在輸出中具有預期的類型。
  • 它在轉換錯誤類型方面有一些有限的回旋余地,例如將float專門化為int
  • 它可以在您不知道哪些類型符合int

主要的缺點是它是一個顯式轉換。

  • 您可以默默地接受“錯誤”值,例如轉換包含文字的str
  • 它不必要地轉換甚至足夠好的類型,例如,當您只需要數字時,將floatint

轉換是某些特定用例的有效工具。 如果您粗略地知道您的輸入是什么,並且必須保證您的輸出,則效果最佳。

函數調度

有時類型檢查的目標只是選擇一個合適的函數。 在這種情況下,諸如functools.singledispatch函數調度允許對特定類型進行專門的函數實現:

@singledispatch
def append_int(value, sequence):
    return

@append_int.register
def _(value: int, sequence):
    sequence.append(value)

這是isinstancedict調度的組合。 它對於較大的應用程序最有用:

  • 無論調度類型的數量如何,它都會使使用站點保持較小。
  • 它允許稍后為其他類型注冊特化,甚至在其他模塊中。

盡管如此,它也並非沒有缺點:

  • 許多 Python 程序員起源於函數式和強類型語言,並不熟悉單分派甚至多分派。
  • 調度需要單獨的功能,因此不適合在使用地點定義。
    • 創建函數和“預熱”調度緩存需要顯着的運行時開銷。 調度函數應該定義一次並經常重復使用。
    • 即使是預熱的調度表也比手寫的 if/else 或dict查找慢。

控制輸入

最好的做法是確保您永遠不必首先檢查類型。 這有點像元主題,因為它在很大程度上取決於用例。

在這里, somelist的來源somelist應該將非數字放入其中。

讓我聲明 int 類型的變量 x

x = 2
if type(x) == type(1) or isinstance(x, int):  
    # do something

兩者都工作正常。

您可以像這樣簡單地使用類型和等號運算符

if (type(x) == int):

易於使用的類型。

import types
k = 5
if(type(k)==types.IntType):
   print "int"

這是一個快速目錄(類型):

['BooleanType', 'BufferType', 'BuiltinFunctionType', 'BuiltinMethodType', 'ClassType', 'CodeType', 'ComplexType', 'DictProxyType', 'DictType', 'DictionaryType', 'EllipsisType', 'FileType', 'FloatType', 'FrameType', 'FunctionType', 'GeneratorType', 'GetSetDescriptorType', 'InstanceType', 'IntType', 'LambdaType', 'ListType', 'LongType', 'MemberDescriptorType', 'MethodType', 'ModuleType', 'NoneType', 'NotImplementedType', 'ObjectType', 'SliceType', 'StringType', 'StringTypes', 'TracebackType', 'TupleType', 'TypeType', 'UnboundMethodType', 'UnicodeType', 'XRangeType', '__builtins__', '__doc__', '__file__', '__name__', '__package__']

您可以在運算符的兩側使用 type 函數。 像這樣:

if type(x) == type(1):

暫無
暫無

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

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