如何在python中安全地计算字典键

时间:2018-01-04 13:30:20

标签: python django

我正在编写一个django应用程序,我将从用户那里获得可变大小的字典。我希望限制字典的大小,即它可以容纳多少(key, value)对。我希望它不超过200.我怀疑如果我这样做:

if len(user_dict)>200:
    raise ValidationError("dict has too many (key, value) pairs")

python必须统计整个字典。如果dict是巨大的,由于恶意用户,这将消耗不必要的处理能力。或者dict是否跟踪它拥有多少个对象,这意味着len(user_dict)是一个简单的查找操作?解决这个问题的最佳方法是什么?

我在想这样的事情:

i=0
for key in user_dict.keys():
    i += 1
    if i>200:
        raise ValidationError("dict has too many (key, value) pairs")

1 个答案:

答案 0 :(得分:5)

  

或者dict是否跟踪它拥有多少个对象,这意味着len(user_dict)是一个简单的查找操作?

字典 - 给出像CPython这样严格的解释器实现 - 确实跟踪存储在字典中的键值对的数量。所以如果 user_dict确实是一个字典,那么len(user_dict) O(1)中工作并且非常快。它在恒定时间内工作的事实也意味着,我们是否计算len(..)具有10万个项目的dict对象,或者根本不计算任何项目,都没有(理论上的)差异。

不需要迭代来计算对象的数量。例如CPython source code for the dict class has

static Py_ssize_t
dict_length(PyDictObject *mp)
{
    return mp->ma_used;
}

因此它返回字典对象的ma_used字段(因此是包含字典中项目数的字段)。

this file

中也对此进行了描述
Dictionaries: dict and defaultdict
                               Complexity
Operation     | Example      | Class         | Notes
--------------+--------------+---------------+-------------------------------
Index         | d[k]         | O(1)      |
Store         | d[k] = v     | O(1)      |
Length        | len(d)       | O(1)      |
Delete        | del d[k]     | O(1)      |
get/setdefault| d.method     | O(1)      |
Pop           | d.pop(k)     | O(1)      |
Pop item      | d.popitem()  | O(1)      |
Clear         | d.clear()    | O(1)      | similar to s = {} or = dict()
View          | d.keys()     | O(1)      | same for d.values()

Construction  | dict(...)    | O(len(...))   | depends # (key,value) 2-tuples

Iteration     | for k in d:  | O(N)          | all forms: keys, values, items