python:错误:字典尝试在SimpleLazyObject上遍历django请求对象时在迭代过程中更改了大小@ [英] python: Error: dictionary changed size during iteration @ when trying to iterate over django request object at SimpleLazyObject

查看:170
本文介绍了python:错误:字典尝试在SimpleLazyObject上遍历django请求对象时在迭代过程中更改了大小@的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在python中的字典中,如果keybyte string,则json.dumps会引发错误,因此我试图在将所有keys递归转换为string之前,将它们传递给json.dumps.

In python in a dictionary if key is byte string then json.dumps will throw error, So I am trying to convert recursively all the keys as string before passing them to json.dumps.

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

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

The following is my function which will check for any byte string keys and convert them to 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中的一些代码

I am debugging some code in django

我想在代码的特定位置检查request对象

I want to check the request object at certain point of my code

我有

request_dir = dir(request)

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

then convert any byte keys to string using keys_string (Else json dumps will throw error)

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

我发现这种情况发生在以下时间:

I found this happening when:

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

我尝试了request.session对象,但它不会引发此类错误.但是有些对象可以.

I tried for request.session object it does not throw such error. But some object do.

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)

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

And now request object is shown without any errors

推荐答案

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

request.user is SimpleLazyObject which holds a callback that is a closure which holds a reference to same request object. And then that callback updates request object by creating new attr request._cached_user if it does not exist. So observing request.user would possibly create a new request._cached_user attribute.

认为通过代码摘录更容易解释它.

A think it is easier to explain it with code excerpts.

来自Django源代码:

From django source code:

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

因此,如果您想更稳定地浏览字典键,则需要遍历dict的键副本:

So if you want to have more stable walk through dictionary keys then you need to iterate over dict's keys copy:

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

这篇关于python:错误:字典尝试在SimpleLazyObject上遍历django请求对象时在迭代过程中更改了大小@的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆