2013-11-30 2 views
2

Я пишу фреймворк, который вызывает код, написанный другими людьми (структура играет монополию и звонит в AI игрока). ИИ сообщают структуре, что делать в возвращаемых значениях вызовов функций.Python: проверка типов сложных возвращаемых значений

Я хотел бы проверить типы возвращаемых значений, чтобы убедиться, что они не взорвут мой код рамки.

Например:

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

В этом примере я ожидал игрок возвращает список кортежей, таких как:

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

Есть Симпл (МОГ) способ проверить, что ИИ возвращается ко мне? Я представляю что-то вроде этого:

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)]), и он будет проверять его, не выполняя работу вручную.

ответ

2

Извините, что ответите на мой вопрос.Он смотрит из ответов до сих пор, что не может быть функцией библиотека, которая делает это, так что я написал один:

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 
+0

Если у кого-то есть лучшая версия этого (что, возможно, справляется с большим количеством типов) или библиотеку, которая делает что-то подобное, пожалуйста, дайте мне знать! –

+0

Это отличное решение .. я не понимаю, почему вам даже нужно спрашивать здесь :) – aIKid

1

Я думаю, что вы ищете isinstance:

isinstance(instruction, (str, int)) 

который будет возвращать True, если инструкция является экземпляром str или int.

Чтобы проверить все это, вы можете использовать функцию all():

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

Это будет проверять, если все первый элемент из ваших кортежей является экземпляр str или int. Возвращает False, если какой-либо из них недействителен.

+0

Я не думаю, что это делает именно то, что я хочу. Например, если «инструкции» были переданы назад как float, тогда код будет генерировать исключение «объект не итерируется». Я бы хотел, чтобы это простой способ проверить: во-первых, результатом является список; то, что элементы в нем являются кортежами; то, что кортежи имеют два элемента; то первые элементы являются строками; то, что вторыми элементами являются ints. Но все в одном удобном вызове функции, если это возможно! –

+0

Я не возражаю, если решение недоступно непосредственно в Python. Если для этого есть библиотека, то это было бы здорово. –

+0

Мех, это много. Серьезно, я представил вам пример о том, как это сделать. Вам просто нужно проверять его больше раз, не так ли? Давай! :) Вы должны быть в состоянии сделать это. – aIKid

1

Ну вы можете использовать type функцию:

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

Хотя ответ aIKid будет делать то же самое.

Смежные вопросы