Ich schreibe ein Framework, das Code aufruft, der von anderen Personen geschrieben wurde (das Framework spielt Monopoly und ruft Spieler-AIs auf). Die AIs teilen dem Framework mit, was in den Rückgabewerten von Funktionsaufrufen zu tun ist.

Ich möchte die Typen der Rückgabewerte überprüfen, um sicherzustellen, dass sie meinen Framework-Code nicht in die Luft jagen.

Beispielsweise:

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

In diesem Beispiel erwarte ich, dass der Spieler eine Liste von Tupeln zurückgibt, wie zum Beispiel:

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

Gibt es eine einfache (Wunsch-) Möglichkeit zu überprüfen, was die KI an mich zurückgibt? Ich stelle mir so etwas vor:

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

Ich möchte nicht nur überprüfen, ob die zurückgegebenen Daten eine Liste sind. Ich möchte überprüfen, ob es sich um eine Liste eines bestimmten Typs handelt. Im Beispiel handelt es sich um eine Liste von Tupeln, in denen jedes Tupel eine Zeichenfolge und eine Ganzzahl enthält.

Ich habe gesehen, dass viele der Python-Fragen zur Typprüfung die Antwort "Typprüfung ist böse" erhalten. Wenn ja, was soll ich in diesem Fall tun? Es scheint nichts zu geben, was den KI-Code davon abhält, absolut irgendetwas zurückzugeben, und ich muss in der Lage sein, ihn zu validieren oder auf irgendeine Weise damit umzugehen.


Bearbeiten: Ich könnte dies 'von Hand' überprüfen, indem ich eine Funktion schreibe. Für instructions oben könnte es ungefähr so sein:

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

In diesem Fall müsste ich jedoch für jeden Wertetyp, den ich validieren muss, eine ähnlich komplexe Validierungsfunktion schreiben. Ich frage mich also, ob es eine allgemeinere Validierungsfunktion oder -bibliothek gibt, in der ich ihr einen Ausdruck geben kann (wie [(str, int)]), und die dagegen validiert, ohne die Arbeit von Hand ausführen zu müssen.

2
Richard Shepherd 30 Nov. 2013 im 20:31

3 Antworten

Beste Antwort

Tut mir leid, meine eigene Frage zu beantworten. Aus den bisherigen Antworten geht hervor, dass es möglicherweise keine Bibliotheksfunktion gibt, die dies tut. Deshalb habe ich eine geschrieben:

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

Sie können dies wie isinstance mit einfachen Typen verwenden, z.

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

Oder mit komplexeren, eingebetteten Typen:

list1 = [("hello", 2), ("world", 3)]
validate_type(list1, [(str, int)])
Out[2]: True
2
Richard Shepherd 30 Nov. 2013 im 22:39

Ich denke du suchst nach isinstance:

isinstance(instruction, (str, int))

Was True zurückgibt, wenn der Befehl eine Instanz von str oder int ist.

Um alles zu überprüfen, können Sie die Funktion all() verwenden:

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

Dadurch wird überprüft, ob alle ersten Elemente Ihrer Tupel eine Instanz von str oder int sind. Gibt False zurück, wenn eines davon ungültig ist.

1
aIKid 1 Dez. 2013 im 07:07

Nun, Sie können die type Funktion verwenden:

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

Obwohl die Antwort von aIKid dasselbe tun wird.

1
Games Brainiac 30 Nov. 2013 im 16:37