【问题标题】:Issue with 'else' sequence using Spotipy/Spotify API使用 Spotipy/Spotify API 的“else”序列问题
【发布时间】:2020-10-20 20:44:32
【问题描述】:

我和我的团队(python 新手)编写了以下代码来生成与特定城市和相关术语相关的 Spotify 歌曲。 如果用户输入的城市不在我们的 CITY_KEY_WORDS 列表中,那么它会告诉用户输入将被添加到请求文件中,然后将输入写入文件。 代码如下:


from random import shuffle
from typing import Any, Dict, List
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
sp = spotipy.Spotify(
    auth_manager=SpotifyClientCredentials(client_id="",
                                          client_secret="")
)
CITY_KEY_WORDS = {
    'london': ['big ben', 'fuse'],
    'paris': ['eiffel tower', 'notre dame', 'louvre'],
    'manhattan': ['new york', 'new york city', 'nyc', 'empire state', 'wall street', ],
    'rome': ['colosseum', 'roma', 'spanish steps', 'pantheon', 'sistine chapel', 'vatican'],
    'berlin': ['berghain', 'berlin wall'],
}

def main(city: str, num_songs: int) -> List[Dict[str, Any]]:
    if city in CITY_KEY_WORDS:
        """Searches Spotify for songs that are about `city`. Returns at most `num_songs` tracks."""
        results = []
        # Search for songs that have `city` in the title
        results += sp.search(city, limit=50)['tracks']['items']  # 50 is the maximum Spotify's API allows
        # Search for songs that have key words associated with `city`
        if city.lower() in CITY_KEY_WORDS.keys():
            for related_term in CITY_KEY_WORDS[city.lower()]:
                results += sp.search(related_term, limit=50)['tracks']['items']
        # Shuffle the results so that they are not ordered by key word and return at most `num_songs`
        shuffle(results)
        return results[: num_songs]
    else:
        print("Unfortunately, this city is not yet in our system. We will add it to our requests file.")
        with open('requests.txt', 'r') as text_file:
            request = text_file.read()
        request = request + city + '\n'
        with open('requests.txt', 'w+') as text_file:
            text_file.write(request)

def display_tracks(tracks: List[Dict[str, Any]]) -> None:
    """Prints the name, artist and URL of each track in `tracks`"""
    for num, track in enumerate(tracks):
        # Print the relevant details
        print(f"{num + 1}. {track['name']} - {track['artists'][0]['name']} {track['external_urls']['spotify']}")
if __name__ == '__main__':
    city = input("Virtual holiday city? ")
    number_of_songs = input("How many songs would you like? ")
    tracks = main(city, int(number_of_songs))
    display_tracks(tracks)

“if”语句的代码运行良好(如果有人进入我们列出的城市)。 但是当 else 语句运行时,在操作 ok 后出现 2 个错误(它打印并将用户的输入写入文件)。

出现的错误是:

Traceback (most recent call last):
  File "...", line 48, in <module>
    display_tracks(tracks)
  File "...", line 41, in display_tracks
    for num, track in enumerate(tracks):
TypeError: 'NoneType' object is not iterable

请原谅我缺乏知识,但有人可以帮助解决这个问题吗?

我们还想在最后创建一个歌曲的播放列表,但是遇到了困难。

【问题讨论】:

标签: python if-statement spotify traceback spotipy


【解决方案1】:

您的main 函数在else 子句中没有return 语句,这导致tracks 成为None。在tracks 上迭代None 是导致错误的原因。 您可以做一些事情来改进代码:

  • 关注点分离:main 函数做了两件不同的事情,检查输入和获取轨道。
  • 在开始时执行一次.lower(),这样您就不必重复了。
  • 遵循文档约定。
  • 在使用前检查响应
  • 一些代码清理

请参阅下面我上面建议的更改:

def fetch_tracks(city: str, num_songs: int) -> List[Dict[str, Any]]:
    """Searches Spotify for songs that are about `city`.

    :param city: TODO: TBD
    :param num_songs:  TODO: TBD
    :return: at most `num_songs` tracks.
    """
    results = []
    for search_term in [city, *CITY_KEY_WORDS[city]]:
        response = sp.search(search_term, limit=50)
        if response and 'tracks' in response and 'items' in response['tracks']:
            results += response['tracks']['items']
    # Shuffle the results so that they are not ordered by key word and return
    # at most `num_songs`
    shuffle(results)
    return results[: num_songs]


def display_tracks(tracks: List[Dict[str, Any]]) -> None:
    """Prints the name, artist and URL of each track in `tracks`"""
    for num, track in enumerate(tracks):
        # Print the relevant details
        print(
            f"{num + 1}. {track['name']} - {track['artists'][0]['name']} "
            f"{track['external_urls']['spotify']}")


def main():
    city = input("Virtual holiday city? ")
    city = city.lower()
    # Check the input city and handle unsupported cities.
    if city not in CITY_KEY_WORDS:
        print("Unfortunately, this city is not yet in our system. "
              "We will add it to our requests file.")
        with open('requests.txt', 'a') as f:
            f.write(f"{city}\n")
        exit()

    number_of_songs = input("How many songs would you like? ")
    tracks = fetch_tracks(city, int(number_of_songs))
    display_tracks(tracks)


if __name__ == '__main__':
    main()

【讨论】:

  • 非常感谢您提供如此有用和全面的答案,作为 python 的新手,这真是太有见地了!谢谢你的好意,我希望你在这一年过得愉快:)
【解决方案2】:

当你的if-statement 被执行时,你返回一个项目列表并将它们提供给display_tracks() 函数。但是当else-语句被执行时会发生什么呢?您将请求添加到您的文本文件,但不返回任何内容(或 NoneType 项目)并将其提供给 display_tracks()display_tracks 然后迭代这个NoneType-item,抛出你的异常。

如果确实有任何曲目要显示,您只想显示曲目。一种方法是将display_tracks() 的调用移动到您的main 函数中,但是如果在您的搜索词中找不到任何轨道,则会引发相同的错误。另一种解决方案是首先检查您的 tracks 是否不为空,或者使用类似

的内容捕获TypeError-exception
tracks = main(city, int(number_of_songs))
try:
    display_tracks(tracks)
except TypeError:
    pass

【讨论】:

  • 非常感谢您的帮助,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-31
  • 2022-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多