请求之间的神秘咒语持续存在?

时间:2013-01-26 07:52:04

标签: python django dictionary

我有一系列函数都通过了dict,但是在每种情况下dict应该以{{1​​}}开头。但是我发现,在对不同视图的顺序请求中,dict会记住数据,导致后来出现问题。

以下是相关代码:

{}

所以问题出现了,我有一个调用def picasa_sync_friend(user_profile, friend_id, force_update=False): logger.warn('picasa_sync_friend') data, error = picasa_query_by_profile('albums', user_profile, replace=(friend_id)) .... def picasa_sync_albums(user_profile, friend_id="default"): logger.warn('picasa_sync_albums') data, error = picasa_query_by_profile('albums', user_profile, replace=(friend_id)) ... def picasa_sync_pictures(user_profile, album_id, force_update=False, full_update=False): friend_id = picasa_get_album(user_profile, album_id).friend.foreign_reference subject = 'photos' if full_update else 'thumbs' logger.warn('picasa_sync_pictures') data, error = picasa_query_by_profile(subject, user_profile, replace=(friend_id, album_id)) ... def picasa_query_by_profile(subject, user_profile, args={}, replace=(), format='xml'): logger.warn('picasa_query_by_profile: %s' % args) access_token = picasa_get_token(user_profile).access_token response = picasa_query(subject, access_token, args=args, replace=replace) ... def picasa_query(subject, access_token='', args={}, replace=()): logger.warn('picasa_query: %s' % args) url, request_args, method = picasa_query_params(subject, access_token=access_token, args=args, replace=replace) ... def picasa_query_params(subject, access_token='', args={}, replace=()): method = 'GET' base_url = 'https://accounts.google.com/o/oauth2/' logger.warn('picasa_query_params (before): %s' % args) if subject == 'albums': args['access_token'] = access_token subject = '' base_url = 'https://picasaweb.google.com/data/feed/api/user/%s' % replace args['kind'] = 'album' args['v'] = '2.0' args['fields'] = 'entry(title,gphoto:id,gphoto:numphotos,published)' elif subject == 'photos': args['access_token'] = access_token base_url = 'https://picasaweb.google.com/data/feed/api/user/%s/albumid/%s' % replace args['v'] = '2.0' args['kind'] = 'photo' args['fields'] = 'entry(gphoto:id,content(@src),gphoto:width,gphoto:height)' subject = '' elif subject == 'thumbs': args['access_token'] = access_token base_url = 'https://picasaweb.google.com/data/feed/api/user/%s/albumid/%s' % replace args['v'] = '2.0' args['kind'] = 'photo' args['fields'] = 'entry(gphoto:id,content(@src),gphoto:width,gphoto:height)' args['max-results'] = ALBUM_THUMBNAIL_LIMIT subject = '' logger.warn('picasa_query_params (after ): %s' % args) url = '%s%s' % (base_url, subject) return url, args, method 然后调用picasa_sync_friend并将所有专辑数据返回给客户端的视图。

然后,对于每个相册,客户端会发出单独请求,为picasa_sync_albums调用picasa_sync_pictures

初始好友/专辑请求的记录器输出如下所示:

album_id

请注意WARNING 2013-01-26 07:27:23,611 picasa_sync_friend WARNING 2013-01-26 07:27:23,617 picasa_query_by_profile: {} WARNING 2013-01-26 07:27:23,633 picasa_query: {} WARNING 2013-01-26 07:27:23,633 picasa_query_params (albums:before): {} WARNING 2013-01-26 07:27:23,633 picasa_query_params (:after ): {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:24,388 picasa_sync_albums WARNING 2013-01-26 07:27:24,388 picasa_query_by_profile: {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:24,389 picasa_query: {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:24,389 picasa_query_params (before): {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:24,389 picasa_query_params (after ): {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} - > picasa_sync_albums,首字母picasa_query_by_profile dict已经填充,尽管args没有向args数组键发送任何数据。

以上记录器输出结束了朋友/专辑请求,接下来要做的是直接进入picasa_sync_albums的单个专辑的图片列表:

picasa_sync_pictures

请注意,在WARNING 2013-01-26 07:27:25,981 picasa_sync_pictures WARNING 2013-01-26 07:27:25,998 picasa_query_by_profile: {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:26,011 picasa_query: {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:26,020 picasa_query_params (before): {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'v': '2.0'} WARNING 2013-01-26 07:27:26,022 picasa_query_params (after ): {'access_token': u'xxx', 'fields': 'entry(gphoto:id,content(@src),gphoto:width,gphoto:height)', 'kind': 'photo', 'max-results': 4, 'v': '2.0'} 中,args已经包含picasa_query_by_profile,尽管这可能是一个新请求。

如果我刷新页面,再次呼叫好友/专辑,我会得到以下日志输出:

'kind': 'album'

这是它开始真正影响应用程序的地方,因为它将WARNING 2013-01-26 07:45:32,589 picasa_sync_friend WARNING 2013-01-26 07:45:32,593 picasa_query_by_profile: {'access_token': u'xxx', 'fields': 'entry(gphoto:id,content(@src),gphoto:width,gphoto:height)', 'kind': 'photo', 'max-results': 4, 'v': '2.0'} WARNING 2013-01-26 07:45:32,597 picasa_query: {'access_token': u'xxx', 'fields': 'entry(gphoto:id,content(@src),gphoto:width,gphoto:height)', 'kind': 'photo', 'max-results': 4, 'v': '2.0'} WARNING 2013-01-26 07:45:32,598 picasa_query_params (before): {'access_token': u'xxx', 'fields': 'entry(gphoto:id,content(@src),gphoto:width,gphoto:height)', 'kind': 'photo', 'max-results': 4, 'v': '2.0'} WARNING 2013-01-26 07:45:32,600 picasa_query_params (after ): {'access_token': u'xxx', 'fields': 'entry(title,gphoto:id,gphoto:numphotos,published)', 'kind': 'album', 'max-results': 4, 'v': '2.0'} 等内容应用于专辑列表,这是不可取的。

现在我可以通过非常明确地删除不应用于某些主题的dict项目来解决所有这些问题,但是这使得这非常难以维护,并且该计划的目标是可以扩展到许多不同的主题所以它需要灵活,不容易脱轨。

我很确定我在这里错过了python / django的一些基本部分,但我完全不知道解释上述行为!谢谢你的任何建议。

2 个答案:

答案 0 :(得分:3)

您不应该使用可变值作为Python函数的默认参数。请考虑以下事项:

def f(arg={}):
  print arg
  if 'count' in arg:
    arg['count'] += 1
  else:
    arg['count'] = 1

f()
f()
f()

这令人惊讶地打印出来

{}
{'count': 1}
{'count': 2}

{}中的f(arg={})被评估一次,并且每当调用f()时都会传递相同的字典。因此,args的任何更改都会在调用过程中持续存在。

修复上述代码的一种方法是:

def f(arg=None):
  if not arg:
    arg = {}
  print arg
  if 'count' in arg:
    arg['count'] += 1
  else:
    arg['count'] = 1

您的代码中的以下函数会受到此问题的影响:

def picasa_query_by_profile(subject, user_profile, args={}, replace=(), format='xml'):
def picasa_query(subject, access_token='', args={}, replace=()):
def picasa_query_params(subject, access_token='', args={}, replace=()):

答案 1 :(得分:1)

不要将mutables用作默认值。更改所有代码案例:

def picasa_query(subject, access_token='', args={}, replace=()):
    ...

对此:

def picasa_query(subject, access_token='', args=None, replace=()):
    if args is None:
        args = {}
    ...

在创建函数对象时,仅对一次评估函数的默认值,并且从那时起将同一对象用作默认值。这是最常见的python gotchas之一。