HTF*_*HTF 5 python oop properties data-conversion
任务是将字段从一个数据集映射到另一个数据集,某些字段需要一些额外的解析/计算。
(我在下面提供的示例中只使用了几个字段,但原始数据集中有更多字段)。
最初我虽然使用 dict 进行字段映射,只是将函数分配给需要额外数据操作的键:
import base64
import hashlib
import json
from datetime import datetime
def str2base64(event):
md5 = hashlib.md5(event['id'].encode())
return base64.b64encode(md5.digest())
def ts2iso(event):
dt = datetime.fromtimestamp(event['timestamp'])
return dt.isoformat()
MAPPINGS = {
'id': id2hash,
'region': 'site',
'target': 'host',
'since': ts2iso
}
def parser(event):
new = dict()
for k, v in MAPPINGS.items():
if callable(v):
value = v(event)
else:
value = event.get(v)
new[k] = value
return new
def main():
for event in events: # dicts
event = parser(event)
print(json.dumps(event, indent=2))
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
我不喜欢我必须在顶部添加所有解析函数以便 MAPPING dict 可以看到它的事实,我不确定这是否是最好的方法?此外,我没有看到一个简单的方法,以默认值传递给dict.get在parser函数。
import base64
import hashlib
import json
from datetime import datetime
class Event(object):
def __init__(self, event):
self.event = event
@property
def id(self):
md5 = hashlib.md5(self.event['id'].encode())
return base64.b64encode(md5.digest())
@property
def region(self):
return self.event['site']
@property
def target(self):
return self.event['host']
@property
def since(self):
dt = datetime.fromtimestamp(self.event['timestamp'])
return dt.isoformat()
def data(self):
return {
attr: getattr(self, attr)
for attr in dir(self)
if not attr.startswith('__') and attr not in ['event', 'data']
}
def main():
for event in events: # dicts
event = Event(event).data()
print(json.dumps(event, indent=2))
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
我确定有更好的方法来获取所有属性(仅限属性方法)以避免这种丑陋的data方法?我还想避免在相关方法中添加前缀,以便我可以使用str.startswith或类似的方法过滤它们。
这项任务的最佳方法是什么?我也在查看来自 functools 的@functools.singledispatch但我认为在这种情况下它不会有帮助。
我认为您的第一种方法很有意义,如果这对您很重要,那么它会比 OO 方法表现得更好。如果您需要处理大量事件,将 a 转换dict为 anobject肯定会占用大量 CPU 资源。我发现它也非常明确和清晰。
在面向对象的方法中,您可以免费dict从 转换为。拥有 没有任何好处,因为您稍后要做的就是将其转换为 JSON(除非您编写 JSON 编码器,否则您无法使用自定义类来执行此操作)。object object
这就是为什么我的选择是第一个选项,我会稍微修改一下,如下所示:
class SimpleConverter:
def __init__(self, key, default=None):
self.key = key
self.default = default
def __call__(self, event):
return event.get(self.key, self.default)
class TimestampToISO:
def __init__(self, key):
self.key = key
def __call__(self, event):
dt = datetime.fromtimestamp(event[self.key])
return dt.isoformat()
class StringToBase64:
def __init__(self, key):
self.key = key
def __call__(self, event):
md5 = hashlib.md5(event[self.key].encode())
return base64.b64encode(md5.digest()).decode() ## Without .decode() for Python2
def transform_event(event, mapping):
return {key: convert(event) for key, convert in mapping.items()}
def main(events, mapping):
for event in events: # dicts
event = transform_event(event, mapping)
print(json.dumps(event, indent=2))
if __name__ == '__main__':
mapping = {
'id': StringToBase64("id"),
'region': SimpleConverter("site"),
'target': SimpleConverter("region"),
'with_default': SimpleConverter("missing_key", "Not missing!"),
'since': TimestampToISO("timestamp"),
}
events = [
{
'id': 'test',
'site': 'X',
'host': 'Y',
'timestamp': 1582408754.5111449,
}
]
main(events, mapping)
Run Code Online (Sandbox Code Playgroud)
输出如下:
{
"id": "CY9rzUYh03PK3k6DJie09g==",
"region": "X",
"target": null,
"with_default": "Not missing!",
"since": "2020-02-22T22:59:14.511145"
}
Run Code Online (Sandbox Code Playgroud)
请注意,通过此解决方案,您可以为不同的事件键重用所有转换器类,而这对于纯函数来说是不可能的。