python:错误:当尝试在 SimpleLazyObject 处迭代 django 请求对象时,字典在迭代期间更改了大小

标签 python django dictionary

在Python字典中如果keybyte string然后json.dumps会抛出错误,所以我尝试递归地转换所有 keysstring在将它们传递给 json.dumps 之前。

Note: json.dumps converts the value to str using default function but not keys

以下是我的函数,它将检查任何 byte string keys并将它们转换为string :

def keys_string(d):
    rval = {}
    if not isinstance(d, dict):
        if isinstance(d,(tuple,list,set)):
            v = [keys_string(x) for x in d]
            return v
        else:
            return d
    for k,v in d.items():
        if isinstance(k,bytes):
            k = k.decode()
        if isinstance(v,dict):
            v = keys_string(v)
        elif isinstance(v,(tuple,list,set)):
            v = [keys_string(x) for x in v]
        rval[k] = v
    return rval

我正在调试 django 中的一些代码

我想查看request对象在我的代码的某个点

所以我有

request_dir = dir(request)

然后使用 keys_string 将任何字节键转换为字符串(否则 json 转储将抛出错误)

request_dir_keys_stringed = keys_string(request_dir)

最后

json.dumps(request_dir_keys_stringed, indent=4, sort_keys=True, default=str)

当我尝试做request_dir_keys_stringed = keys_string(request_dir)时它说

in keys_string
    for k,v in d.items():
RuntimeError: dictionary changed size during iteration

我发现这种情况发生在:

k: userv: <SimpleLazyObject: <User: test@gmail.com>>

我尝试了request.session对象它不会抛出这样的错误。但有些对象确实如此。

request_session_dir = dir(request.session)
request_session_dir_keys_stringed = keys_string(request_session_dir)
json.dumps(request_session_dir_keys_stringed, indent=4, sort_keys=True, default=str)

遇到这种情况该怎么办

重现问题的更多信息:

$ python --version
Python 3.7.3

$ django-admin --version
2.2.6

def articles(request):
    request_dir = dir(request)
    request_dir_keys_stringed = keys_string(request_dir)
    print(json.dumps(request_dir_keys_stringed, indent=4, sort_keys=True, default=str)
    return render(request, 'articles/main_page/articles.html')

实现解决方案后,keys_string 变为:

def keys_string(d):
    rval = {}
    if not isinstance(d, dict):
        if isinstance(d,(tuple,list,set)):
            v = [keys_string(x) for x in d]
            return v
        else:
            return d
    keys = list(d.keys())
    for k in keys:
        v = d[k]
        if isinstance(k,bytes):
            k = k.decode()
        if isinstance(v,dict):
            v = keys_string(v)
        elif isinstance(v,(tuple,list,set)):
            v = [keys_string(x) for x in v]
        rval[k] = v
    return rval


        request_dir = dir(request)
        request_dir_keys_stringed = keys_string(request_dir)
        print(json.dumps(request_dir_keys_stringed, indent=4, sort_keys=True, default=str)

现在请求对象显示没有任何错误

最佳答案

request.userSimpleLazyObject,它包含一个回调,该回调是一个闭包,它包含对同一 request 对象的引用。然后,该回调通过创建新的 attr request._cached_user 来更新 request 对象(如果该对象不存在)。因此,观察 request.user 可能会创建一个新的 request._cached_user 属性。

A认为用代码摘录来解释更容易。

来自 django 源代码:

class SimpleLazyObject(LazyObject):
    def __init__(self, func):
        ...

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: get_user(request))

def get_user(request):
    if not hasattr(request, '_cached_user'):
        request._cached_user = auth.get_user(request)
    return request._cached_user

因此,如果您想要更稳定地浏览字典键,那么您需要迭代字典的键副本:

keys = list(d.keys())
for k in keys:
    v = d[k]
    if isinstance(k, bytes):
        ...

关于python:错误:当尝试在 SimpleLazyObject 处迭代 django 请求对象时,字典在迭代期间更改了大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59662479/

相关文章:

python - 在扩展 CB 上按用户显示内容过滤器

python - 字典: Value of type "object" is not indexable字典的Mypy错误

c++ - 使用 C++ 的具有一种类型键但具有不同类型值的复杂映射。 (不是 multimap )

ios - Swift:如何将字典数组添加到数组?

python - 在递归中仅应用一次条件

python - Seaborn 未显示完整情节

python - 将列表中的元素向后移动一位而不改变原始列表

python - scitkit-learn.ensemble.GradientBoostingRegressor 的均方根对数平方误差问题

python - Django 应用程序中的外部身份验证

python - django.db.migrations.exceptions.InconsistentMigrationHistory : Migration . ..在其依赖项之前应用