#python #object #json-serialization
Вопрос:
Я пытаюсь передать конфигурацию с клиента на сервер.
- Конфигурация содержит
password
ключ, который я НЕ должен передавать - Конфигурация содержит пару простых объектов, которые являются просто парами ключ/значение (значение является базовым примитивом).
Этот код работает:
class Empty:
pass
class Config:
def __init__(self):
# don't want to transmit this over the internet
self.secret = 'P@ssw0rd'
def create(self, foo):
self.foo = foo # property passed in
self.bar = f'Hello {foo}' # calculated property
# A couple of custom objects, but they are simple
# (only containing key/value pairs where value is basic primitive)
self.v = Empty()
self.v.a = 1
self.w = Empty()
self.w.b = 2
def export_json(self):
J = {}
for k, v in vars(self).items():
if k == 'secret':
continue
J[k] = vars(v) if isinstance(v, Empty) else v
return J
def construct_from_json(self, J_str):
J = json.loads(J_str)
for k, v in J.items():
if isinstance(v, dict):
_ = Empty()
for k_, v_ in v.items():
setattr(_, k_, v_)
v = _
setattr(self, k, v)
Test:
```python
c = Config()
c.create('123')
J = c.export_json()
print('Serialized:')
print(json.dumps(J, indent=4))
d = Config()
d.construct_from_json(J)
print('Reconstructed: w.b = ', d.w.b)
Выход:
Serialized:
{
"foo": "123",
"bar": "Hello 123",
"v": {
"b": 2
},
"w": {
"b": 2
}
}
Reconstructed: w.b = 2
Однако существует ли предпочтительный/питонический способ сделать это?
Комментарии:
1. вы уже разобрались
pickle
?
Ответ №1:
Как кто-то упоминал в комментариях, вы можете просто захотеть использовать pickle
библиотеку здесь, чтобы избежать необходимости сериализации/десериализации самостоятельно и избежать необходимости вносить серьезные изменения в код сериализации в будущем, если вы добавляете вложенные структуры / и т.д. Или хотите игнорировать другие атрибуты. Вот версия вашего кода , которая работает с pickle
атрибутом, но не сериализует secret
его.
class Empty:
pass
class Config:
def __init__(self):
# don't want to transmit this over the internet
self.secret = 'P@ssw0rd'
def create(self, foo):
self.foo = foo # property passed in
self.bar = f'Hello {foo}' # calculated property
# A couple of custom objects, but they are simple
# (only containing key/value pairs where value is basic primitive)
self.v = Empty()
self.v.a = 1
self.w = Empty()
self.w.b = 2
# This gets the state for pickling. Note how we are explicitly removing
# the `secret` attribute from the internal dictionary. You don't need to
# do anything else
def __getstate__(self):
state = self.__dict__.copy()
del state['secret']
return state
Проверяю это:
import pickle
c = Config()
c.create('123')
J = pickle.dumps(c)
print("Serialized: ", J)
d = pickle.loads(J)
print("Reconstructed w.b:", d.w.b)
print("Reconstructed secret:", d.secret)
И это результат, который он производит (по желанию):
Serialized: b'x80x04x95mx00...(truncated)'
Reconstructed w.b: 2
Traceback (most recent call last):
File "/Users/mustafa/scratch/test.py", line 36, in <module>
print("Reconstructed secret:", d.secret)
AttributeError: 'Config' object has no attribute 'secret'
Комментарии:
1. Если вам необходимо использовать JSON, вы можете просто попробовать сделать
json.dumps(state)
(гдеstate
то же самое, что и в приведенном выше коде), но это было бы более раздражающим, так как вам нужно снова явно обрабатывать вложенные значения.