python - 数据转换/映射的最佳方法

标签 python oop properties data-conversion

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

去年关闭。




Improve this question




任务是将字段从一个数据集映射到另一个数据集,某些字段需要一些额外的解析/计算。

(我在下面提供的示例中只使用了几个字段,但原始数据集中有更多字段)。

方法一:

最初我虽然使用 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()

我不喜欢我必须在顶部添加所有解析函数以便 MAPPING dict 可以看到它的事实,我不确定这是否是最好的方法?此外,我没有看到将默认值传递给 dict.get 的简单方法。在 parser功能。

方法 2 (OOP):
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()

我确信有更好的方法来获取所有属性(仅限属性方法)以避免这种丑陋的 data方法?我还想避免在相关方法中添加前缀,以便我可以使用 str.startswith 过滤它们。或类似的东西。

这项任务的最佳方法是什么?我也在看@functools.singledispatch来自 functools 但我认为在这种情况下它不会有帮助。

最佳答案

我认为您的第一种方法很有意义,如果这对您很重要,它将比 OO 方法表现得更好。如果您需要处理大量事件,请转换 dictobject肯定会占用大量 CPU。我发现它也非常明确和清晰。

在 OO 方法中,您将从 dict 转换至 object不求返回。拥有 object 没有任何好处,因为您稍后要做的就是将其转换为 JSON(除非您编写 JSON 编码器,否则您无法使用自定义类执行此操作)。

这就是为什么我的选择是第一个选项,我会像这样稍微修改一下:

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)

输出这个:
{
  "id": "CY9rzUYh03PK3k6DJie09g==",
  "region": "X",
  "target": null,
  "with_default": "Not missing!",
  "since": "2020-02-22T22:59:14.511145"
}

请注意,使用此解决方案,您可以为不同的事件键重用所有转换器类,这是纯函数无法实现的。

关于python - 数据转换/映射的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60323938/

相关文章:

java - 如何读取Spring Boot application.properties?

java - 属性文件中的字符串值

python - django 表单预取清理后的数据

python - Flask 和 SQLAlchemy 在 PostgreSQL 的事务连接中导致大量 IDLE

具有动态命名输出的 Python 循环

创建从字典键到它的值的所有组合的 Pythonic 方法

PHP 静态方法/单例模式

java - 将外部匿名类引用传递给内部匿名类中的方法

.Net 类属性 - 获取访问器 - 多少处理算太多?

oop - 我应该编写利用 Intellisense 的代码吗?