python 在python中序列化一个suds对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2412486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Serializing a suds object in python
提问by jeffff
Ok I'm working on getting better with python, so I'm not sure this is the right way to go about what I'm doing to begin with, but here's my current problem...
好的,我正在努力使用 python 变得更好,所以我不确定这是开始我正在做的事情的正确方法,但这是我目前的问题......
I need to get some information via a SOAP method, and only use part of the information now but store the entire result for future uses (we need to use the service as little as possible). Looking up the best way to access the service I figured suds was the way to go, and it was simple and worked like a charm to get the data. But now I want to save the result somehow, preferably serialized / in a database so I can pull it out later and use it the same.
我需要通过 SOAP 方法获取一些信息,现在只使用部分信息,但存储整个结果以备将来使用(我们需要尽可能少地使用该服务)。查找访问服务的最佳方式我认为 suds 是要走的路,它很简单,并且像魅力一样工作来获取数据。但是现在我想以某种方式保存结果,最好在数据库中序列化/保存,以便稍后将其取出并使用相同的方法。
What's the best way to do this, it looks like pickle/json isn't an option? Thanks!
什么是最好的方法来做到这一点,看起来泡菜/json 不是一个选择?谢谢!
UpdateReading the top answer at How can I pickle suds results?gives me a better idea of why this isn't an option, I guess I'm stuck recreating a basic object w/ the information I need?
更新阅读How can I pickle suds results?的最佳答案?让我更好地了解为什么这不是一个选项,我想我被困在重新创建一个带有我需要的信息的基本对象?
采纳答案by Alex Martelli
Yep, I confirm the explanation I gave in the answer you refer to -- dynamically generated classes are not easily picklable (nor otherwise easily serializable), you need to extract all the state information, pickle thatstate, and reconstruct the tricky sudsobject on retrieval if you really insist on using it;-).
是的,我确认我在您参考的答案中给出的解释——动态生成的类不容易被腌制(也不容易被序列化),您需要提取所有状态信息,腌制该状态,并在检索时重建棘手的 sudsobject如果你真的坚持使用它;-)。
回答by plaes
I have been using following approach to convert Suds object into JSON:
我一直在使用以下方法将 Suds 对象转换为 JSON:
from suds.sudsobject import asdict
def recursive_asdict(d):
"""Convert Suds object into serializable format."""
out = {}
for k, v in asdict(d).iteritems():
if hasattr(v, '__keylist__'):
out[k] = recursive_asdict(v)
elif isinstance(v, list):
out[k] = []
for item in v:
if hasattr(item, '__keylist__'):
out[k].append(recursive_asdict(item))
else:
out[k].append(item)
else:
out[k] = v
return out
def suds_to_json(data):
return json.dumps(recursive_asdict(data))
回答by Rogerio Hilbert
I made an implementation of a dummy class for Object intance of suds, and then being able to serialize. The FakeSudsInstance behaves like an original Suds Object instance, see below:
我为 suds 的对象实例做了一个虚拟类的实现,然后能够序列化。FakeSudsInstance 的行为类似于原始的 Suds Object 实例,见下文:
from suds.sudsobject import Object as SudsObject
class FakeSudsNode(SudsObject):
def __init__(self, data):
SudsObject.__init__(self)
self.__keylist__ = data.keys()
for key, value in data.items():
if isinstance(value, dict):
setattr(self, key, FakeSudsNode(value))
elif isinstance(value, list):
l = []
for v in value:
if isinstance(v, list) or isinstance(v, dict):
l.append(FakeSudsNode(v))
else:
l.append(v)
setattr(self, key, l)
else:
setattr(self, key, value)
class FakeSudsInstance(SudsObject):
def __init__(self, data):
SudsObject.__init__(self)
self.__keylist__ = data.keys()
for key, value in data.items():
if isinstance(value, dict):
setattr(self, key, FakeSudsNode(value))
else:
setattr(self, key, value)
@classmethod
def build_instance(cls, instance):
suds_data = {}
def node_to_dict(node, node_data):
if hasattr(node, '__keylist__'):
keys = node.__keylist__
for key in keys:
if isinstance(node[key], list):
lkey = key.replace('[]', '')
node_data[lkey] = node_to_dict(node[key], [])
elif hasattr(node[key], '__keylist__'):
node_data[key] = node_to_dict(node[key], {})
else:
if isinstance(node_data, list):
node_data.append(node[key])
else:
node_data[key] = node[key]
return node_data
else:
if isinstance(node, list):
for lnode in node:
node_data.append(node_to_dict(lnode, {}))
return node_data
else:
return node
node_to_dict(instance, suds_data)
return cls(suds_data)
Now, after a suds call, for example below:
现在,在 suds 调用之后,例如下面:
# Now, after a suds call, for example below
>>> import cPickle as pickle
>>> suds_intance = client.service.SomeCall(account, param)
>>> fake_suds = FakeSudsInstance.build_instance(suds_intance)
>>> dumped = pickle.dumps(fake_suds)
>>> loaded = pickle.loads(dumped)
I hope it helps.
我希望它有帮助。
回答by radtek
Here is what I came up with before researching and finding this answer. This actually works well for me on complex suds responses and also on other objects such as __builtins__
since the solution is suds agnostic:
这是我在研究和找到这个答案之前想到的。这实际上对我来说对复杂的泡沫响应以及其他对象都很有效,例如__builtins__
因为解决方案与泡沫无关:
import datetime
def object_to_dict(obj):
if isinstance(obj, (str, unicode, bool, int, long, float, datetime.datetime, datetime.date, datetime.time)):
return obj
data_dict = {}
try:
all_keys = obj.__dict__.keys() # vars(obj).keys()
except AttributeError:
return obj
fields = [k for k in all_keys if not k.startswith('_')]
for field in fields:
val = getattr(obj, field)
if isinstance(val, (list, tuple)):
data_dict[field] = []
for item in val:
data_dict[field].append(object_to_dict(item))
else:
data_dict[field] = object_to_dict(val)
return data_dict
This solution works and is actually faster. It also works on objects that don't have the __keylist__
attribute.
此解决方案有效并且实际上更快。它也适用于没有该__keylist__
属性的对象。
I ran a benchmark 100 times on a complex suds output object, this solutions run time was 0.04 to .052 seconds (0.045724287 average). While recursive_asdict
solution above ran in .082 to 0.102 seconds so nearly double (0.0829765582 average).
我在一个复杂的 suds 输出对象上运行了 100 次基准测试,这个解决方案的运行时间是 0.04 到 0.052 秒(平均 0.045724287)。虽然recursive_asdict
上述解决方案在 0.082 到 0.102 秒内运行,但几乎翻了一番(平均 0.0829765582)。
I then went back to the drawing board and re-did the function to get more performance out of it, and it does not need the datetime
import. I leveraged in using the __keylist__
attribute, so this will not work on other objects such as __builtins__
but works nicely for suds object output:
然后我回到绘图板并重新执行该功能以从中获得更多性能,并且不需要datetime
导入。我利用了该__keylist__
属性,因此这不适用于其他对象,例如__builtins__
但对 suds 对象输出效果很好:
def fastest_object_to_dict(obj):
if not hasattr(obj, '__keylist__'):
return obj
data = {}
fields = obj.__keylist__
for field in fields:
val = getattr(obj, field)
if isinstance(val, list): # tuple not used
data[field] = []
for item in val:
data[field].append(fastest_object_to_dict(item))
else:
data[field] = fastest_object_to_dict(val)
return data
The run time was 0.18 - 0.033 seconds (0.0260889721 average), so nearly 4x as faster than the recursive_asdict
solution.
运行时间为 0.18 - 0.033 秒(平均为 0.0260889721),因此比recursive_asdict
解决方案快近 4 倍。
回答by ffeast
The solutions suggesed above lose valuable information about class names - it can be of value in some libraries like DFP client https://github.com/googleads/googleads-python-libwhere entity types might be encoded in dynamically generated class names (i.e. TemplateCreative/ImageCreative)
上面建议的解决方案丢失了有关类名的宝贵信息 - 它在 DFP 客户端https://github.com/googleads/googleads-python-lib等某些库中可能很有价值,其中实体类型可能被编码为动态生成的类名(即TemplateCreative/ ImageCreative)
Here's the solution I used that preserves class names and restores dict-serialized objects without data loss (except suds.sax.text.Textwhich would be converted into regular unicode objects and maybe some other types I haven't run into)
这是我使用的解决方案,它保留类名并恢复 dict 序列化的对象而不会丢失数据(除了suds.sax.text.Text它将被转换为常规的 unicode 对象,也许还有一些我没有遇到过的其他类型)
from suds.sudsobject import asdict, Factory as SudsFactory
def suds2dict(d):
"""
Suds object serializer
Borrowed from https://stackoverflow.com/questions/2412486/serializing-a-suds-object-in-python/15678861#15678861
"""
out = {'__class__': d.__class__.__name__}
for k, v in asdict(d).iteritems():
if hasattr(v, '__keylist__'):
out[k] = suds2dict(v)
elif isinstance(v, list):
out[k] = []
for item in v:
if hasattr(item, '__keylist__'):
out[k].append(suds2dict(item))
else:
out[k].append(item)
else:
out[k] = v
return out
def dict2suds(d):
"""
Suds object deserializer
"""
out = {}
for k, v in d.iteritems():
if isinstance(v, dict):
out[k] = dict2suds(v)
elif isinstance(v, list):
out[k] = []
for item in v:
if isinstance(item, dict):
out[k].append(dict2suds(item))
else:
out[k].append(item)
else:
out[k] = v
return SudsFactory.object(out.pop('__class__'), out)
回答by maerteijn
I updated the recursive_asdict
example aboveto be compatible with python3 (items
instead of iteritems
).
我更新了上面的recursive_asdict
示例以与 python3 (而不是)兼容。items
iteritems
from suds.sudsobject import asdict
from suds.sax.text import Text
def recursive_asdict(d):
"""
Recursively convert Suds object into dict.
We convert the keys to lowercase, and convert sax.Text
instances to Unicode.
Taken from:
https://stackoverflow.com/a/15678861/202168
Let's create a suds object from scratch with some lists and stuff
>>> from suds.sudsobject import Object as SudsObject
>>> sudsobject = SudsObject()
>>> sudsobject.Title = "My title"
>>> sudsobject.JustAList = [1, 2, 3]
>>> sudsobject.Child = SudsObject()
>>> sudsobject.Child.Title = "Child title"
>>> sudsobject.Child.AnotherList = ["4", "5", "6"]
>>> childobject = SudsObject()
>>> childobject.Title = "Another child title"
>>> sudsobject.Child.SudObjectList = [childobject]
Now see if this works:
>>> result = recursive_asdict(sudsobject)
>>> result['title']
'My title'
>>> result['child']['anotherlist']
['4', '5', '6']
"""
out = {}
for k, v in asdict(d).items():
k = k.lower()
if hasattr(v, '__keylist__'):
out[k] = recursive_asdict(v)
elif isinstance(v, list):
out[k] = []
for item in v:
if hasattr(item, '__keylist__'):
out[k].append(recursive_asdict(item))
else:
out[k].append(
item.title() if isinstance(item, Text) else item)
else:
out[k] = v.title() if isinstance(v, Text) else v
return out