在类名来自lis的循环中创建类

2024-05-21 14:30:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我基本上是想从播放列表中提取歌曲名称,然后我想为播放列表中的每首歌曲创建一个类,其中包含该歌曲的所有相关数据(歌曲标题、艺术家、每首歌曲的位置等)

我有一个列表,列表中的每一项都是歌曲名。我正在尝试创建一个循环,该循环将根据列表中的每个项创建一个新类。

这就是我目前所拥有的:

class MyClass():
    var = "hi"

songNames = ['song1', 'song2', 'song3']

for name in songNames:
    name = MyClass()

这不起作用,我认为这是因为Python遇到了麻烦/无法为这样的类分配名称。我是一个Python的初学者,经过大量的搜索,我无法想出一个解决方案。正确的方法是什么?


所以我一直在写代码,并取得了一些进展:

class SongData(object):
    def __init__(self, title="", artist="", directory=""):
        self.title, self.artist, self.directory = title, artist, directory
    def __str__(self):
        desc_str = "Title: %s \nArtist: %s \nDirectory: %s \n" %(self.title,
                                            self.artist, self.directory)
        print desc_str

songNames = ['song1', 'song2', 'song3']
artistNames = ['artist1', 'artist2', 'artist3']
dirNames = ['dir1', 'dir2', 'dir3']

songs = {name: SongData(title=name) for name in songNames}
artists = {band: SongData(artist=band) for band in artistNames}
directorys = {direc: SongData(directory=direc) for direc in dirNames}

我想能够打印出每首歌的desc_str,所以它看起来像这样:

Title: song1 
Artist: artist1 
Directory: dir1

但到目前为止,我只能一次调用一个数据类别,因此它会打印Title: song1,但会将Artist:Directory:部分留空。

我怎么能一次打印出来?


Tags: nameinself列表forbandtitleartist
1条回答
网友
1楼 · 发布于 2024-05-21 14:30:22

你不想为每首歌创建一个类;你想为每首歌创建一个类的实例。例如:

class Song(object):
    def __init__(self, name):
        self.name = name

songNames = ['song1', 'song2', 'song3']

songs = []
for name in songNames:
    songs.append(Song(name))

注意,我正在列表中存储Song对象。你需要把它们存储在某个地方,或者以后不能再访问它们,对吧?

如果您希望以后能够按名称访问它们,而不只是循环访问所有这些对象:

songs = {}
for name in songNames:
    songs[name] = Song(name)

你可以用一种理解力把它们转换成一行:

songs = [Song(name) for name in songNames]
songs = {name: Song(name) for name in songNames}

从评论:

I had intended by class to look something like the following, because every song was going to have all the same variables:

class songData: 
    title = "" 
    artist = "" 
    directory = "" 
    tempStr = ""
    def description(self): 
        desc_str = "%s is by %s, located at %s" %(self.title, self.artist,self.directory)
        return desc_str

这是错误的,原因与我已经解释过的相同:您创建的是类属性,而不是实例属性。这意味着每个实例都将共享一个标题等,这不是您想要的。而且,这意味着self.title是误导性的(尽管它会起作用)。

同时,如果这是Python2,您将再次创建一个经典类。另外,您可能需要一个__str__方法,而不是一个特殊的description方法,因为这样您就可以print(song)而不必print(song.description())。最后,对变量和类使用相同的命名约定有点混乱。

你可能想要的是:

class SongData:
    def __init__(self, title="", artist="", directory=""):
        self.title, self.artist, self.directory = title, artist, directory
    def __str__(self): 
        desc_str = "%s is by %s, located at %s" % (self.title, self.artist,self.directory)
        return desc_str

现在,您可以使用与上面的Song类基本相同的方法:

songNames = ['song1', 'song2', 'song3']
songs = {name: SongData(title=name) for name in songNames}

现在你可以这样做:

name = input('What song do you want info on?') # raw_input, if Python 2
print(songs[name])

(当然,这不是很有用,除非您也有设置艺术家和目录的代码,因为它只会打印Song Windowlicker is by , located at。但我不知道你打算从哪里弄到这些。)


你的新代码有两个问题。首先:

def __str__(self):
    desc_str = "Title: %s \nArtist: %s \nDirectory: %s \n" %(self.title,
                                        self.artist, self.directory)
    print desc_str

你需要return desc_str在这里,而不是print它。


第二:

songNames = ['song1', 'song2', 'song3']
artistNames = ['artist1', 'artist2', 'artist3']
dirNames = ['dir1', 'dir2', 'dir3']

songs = {name: SongData(title=name) for name in songNames}
artists = {band: SongData(artist=band) for band in artistNames}
directorys = {direc: SongData(directory=direc) for direc in dirNames}

在这里,您将创建三个独立的SongData对象集合,每个对象只填充一个属性。

这里的关键是^{}。它是Python中最有用的函数之一,一旦你了解了它的功能,但是除非你知道它,否则你永远不会去寻找它。如果我展示它的功能,就更容易描述:

>>> zip(songNames, artistNames, dirNames)
[('song1', 'artist1', 'dir1'),
 ('song2', 'artist2', 'dir2'),
 ('song3', 'artist3', 'dir3')]

所以,这给了你一个元组列表,每个元组有一个歌曲名,一个艺术家和一个目录。第一个元组是每个元组的第一个元组,第二个元组是每个元组的第二个元组,等等

现在,您可以很容易地从每个元组构建一个SongData

songs = {}
for title, artist, directory in zip(songNames, artistNames, dirNames):
     songs[title] = SongData(title, artist, directory)

作为一种听写理解,它有点冗长:

songs = {title: SongData(title, artist, directory)
         for title, artist, directory in zip(songNames, artistNames, dirNames)}

但是你可以用另一个技巧来简化它:unpacking arguments

songs = {t[0]: SongData(*t) for songtuple in zip(songNames, artistNames, dirNames)}

当然,你不需要zip就可以做到这一点,但这看起来很混乱:

songs = {SongData(songNames[i], artistNames[i], dirNames[i])
         for i in range(len(songNames))}

…如果有一个列表不匹配的小错误,那么很难通过这种方式理解和调试。一般来说,无论何时用Python编写for i in range(len(foo)),可能有一种简单的方法。


无论您如何构建它,您都可以像预期的那样使用它:

>>> print songs['song1']
Title: song1 
Artist: artist1 
Directory: directory1

当我们在它的时候,你可能不希望在每行输出的末尾都有一个空格。它对人类来说是不可见的,但它可能会混淆您稍后编写的解析输出的代码,而且它会浪费空间,而且没有真正的好处。把每个\n放在%s后面。

网友
2楼 · 发布于 2024-05-21 14:30:22

我同意你似乎想为每首歌创建一个实例而不是一个类。但是如果您确实想为每首歌创建一个类,请使用type(className, parentTuple, attributeDict)函数。它返回具有给定名称的新类。

例如

songClasses = []
for name in songNames:
    songClasses.append(type(name, (), {}))

相关问题 更多 >