问题
I have a set of python webservices that work with data objects they get via a JSON POSTs. In my old services I have a lot of boilerplate to (de)serialize and check JSONs for each object. With Python 3.5s new typing and PEP 484 I have the feeling that could be substantially reduced. Is it worth it? Does anyone have a good solution for it?
Additional info
My old boilerplate looks like this for every object:
class Data:
class Nested1:
def __init__(self, nested1_flat1):
self.nested1_flat1 = nested1_flat1
@classmethod
def from_jsond(cls, jsond):
# jsond : dict of strings, lists and dicts as usually receivied from reading JSON
kwargs = {}
for key, val in jsond.items():
# lots of code to deal with special objects , e.g.
if key=='date' : kwargs[key] = cleverly_build_datetime_from_js_format(val)
return cls.__init__(**kwargs)
def __init__(self, flat1, nested1):
self.flat1 = flat1
self.nested1 = nested1
@classmethod
def from_jsond(cls, jsond):
kwargs = {}
for key, val in jsond.items():
# lots of code to deal with nested and special objects, e.g.
if key=='nested1' : kwargs[key] = Nested1.from_jsond(val)
return cls.__init__(**kwargs)
I managed to reduce it down to the following
@from_jsond
class Data:
@from_jsond
class Nested1:
@auto_assign
@beartype
def __init__(self, nested1_flat1: str):
pass
@auto_assign
@beartype
def __init__(self, flat1: str, nested1: Nested1)
pass
Here I used snippets for @auto_assign and @beartype and my own from_jsond.
import inspect
from typing import Any
_JSON_READABLE = [str, list, dict, Any]
def _from_jsond(cls, json_dict):
'''
Entity specific conversion of string dictionary to entity.
The json_dict is a dict of string, lists and other dicts as typically encoded in a JSON.
'''
kwargs = {}
init_parameters = inspect.signature(cls.__init__).parameters
for key, val in json_dict.items():
if key in init_parameters.keys():
if init_parameters[key].annotation in _JSON_READABLE:
kwargs[key] = val
else:
if hasattr(init_parameters[key].annotation, 'from_jsond'):
kwargs[key] = init_parameters[key].annotation.from_jsond(val)
else:
raise TypeError('No method to unserialize type "' + init_parameters[key].annotation.__name__ + '"')
else:
raise AttributeError('Class "' + cls.__name__ + '" does not accept attribute "' + key + '"')
return cls(**kwargs)
def from_jsond(cls):
''' Wrapper to add _from_jsonlike to cls as classmethod '''
cls.from_jsonlike = classmethod(_from_jsond)
return cls
With inheritance one could most likely reduce it even further, but I don't know if it is all worth the hassle and stable enough. Opinions and experiences are welcome :)
回答1:
No, PEP 484 and type hints in general will not help you reduce the boilerplate.
The simplest explanation is that python run-time is not aware of PEP 484. Python interpreter executes type hints only to make sure the syntax is correct, there are no undefined names, etc.
Therefore, there is no way to meaningfully change the run-time behavior of your program by using type hints.
Type hints are only processed in a separate phase, before you execute the interpreter, to verify that your types are correct. No information flows from that analysis to the python interpreter.
Of course you can read type annotations for your source code in run-time yourself, and then do what you want with them. But that's clearly not what you're asking, since in order to do anything useful with that approach, you'd have to write a lot of rather complex code.
来源:https://stackoverflow.com/questions/39097411/how-to-reduce-boilerplate-when-initializating-classes-from-jsons-in-python-3-5