【问题标题】:Dynamically assigning variable with locals() isn't working in recursive function使用 locals() 动态分配变量在递归函数中不起作用
【发布时间】:2014-10-19 17:56:44
【问题描述】:

我有一个递归脚本,它正在为汽车抓取 JSON 文件。在每个递归级别,它都会添加一个新变量,并将其(与其他值一起)传递给递归调用,每次都会获得越来越详细的信息。我尝试使用locals() 动态分配一个变量,但即使在调用之后它仍然是None(我记得看到有时locals() 是只读的)。

我也尝试使用eval(),但它给了我同样的问题(我知道 eval 并不理想)。理想情况下,我希望避免使用字典,因为这需要我先用值加载它,这似乎有一些不必要的步骤,但我现在对任何事情都持开放态度。

例子:

scraper(manufacturer='Honda') 会抓取模型的 JSON 文件,设置 model='Accord' 然后递归调用

scraper(manufacturer='Honda, model='Accord') 抓取一个年份文件,设置year=2014 并递归调用

scraper(manufacturer='Honda', model='Accord', year='2014') 这是基本情况

def scraper(self, manufacturers, model=None, year=None):

    if year:
        scrapeurl = '%s&manufacturer=%s&model=%s&year=%s' % (url, manufacturer, model, year)
        return someFinalFunction()

    elif model:
        scrapeurl = '%s&manufacturer=%s&model=%s' % (url, manufacturer, model)

    elif manufacturer:
        scrapeurl = '%s&manufacturer=%s' % (url, manufacturer)

    j = getJSONFromUrl(scrapeurl)
    key, values = j.popitems()

    for value in values:
        locals()[key] = value
        return self.scraper(manufacturer, model, year, color)

对于如何处理此问题的任何意见,我将不胜感激,我知道 Python 似乎总是有一些聪明的做事方式,而且我一直在学习更多关于它的知识,所以提前谢谢你!我也在这个例子中使用 Python3,如果这有什么改变的话

【问题讨论】:

  • 根据docs for locals - "注意 本词典的内容不应修改;更改可能不会影响由口译员。”
  • locals() 无论如何只是一本字典。只需制作自己的字典和所有值,而不是 locals
  • for value in values: ... return 想要达到什么目的?
  • Eric,JSON 会有多个值,所以在脚本执行 model='Accord' 之后,它会转到 model='Civic' 等
  • return 不是“继续”的意思,而是“完成”的意思……

标签: python python-3.x recursion exec locals


【解决方案1】:

locals()['key'] = value 应该是locals()[key] = value


更好的是,使用**kwargs

def scraper(self, manufacturer, model=None, year=None):
    kwargs = dict(manufacturer=manufacturer, model=model, year=year)

    if year:
        scrapeurl = '%s&manufacturer=%s&model=%s&year=%s' % (url, manufacturer, model, year)
        return someFinalFunction()

    elif model:
        scrapeurl = '%s&manufacturer=%s&model=%s' % (url, manufacturer, model)

    elif manufacturer:
        scrapeurl = '%s&manufacturer=%s' % (url, manufacturer)

    j = getJSONFromUrl(scrapeurl)
    key, values = j.popitems()

    for value in values:
        kwargs[key] = value
        return self.scraper(**kwargs)

【讨论】:

  • “钥匙”是个错字,我的错。另外,为什么这被否决了,请这样做的人解释一下您为什么这样做,以及为什么他的方法可能不理想?
【解决方案2】:

目前尚不完全清楚您要做什么,但也许这会有所帮助:

def scraper(self, **kwargs):

    if kwargs.get('year') is not None:
        scrapeurl = '{0}&manufacturer={manufacturer}&model={model}&year={year}'
        return someFinalFunction() # not sure why this takes no arguments

    elif kwargs.get('model') is not None:
        scrapeurl = '{0}&manufacturer={manufacturer}&model={model}'

    elif kwargs.get('manufacturer') is not None:
        scrapeurl = '{0}&manufacturer={manufacturer}'

    else:
        raise KeyError

    j = getJSONFromUrl(scrapeurl.format(url, **kwargs))
    key, values = j.popitems()

    for value in values:
        kwargs[key] = value
        return self.scraper(**kwargs)

这使用 Python 的内置功能将任意关键字参数视为字典,以及更现代的 str.format 字符串格式,以动态处理您正在寻找的参数。唯一的区别是你现在需要调用它:

instance.scraper(manufacturer='...')

而不仅仅是

instance.scraper('...')

字符串格式、混合位置参数和关键字参数的示例:

>>> '{0}&manufacturer={manufacturer}'.format('foo', **{'manufacturer': 'bar'})
'foo&manufacturer=bar'

【讨论】:

  • finalFunction 不接受任何参数,因为我清理了提供的代码以使其更短且与问题所在的位置相关,不过感谢您抽出宝贵时间。
  • 另外,不知道现代 str.format 的东西,很酷,谢谢
  • @Parker 一般而言,在削减代码以确保其易于理解时请小心 - 我也对范围内没有 url 感到困惑!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-14
  • 1970-01-01
  • 2020-07-26
  • 2018-04-19
  • 2021-10-28
相关资源
最近更新 更多