这个Python技巧有什么不明显的问题吗?

2024-09-26 22:52:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我经常需要一个字典将键映射到连续的ID,因此我执行以下操作:

ids = defaultdict()
ids.default_factory = ids.__len__

由于这里使用__len__方法,有什么奇怪的地方可能出错吗?你知道吗


Tags: 方法ididsdefaultlen字典factory地方
3条回答

很遗憾,每次都需要指定默认的工厂。也许可以试试这样的

class ConsecutiveIds(defaultdict):
    def __init__(self):
        super(ConsecutiveIds, self)
        self.default_factory = lambda: len(self)

d = ConsecutiveIds()

似乎确实有一个异常删除,这将重复旧的值

In [4]: d = ConsecutiveIds()

In [5]: d[0]
Out[5]: 0

In [6]: d[10]
Out[6]: 1

In [7]: d[20]
Out[7]: 2

In [8]: d
Out[8]: 
ConsecutiveIds(<function __main__.ConsecutiveIds.__init__.<locals>.<lambda>()>,
               {0: 0, 10: 1, 20: 2})

In [9]: del d[10]

In [10]: d[30]
Out[10]: 2

In [11]: d
Out[11]: 
ConsecutiveIds(<function __main__.ConsecutiveIds.__init__.<locals>.<lambda>()>,
               {0: 0, 20: 2, 30: 2})

这种异常似乎并不存在于ikamen's answer,但更简洁地说,你可以说:

class ConsecutiveIds(defaultdict):
    def __init__(self):
        super(ConsecutiveIds, self)
        self.default_factory = self.next_int
        self.index = 0

    def next_int(self):
        result = self.index
        self.index += 1
        return result

这可以进一步细化为

class ConsecutiveIds(defaultdict):
    def __init__(self):
        super(ConsecutiveIds, self)
        counter = itertools.count()
        self.default_factory = lambda: next(counter)

我看不出有什么问题,但你应该把它说得更清楚一点。可能使用lambda:

ids = defaultdict()
ids.default_factory = lambda:len(ids)

Is there anything strange that could go wrong due to the use of the __len__ method here?

取决于预期用途和限制。什么样的行为可以将出错的东西与“python就是这样工作的”区别开来?你知道吗

如果您想要的是一个对象为它“注册”的其他对象提供相应的ID,那么下面是一个不那么令人惊讶的实现:

class ConseqIds:
    def __init__(self):
        self.ctr = 0
        self.elements = {}

    def assign_next(self, obj):
        self.elements[obj] = self.ctr
        self.ctr += 1

    def __getitem__(self, item):
        if not item in self.elements:
            self.assign_next(item)
        return self.elements[item]

ids = ConseqIds()
print(ids['first element'])
print(ids['second element'])
ids.assign_next('third element')

你将避免许多边缘情况,并确定它做什么。你知道吗

相关问题 更多 >

    热门问题