在Python字典中如果key
是 byte string
然后json.dumps
会抛出错误,所以我尝试递归地转换所有 keys
如string
在将它们传递给 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: user
和v: <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.user
是 SimpleLazyObject
,它包含一个回调,该回调是一个闭包,它包含对同一 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/