【问题标题】:Python: type checking of complex returned valuesPython:复杂返回值的类型检查
【发布时间】:2013-12-16 15:34:10
【问题描述】:

我正在编写一个调用其他人编写的代码的框架(该框架播放 Monopoly 并调用玩家 AI)。 AI 告诉框架在函数调用的返回值中要做什么。

我想检查返回值的类型以确保它们不会破坏我的框架代码。

例如:

instructions = player.sell_houses()
# Process the instructions...

在这个例子中,我希望玩家返回一个元组列表,例如:

[(Square.BOW_STREET, 2), (Square.MARLBOROUGH_STREET, 2), (Square.VINE_STREET, 1)]

是否有一种简单(ish)的方式来验证人工智能返回给我的内容?我在想象这样的事情:

    instructions = player.sell_houses()
    if not typecheck(instructions, [(str, int)]):
        # Data was not valid...

我不只是想检查返回的数据是否是一个列表。我想检查它是否是特定类型的列表。在示例中,它是一个元组列表,其中每个元组包含一个字符串和一个整数。

我看到很多 Python 类型检查问题的答案都是“类型检查是邪恶的”。如果是这样,在这种情况下我应该怎么做?似乎没有任何东西可以阻止 AI 代码返回任何东西,我必须能够以某种方式验证或处理它。


编辑:我可以通过编写函数来“手动”检查。对于上面的instructions,它可能是这样的:

def is_valid(instructions):
    if not isinstance(instructions, list): return False
    for item in instructions:
        if not isinstance(item, tuple): return False
        if len(item) != 2: return False
        if not isinstance(item[0], str): return False
        if not isinstance(item[1], int): return False
    return True

但在这种情况下,我必须为我需要验证的每种类型的值编写一个类似的复杂验证函数。所以我想知道是否存在一个更通用的验证函数或库,我可以给它一个表达式(如[(str, int)]),它会验证它而无需手动完成工作。

【问题讨论】:

    标签: python typechecking


    【解决方案1】:

    我想你在找isinstance

    isinstance(instruction, (str, int))
    

    如果指令是strint 的实例,则返回True

    要检查所有内容,您可以使用all() 函数:

    all(isinstance(e[0], (str, int)) for e in instructions)
    

    这将检查您的元组的所有第一个元素是否都是strint 的实例。如果其中任何一个无效,则返回 False

    【讨论】:

    • 我不认为这正是我想要的。例如,如果 instructions 作为浮点数传回,则代码将抛出“对象不可迭代”异常。我想要的是一种简单的检查方法:首先结果是一个列表;那么其中的项目是元组;那么元组有两个元素;那么第一个元素是字符串;那么第二个元素是整数。但如果可能的话,所有功能都在一个方便的函数调用中!
    • 我不介意该解决方案是否不能直接在 Python 中使用。如果有一个图书馆,那就太好了。
    • 嗯,很多。说真的,我为你提供了一个如何做的例子。你只需要检查更多次,不是吗?快点! :) 你应该能够做到这一点。
    • 提示:以if isinstance(instructions, list) and all(isinstance(e, tuple) for e in instructions)开头。将其包装在函数is_valid 中,该函数根据输入返回TrueFalse。哈哈:)
    • 回复:嗯...我不想听起来忘恩负义,我很高兴你花时间回答我的问题!我想我的问题一定不够清楚。我知道我可以“手动”检查类型。我希望(也许太多)有一种简单的方法来检查复杂的嵌套类型。
    【解决方案2】:

    你可以使用type函数:

    >>> type("abc") in [str, tuple]
    True
    

    虽然 aIKid 的回答会做同样的事情。

    【讨论】:

      【解决方案3】:

      很抱歉回答我自己的问题。从目前的答案来看,可能没有库函数可以做到这一点,所以我写了一个:

      def is_iterable(object):
          '''
          Returns True if the object is iterable, False if it is not.
          '''
          try:
              i = iter(object)
          except TypeError:
              return False
          else:
              return True
      
      
      def validate_type(object, type_or_prototype):
          '''
          Returns True if the object is of the type passed in.
      
          The type can be a straightforward type, such as int, list, or
          a class type. If so, we check that the object is an instance of
          the type.
      
          Alternatively the 'type' can be a prototype instance of a more
          complex type. For example:
          [int]                   a list of ints
          [(str, int)]            a list of (str, int) tuples
          {str: [(float, float)]} a dictionary of strings to lists of (float, float) tuples
      
          In these cases we recursively check the sub-items to see if they match
          the prototype.
          '''
          # If the type_or_prototype is a type, we can check directly against it...
          type_of_type = type(type_or_prototype)
          if type_of_type == type:
              return isinstance(object, type_or_prototype)
      
          # We have a prototype.
      
          # We check that the object is of the right type...
          if not isinstance(object, type_of_type):
              return False
      
          # We check each sub-item in object to see if it is of the right sub-type...
          if(isinstance(object, dict)):
              # The object is a dictionary, so we check that its items match
              # the prototype...
              prototype = type_or_prototype.popitem()
              for sub_item in object.items():
                  if not validate_type(sub_item, prototype):
                      return False
      
          elif(isinstance(object, tuple)):
              # For tuples, we check that each element of the tuple is
              # of the same type as each element the prototype...
              if len(object) != len(type_or_prototype):
                  return False
              for i in range(len(object)):
                  if not validate_type(object[i], type_or_prototype[i]):
                      return False
      
          elif is_iterable(object):
              # The object is a non-dictionary collection such as a list or set.
              # For these, we check that all items in the object match the
              prototype = iter(type_or_prototype).__next__()
              for sub_item in object:
                  if not validate_type(sub_item, prototype):
                      return False
      
          else:
              # We don't know how to check this object...
              raise Exception("Can not validate this object")
      
          return True
      

      你可以像 isinstance 这样使用简单类型,例如:

      validate_type(3.4, float)
      Out[1]: True
      

      或者使用更复杂的嵌入式类型:

      list1 = [("hello", 2), ("world", 3)]
      validate_type(list1, [(str, int)])
      Out[2]: True
      

      【讨论】:

      • 如果有人有更好的版本(可能可以处理更多类型)或有类似功能的库,请告诉我!
      • 这是一个很好的解决方案.. 我不明白你为什么还要在这里问:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 2013-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      相关资源
      最近更新 更多