使用 Spotipy/Spotify API 的 'else' 序列问题
Issue with 'else' sequence using Spotipy/Spotify API
我和我的团队(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 语句是 运行 时,在执行完操作后会出现 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
请原谅我的知识匮乏,但有人可以帮助解决这个问题吗?
我们也想在最后创建一个歌曲的播放列表,但是在这方面遇到了困难。
当您的 if
语句被执行时,您 return 一个项目列表并将它们提供给 display_tracks()
函数。但是当执行 else
语句时会发生什么?您将请求添加到您的 text-file,但不要 return 任何东西(或 NoneType
项目)并将其提供给 display_tracks()
。 display_tracks
然后迭代此 NoneType
项,抛出异常。
如果确实有任何曲目要显示,您只想显示曲目。一种方法是将 display_tracks()
的调用移动到 main
函数中,但是如果找不到 search-terms 的曲目,则会抛出相同的错误。另一种解决方案是首先检查您的 tracks
是否不为空,或者使用
之类的东西捕获 TypeError
异常
tracks = main(city, int(number_of_songs))
try:
display_tracks(tracks)
except TypeError:
pass
您的 main
函数在 else
子句中没有 return
语句,这导致 tracks
成为 None
。在 tracks
为 None
时迭代 tracks
是导致错误的原因。
您可以做一些事情来改进代码:
- 关注点分离:
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 的新手)编写了以下代码来生成与特定城市和相关术语相关的 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 语句是 运行 时,在执行完操作后会出现 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
请原谅我的知识匮乏,但有人可以帮助解决这个问题吗?
我们也想在最后创建一个歌曲的播放列表,但是在这方面遇到了困难。
当您的 if
语句被执行时,您 return 一个项目列表并将它们提供给 display_tracks()
函数。但是当执行 else
语句时会发生什么?您将请求添加到您的 text-file,但不要 return 任何东西(或 NoneType
项目)并将其提供给 display_tracks()
。 display_tracks
然后迭代此 NoneType
项,抛出异常。
如果确实有任何曲目要显示,您只想显示曲目。一种方法是将 display_tracks()
的调用移动到 main
函数中,但是如果找不到 search-terms 的曲目,则会抛出相同的错误。另一种解决方案是首先检查您的 tracks
是否不为空,或者使用
TypeError
异常
tracks = main(city, int(number_of_songs))
try:
display_tracks(tracks)
except TypeError:
pass
您的 main
函数在 else
子句中没有 return
语句,这导致 tracks
成为 None
。在 tracks
为 None
时迭代 tracks
是导致错误的原因。
您可以做一些事情来改进代码:
- 关注点分离:
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()