1

我有一系列函数都传递一个 dict,但是在每个实例中,dict 应该以{}. 但是,我发现在对不同视图的顺序请求中,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中,已经填充了首字母argsdict,尽管事实上picasa_sync_albums没有将任何数据发送到 args 数组键。

上面的记录器输出结束了朋友/相册请求,接下来要输入的是单个相册的图片列表,该列表直接转到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'}

请注意,尽管这应该是一个新请求,但在picasa_query_by_profileargs 中已经包含了。'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'}

这是它开始真正影响应用程序的地方,因为它正在应用诸如max-results专辑列表之类的东西,这是不可取的。

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

我很确定我在这里遗漏了 python/django 的一些基本部分,但我完全无法解释上述行为!感谢您的任何建议。

4

2 回答 2

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}

发生的情况是{}in被评估一次,并且每次调用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=()):
于 2013-01-26T08:07:12.890 回答
1

不要使用可变变量作为默认值。像这样更改所有代码案例:

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

对此:

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

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

于 2013-01-26T08:07:01.337 回答