Seite 2 von 2
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Freitag 20. Juli 2012, 12:10
von lunar
@mutetella: Welcher Einwand? Ob wirklich alle builtins übersprungen werden müssen?
Nein, genau genommen ist das sogar falsch, denn "json" versteht gar nicht alle builtins ("set" beispielsweise nicht). Eigentlich darf man nur die Typen überspringen, die "json" laut
Dokumentation von Haus aus versteht. Dazu war ich allerdings zu faul
Ich habe das
Beispiel aktualisiert. Ganz korrekt ist es immer noch nicht, da beispielsweise "set" nicht richtig serialisiert wird, aber das überlasse ich Dir zur Übung

Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Freitag 20. Juli 2012, 19:04
von BlackJack
Wenn ich mal Korinthen kacken darf: Natürlich kann es auch „built in”-Module geben:
Code: Alles auswählen
In [227]: sys.builtin_module_names
Out[227]:
('__builtin__',
'__main__',
'_ast',
'_bisect',
'_codecs',
'_collections',
'_functools',
'_hashlib',
'_locale',
'_random',
'_socket',
'_sre',
'_ssl',
'_struct',
'_symtable',
'_warnings',
'_weakref',
'array',
'binascii',
'cPickle',
'cStringIO',
'errno',
'exceptions',
'fcntl',
'gc',
'grp',
'imp',
'itertools',
'marshal',
'math',
'operator',
'posix',
'pwd',
'select',
'signal',
'spwd',
'strop',
'sys',
'syslog',
'thread',
'time',
'unicodedata',
'xxsubtype',
'zipimport',
'zlib')
In [228]: sys
Out[228]: <module 'sys' (built-in)>
Die Module sind fest in den Interpreter einkompiliert. Auswahl und Anzahl kann von der Python-Version und den Optionen beim Übersetzen des Interpreters abhängen.
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Freitag 20. Juli 2012, 19:08
von lunar
@BlackJack: Ich würde das als Implementierungsdetail bezeichnen. Für den Programmierer verhalten sich diese Module – einige Ausnahmen beiseite gelassen – wie normale Module auch, vor allem muss man sie importieren, bevor man sie nutzen kann.
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Freitag 20. Juli 2012, 19:35
von mutetella
Ok, hab' mich mal herangewagt...:
Code: Alles auswählen
try:
#Python < 3.0
BUILTINS = __builtin__
except NameError:
#Python >= 3.0
BUILTINS = builtins
# Supported Json types as by
# http://docs.python.org/library/json.html#json.JSONEncoder
JSON_STANDARD_TYPES = [
dict,
list, tuple,
str, unicode,
int, long, float,
bool,
type(None)
]
JSON_NONSTANDARD_TYPES = [
set
]
TO_JSON = {
'set': list
}
def deserialize_object(o):
o = dict(o)
if '__type' in o:
typename = o.pop('__type')
modulename, classname = typename.rsplit('.', 1)
#TODO: load module dynamically depending on python-version
#module = importlib.import_module(modulename)
module = __import__(modulename, fromlist=[classname])
cls = getattr(module, classname)
obj = cls.__new__(cls)
if hasattr(obj, '__setstate__'):
obj.__setstate__(o)
else:
for attr, value in o.iteritems():
_type, value = value
obj.__dict__[attr] = getattr(BUILTINS, _type)(value)
return obj
else:
return o
def convert2json(obj):
objname = type(obj).__name__
return TO_JSON[objname](obj)
def default(obj):
objtype = type(obj)
if objtype in JSON_STANDARD_TYPES:
# skip standard JSON types
return objtype.__name__, obj
elif objtype in JSON_NONSTANDARD_TYPES:
return objtype.__name__, convert2json(obj)
else:
typename = objtype.__module__ + '.' + objtype.__name__
state = {'__type': typename}
if hasattr(obj, '__getstate__'):
attrs = obj.__getstate__()
else:
attrs = dict(obj.__dict__)
for attr, value in attrs.iteritems():
state[attr] = default(value)
return state
Was haltet ihr davon?
mutetella
P. S.: Den 'importlib'-Quellcode hab' ich jetzt der Einfachheit halber noch nicht übernommen...
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Samstag 21. Juli 2012, 07:37
von mutetella
Mein erster Versuch ist nix gudd!! Das mit 'convert2json()' und 'TO_JSON' war zwar gut gemeint, gaukelt aber eigentlich nur vor, dass sich hier "einfach so" weitere typen zufügen lassen. Geht aber nicht "einfach so". Und das ist doof!
Ich will das noch ändern, muss jetzt aber erst mal früüühhhhstücken!
mutetella
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 11:43
von mutetella
Puhhh.... hier mein zweiter Entwurf:
Code: Alles auswählen
JSON_STANDARD_TYPES = [
dict,
list, tuple,
str, unicode,
int, long, float,
bool,
type(None)
]
def deserialize_object(o):
if o is not None and '__type' in o:
typename = o.pop('__type')
value = o.get('__value', o.iteritems())
modulename, classname = typename.rsplit('.', 1)
#TODO: load module dynamically depending on python-version
#module = importlib.import_module(modulename)
module = __import__(modulename, fromlist=[classname])
cls = getattr(module, classname, None)
if cls in JSON_STANDARD_TYPES or cls == set:
return cls(value)
elif classname == 'datetime':
return cls.strptime(value, '%Y%m%d%H%M')
elif classname == 'date':
return cls(*value)
elif cls is None:
return
else:
cls = cls.__new__(cls)
if hasattr(cls, '__setstate__'):
cls.__setstate__(o)
else:
for attr, value in value:
cls.__dict__[attr] = deserialize_object(value)
return cls
else:
return o
def default(obj):
objtype = type(obj)
objname = objtype.__name__
objmodule = objtype.__module__
typename = objmodule + '.' + objname
state = {'__type': typename}
if objtype in JSON_STANDARD_TYPES:
state['__value'] = obj
elif objtype == set:
state['__value'] = list(obj)
elif objname == 'date':
state['__value'] = (obj.year, obj.month, obj.day)
elif objname == 'datetime':
state['__value'] = obj.strftime('%Y%m%d%H%M')
else:
if hasattr(obj, '__getstate__'):
attrs = obj.__getstate__()
else:
attrs = dict(obj.__dict__)
for attr, value in attrs.iteritems():
state[attr] = default(value)
return state
Nicht ganz so glücklich bin ich darüber, dass mit dieser Lösung manche Objekte 2 mal an 'deserialize_object()' geschickt werden:
Einmal, wenn sie tatsächlich deserialisiert werden und evtl. nochmal, wenn sie innerhalb der 'for'-Schleife einer Klasse als Attribut hinzugefügt werden. Nachdem ich unter Python < 2.7 keinen Einfluss darauf habe, in welcher Reihenfolge das an 'json.load()' dict abgearbeitet wird, wüsste ich nicht, wie sich das lösen lässt.
Ich könnte natürlich einfach alle JSON_STANDARD_TYPES in 'default()' unverändert durchwinken, dann allerdings würden non-JSON_STANDARD_TYPES die sich z. B. in einer Liste befinden nicht deserialisiert, da sie ja von 'json.load()' nie an 'deserialize_object()' übergeben werden.
Was meint ihr?
mutetella
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 11:56
von lunar
@mutetella: Ich verstehe Dein Problem nicht… Du musst doch ohnehin rekursiv (de-)serialisieren, da ein Objekt ja ein weiteres komplexes Objekt als Attribut haben kann.
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 16:12
von mutetella
@lunar:
Wenn ich eine Klasse mit einem str-Attribut habe, schaut damit ein json-Objekt so aus:
Code: Alles auswählen
'{"__type": "any.Class", "name": {"__value": "simply a string", "__type": "__builtin__.str"}}'
Könnte ich die Reihenfolge beim Deserialisieren beeinflussen, würde ich 'any.Class' erzeugen, dabei das str-Attribut deserialisieren und als Attribut hinzufügen.
In dieser Form ist es so, dass 'json.dump()' erstmal
Code: Alles auswählen
{"__value": "simply a string", "__type": "__builtin__.str"}
zu 'deserialize_object()' schickt und 'simply a string' zurück erhält. Danach wird
an 'deserialize_object()' übergeben. Dort wird dann innerhalb der for-Schleife 'simply a string' nochmals an 'deserialze_object()' geschickt. 'simply a string' erzeugt demnach 2 Funktionsaufrufe. Ginge das nicht billiger?
mutetella
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 16:20
von lunar
@mutetella: Wieso serialisierst Du Zeichenketten nicht einfach direkt?! Mein ursprünglicher Code hat das getan…
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 17:02
von mutetella
Ok, ich kann Dir das jetzt leider nicht mehr erklären... In einer ursprünglichen Version war es allerdings so, dass 'json.load()' nur dann "in die Tiefe" ging, wenn jedes Objekt aufgebröselt per dict vorlag. Es sah so aus, als würden andernfalls JSON_STANDARD_TYPES nicht an 'deserialize_object()' gesendet und demnach z. B. Listen- oder Tuple-Elemente nicht weiter bearbeitet werden.
Na ja, wie auch immer, Du hast Recht. So
Code: Alles auswählen
def default(obj):
...
if objtype in JSON_STANDARD_TYPES:
return obj
...
klappts und nix ist doppelt gemobbelt... Man könnte natürlich noch tuple aus den 'JSON_STANDARD_TYPES' herausnehmen, weil 'json' daraus Listen macht...
Ansonsten: Kann ich es so lassen oder sind grobe Schnitzer drin?
mutetella
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 18:04
von lunar
@mutetella: Ich sehe auf den ersten Blick keine kapitalen Fehler… natürlich liegt es an Dir, dafür jetzt Tests zu schreiben, um wirklich sicher zu sein, dass die Funktionen funktionieren

Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 18:25
von mutetella
@lunar:
Das mit der Testerei (also nicht nur ein paar gut gemeinte Funktionsaufrufe) ist 'ne Sache, mit der ich mich auch schon lange auseinandersetzen sollte.... ob mein Kalender jemals zum Einsatz kommen wird...?
Jedenfalls danke ich Dir sehr für Deine Hilfe!!!
mutetella
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 24. Juli 2012, 18:54
von EyDu
Wenn du bis jetzt keine Tests für deinen Kalender geschrieben hast, dann kannst du es dir eigentlich (für die vorhandenen Methoden) sparen oder mal hier und dort hinzufügen, wenn du an einer Methode etwas ändern willst. Das Testen muss eigentlich von Anfang systematisch geschenen, so dass möglichst der gesamte Code abgedeckt wird. Fängst du erst am Ende damit an, fehlt dir schon ein großer Teil des Nutzens. Mit Tests will man nicht nur sicher gehen, dass am Ende alles funktioniert, sondern dass Änderungen zwischendurch auch nichts zerstören. Vielleicht testest du das einfach mal bei Gelegenheit an einem neuen Modul.
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Samstag 25. August 2012, 16:21
von mutetella
Mit Urlaub, Faulheit, Hitze und so weiter sind jetzt zwar 4 Wochen vergangen... trotzdem möchte ich die paar Änderungen an der '
json_ser.py' hier noch einstellen.
mutetella
Re: Klassen mit 'is' oder '==' vergleichen?
Verfasst: Dienstag 30. Oktober 2012, 21:13
von mutetella
Bin gerade über Twitter @getpy auf das folgende Modul aufmerksam geworden und dachte mir, das gehört eigentlich auch noch hier in diesen Thread... man weiß ja nie...
jsonpickle
mutetella