python:错误:字典尝试在SimpleLazyObject上遍历django请求对象时在迭代过程中更改了大小@ [英] python: Error: dictionary changed size during iteration @ when trying to iterate over django request object at SimpleLazyObject
问题描述
在python中的字典中,如果key
是byte 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: user
和v: <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.user
是SimpleLazyObject
,其中包含一个回调,该回调是一个闭包,其中包含对同一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屋!