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
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'
Habs mal aus Interesse an DuckTyping geschrieben, in einem Projekt verwendet hab ich es noch nicht.
Gruss Rayo