DuckTyping

Code-Stücke können hier veröffentlicht werden.
Antworten
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Vielleicht habt ihr schon von DuckTyping gelesen. Für alle die es noch nicht getan haben:

Wenn es wie eine Ente läuft und es wie eine Quakt ist es eine Ente. Sprich wenn ein Object z.B. read,write und seek funktionen besitzt ist es ein Stream, es ist egal wovon die Klasse vererbt wurde.

Ich habe nun ein kleines Script erstellt dass DuckTyping "vereinfachen" soll :)

Hier mal das Script:

Code: Alles auswählen

import inspect
import types

class Function(object):
    """
    Arguments:
        name: Name der Funktion (string)
        numArgs: Anzahl der benötigten Parameter (integer)
        keywordArgs: Die KeywordArguments als Liste, ['arg1','arg2']
    """
    __slots__ = ['name','numArgs','keywordArgs']
    def __init__(self, name, numArgs, kwArgs=[]):
        self.name = name
        self.numArgs = numArgs
        self.keywordArgs = kwArgs

class Property(object):
    """
    Arguments:
        name: Name des Property (string)
        readable: Property hat fget Methode (boolean)
        writable: Property hat fset Methode (boolean)
        deletable: Property hat fdel Methode (boolean default=>False)
    """
    __slots__ = ['name','readable','writable','deletable']

    def __init__(self, name, readable, writable, deletable=False):
        self.name = name
        self.readable = readable
        self.writable = writable
        self.deletable = deletable

class Attribute(object):
    """
    Arguments:
        name: Name des Attributs
        type_: Typ des Attributs (muss vergleichbar mit type(attribut) sein)
    """
    __slots__ = ['name', 'type']

    def __init__(self, name, type_):
        self.name = name
        self.type = type_



def _checkFunction(obj, function):
    func = getattr(obj, function.name, None)
    if func:
        if type(func) in [types.BuiltinFunctionType,types.BuiltinMethodType]:
            return True
        
        try:
            func = func.im_func
        except AttributeError:
            pass

        try:
            args, varargs, varkw = inspect.getargs(func.func_code)
            defaults = func.func_defaults
        except AttributeError:
            return False
        
        if defaults == None:
            defaults = ()
        
        del args[0] # self loeschen
        
        if varargs and varkw:
            if len(args)-len(defaults) > function.numArgs:
                return False
        elif varargs:
            if len(args) > 0:
                for x in function.keywordArgs:
                    if not x in args:
                        return False
        elif varkw:
            if len(args)-len(defaults) > 0:
                for x in function.keywordArgs:
                    count = 0
                    for x in args:
                        if x in function.keywordArgs:
                            count += 1
                    if count != len(args)-len(defaults):
                        return False
                
        else:
            if not function.numArgs >= len(args)-len(defaults):
                return False
            if len(args) < function.numArgs:
                return False
        
        return True
    return False

def _checkProperty(obj, prop):
    cls = obj.__class__
    classprop = getattr(cls, prop.name, None)
    
    if classprop:
        if not isinstance(classprop, property):
            return False
        if prop.readable and not getattr(classprop, 'fget', None):
            return False
        if prop.writable and not getattr(classprop, 'fset', None):
            return False
        if prop.deletable and not getattr(classprop, 'fdel', None):
            return False
        return True
    return False

def _checkAttribute(obj, attr):
    attribute = getattr(obj, attr.name, None)
    if attribute:
        if type(attribute) != attr.type:
            return False
        return True
    return False

_attributeChoose = { Function: _checkFunction,
                    Property: _checkProperty,
                    Attribute: _checkAttribute}

def isDucky(obj, neededAttributes):
    for attr in neededAttributes:
        if not _attributeChoose[attr.__class__](obj, attr):
            return False
    return True

Davon brauchen werdet ihr isDucky, Function, Property, Attribute.

nun könnt ihr, wenn ihr eine Library oder Funktion für andere zur verfügung stellt einfach folgendes implementieren:

Code: Alles auswählen

import DuckTyping as dt

wantedObject = [
    dt.Function('check',2),
    dt.Attribute('count',int)
               ]

def meineFunktion(requiredObject):
    if dt.isDucky(requiredObject, wantedObject):
        print 'alles ok, ist ein kompatibles object'
    else:
        print 'leider stellt dieses objekt nicht alle attribute zur verfügung die wir brauchen'
Vielleicht brauchts ja jemand oder hat noch Vorschläge :)

Habs mal aus Interesse an DuckTyping geschrieben, in einem Projekt verwendet hab ich es noch nicht.

Gruss Rayo
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ich denke in Python ist das Duck-Typing eher schleichend/versteckt: wenn ein Objekt die entsprechenden Funktionen hat, dann ist es automatisch eine Ente (oder halt ein Kuckucksei *g*).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Ja, mit dem Script kann man einfach überprüfen ob ein Objekt Funktionen, Attribute und Properties besitzt. Vielleicht ists ja einfacher wenn man grössere Objekte hat.

Wie gesagt, verwendet hab ich es auch nicht in einem Projekt :D

Gruss
BlackJack

Ich denke auch das duck-typing in Python eher so angewendet werden sollte, dass man die Objekte so benutzt wie man es von ihnen erwartet und dann auf entsprechende Fehler reagiert. Ansonsten baut man per Hand eine statisch getypte Sprache nach. Wenn man das möchte, dann sollte man die Finger von Python lassen.

Interessanter ist PyProtocols, da kann man die Ente fragen, ob sie eine Ente ist, oder ob sie weiss, wie sie sich in eine Verwandeln kann. Oder ob das Entenprotokoll weiss wie man das "falsche" Objekt in eine Ente verwandelt. Oder als letzte Lösung ob es eine registrierte Funktion gibt, die das Entenprotokoll und das Objekt kennt und weiss, wie man beide zusammenbringen kann.

Da sehe ich einen Mehrwert im Gegensatz zum simplen prüfen, ob der Typ "stimmt".
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Mhh ja das PyProtocols sieht interessant aus. Kannte ich noch gar nicht. Da schaue ich mir dass doch mal an.

Gruss
Antworten