在 python 字典中,如果key是byte string,json.dumps则会引发错误,因此我尝试在将它们传递给之前递归地转换所有的keysas 。string``json.dumps
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:
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
所以我有
request_dir = dir(request)
然后使用将任何字节键转换为字符串keys_string(否则 json 转储将引发错误)
keys_string
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
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`对象的引用。然后,如果不存在该回调`request`,则通过创建新的属性来更新对象。因此,观察可能会创建一个新属性。`request._cached_user``request.user``request._cached_user
我认为用代码摘录来解释它会更容易。
来自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): ...