首页 > 解决方案 > 使用对象动态构建列表

问题描述

我正在构建一个 SP 500 组件列表以将其保存在泡菜中。

我从代码中的链接获取项目,然后获取我想要的信息并为每个项目构建一个对象。

这就是问题所在——>然后我想将每个对象保存到一个列表中,以便将来迭代。

该列表仅存储循环的最后一个对象,而不是存储每个显示的对象。

这样做应该相当容易,但我似乎无法找到为什么会发生这种情况的答案

def save_sp500_tickers():
    resp = requests.get(
        'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
    soup = bs.BeautifulSoup(resp.text, "lxml")
    table = soup.find('table', {'class': 'wikitable sortable'})
    components = []
    data = {}
    for row in table.findAll('tr')[1:]:

        ticker = row.findAll('td')[0].text.replace('\n', '') # AAPL
        name = row.findAll('td')[1].text.replace('\n', '') # Apple Inc
        sector = row.findAll('td')[3].text.replace('\n', '') # Information Technology
        mapping = str.maketrans(".", "-")

        ticker = ticker.translate(mapping)
        name = name.translate(mapping)
        sector = sector.translate(mapping)

        data['ticker']=ticker
        data['name']=name
        data['sector']=sector

        print(data) # {'ticker': 'AAPL', 'name': 'Apple Inc-', 'sector': 'Information Technology'}
        components.append(data) # I add each component to the list


    with open("SP500components.pickle", "wb") as f:
        pickle.dump(components, f)

    print(components) # this gives me the list with only the last item repeated 

    return components

save_sp500_tickers()

目标是有一个如下所示的列表:

[{'ticker': 'AAPL', 'name': 'Apple Inc-', 'sector': 'Information Technology'},
{'ticker': 'ETN', 'name': 'Eaton Corporation', 'sector': 'Industrials'},
{'ticker': 'EBAY', 'name': 'eBay Inc-', 'sector': 'Consumer Discretionary'},
{'ticker': 'ECL', 'name': 'Ecolab Inc-', 'sector': 'Materials'},
{'ticker': 'EIX', 'name': "Edison Int'l", 'sector': 'Utilities'},
...,
...]

相反,我得到一个仅多次显示最后一个对象的列表,如下所示:

[{'ticker': 'ZTS', 'name': 'Zoetis', 'sector': 'Health Care'},
{'ticker': 'ZTS', 'name': 'Zoetis', 'sector': 'Health Care'},
{'ticker': 'ZTS', 'name': 'Zoetis', 'sector': 'Health Care'},
{'ticker': 'ZTS', 'name': 'Zoetis', 'sector': 'Health Care'},
...,
...]

标签: python-3.x

解决方案


这完全取决于您的data对象。您在 for 循环之外对其进行初始化。由于它是一个字典,它在 python 中是可变的,当你将它附加到列表时,你只是data在循环的每次迭代中附加一个对该字典的引用,而不是一个新的字典。所以最后引用只是指向字典的最新版本,因此为什么它多次出现是同一个字典 - 它是同一个字典。

此页面可能有助于了解正在发生的事情。

尝试在 for 循环中移动 dict 的初始化:

def save_sp500_tickers():
    resp = requests.get(
        'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
    soup = bs.BeautifulSoup(resp.text, "lxml")
    table = soup.find('table', {'class': 'wikitable sortable'})
    components = []
    for row in table.findAll('tr')[1:]:
        ticker = row.findAll('td')[0].text.replace('\n', '') # AAPL
        name = row.findAll('td')[1].text.replace('\n', '') # Apple Inc
        sector = row.findAll('td')[3].text.replace('\n', '') # Information Technology
        mapping = str.maketrans(".", "-")

        ticker = ticker.translate(mapping)
        name = name.translate(mapping)
        sector = sector.translate(mapping)

        data = dict(ticker=ticker, name=name, sector=sector)

        print(data) # {'ticker': 'AAPL', 'name': 'Apple Inc-', 'sector': 'Information Technology'}
        components.append(data) # I add each component to the list


    with open("SP500components.pickle", "wb") as f:
        pickle.dump(components, f)

    print(components) # this gives me the list with only the last item repeated 

    return components

推荐阅读