按对象属性访问Python对象列表

按对象属性访问Python对象列表,python,Python,我不知道我想做的是不是太不符合python,我只是想做错事,或者我不知道如何正确地问这个问题。这对我来说是有道理的,但我已经找到了15种不同的方法,却找不到答案 我想做的事情似乎很简单:我有一个对象列表。我想通过对象的属性访问该列表。此代码适用于: class Fruit: def __init__(self, name, color): self.name = name self.color = color def __str__(self):

我不知道我想做的是不是太不符合python,我只是想做错事,或者我不知道如何正确地问这个问题。这对我来说是有道理的,但我已经找到了15种不同的方法,却找不到答案

我想做的事情似乎很简单:我有一个对象列表。我想通过对象的属性访问该列表。此代码适用于:

class Fruit:
    def __init__(self, name, color):
        self.name = name
        self.color = color

    def __str__(self):
        return self.name    

class BaseballPlayer:
    def __init__(self, name, number, position):
        self.name = name
        self.number = number
        self.position = position

    def __str__(self):
        return self.name    

class ListByProperty(list):
    def __init__(self, property, list):
        super(ListByProperty, self).__init__(list)
        self.property = property

    def __getitem__(self, key):
        return [item for item in self if getattr(item, self.property) == key][0]

fruits = ListByProperty('name', [Fruit('apple', 'red'), Fruit('banana', 'yellow')])

baseballTeam = ListByProperty('position', [BaseballPlayer('Greg Maddux', 31, 'P'),
                                           BaseballPlayer('Javy Lopez', 8, 'C')])
teamByNumber = ListByProperty('number', baseballTeam)

print 'Apples are', fruits['apple'].color

pitcher = baseballTeam['P']
print 'The pitcher is #%s, %s' % (pitcher.number, pitcher)
print '#8 is', teamByNumber[8]

>>> Apples are red
The pitcher is #31, Greg Maddux
#8 is Javy Lopez
但是,我真的需要创建自己的列表类来做这么简单的事情吗?除了循环或listcomp之外,没有通用的方法吗?这似乎应该是一件非常常见的事情,拥有一个对象列表,并通过对象的属性访问列表中的项。它似乎应该以类似于
sorted(key=…)
的方式得到普遍支持

请注意,这与需要dict的情况不同。事实上,使用对象列表而不是dict的全部目的是避免执行以下操作:

fruits = {'apple': Fruit('apple', 'red')}
…这要求您键入
apple
两次。似乎应该有一种通用的方法来做这样的事情:

print 'Apples are', fruits['apple'].color
fruits = [Fruit('apple', 'red'), Fruit('banana', 'yellow')]
fruits = {f.name: f for f in fruits}
…无需子类化
列表

好的,你可以建立这样一个dict:

print 'Apples are', fruits['apple'].color
fruits = [Fruit('apple', 'red'), Fruit('banana', 'yellow')]
fruits = {f.name: f for f in fruits}
或者你可以只写一行,但这仍然看起来……呃……语法上是酸的?:)

到目前为止,我认为最好的办法是:

class DictByProperty(dict):
    def __init__(self, property, list):
        super(DictByProperty, self).__init__({getattr(i, property): i for i in list})
        self.property = property

fruits = DictByProperty('name', [Fruit('apple', 'red')])
哦,谢谢,我已经从这个问题中学到了很多

class Fruit:
    def __init__(self, name, color):
        self.name = name
        self.color = color

fruits = dict(zip(['apple', 'banana'], [Fruit('apple', 'red'), Fruit('banana', 'yellow')]))

print("An apple is %s" % fruits['apple'].color)
或:


以下事实并不产生一个集合:

fruits = {Fruit('apple', 'red'), Fruit('banana', 'yellow')}
请注意与我创建dict的方式不同

fruits = [Fruit('apple', 'red'), Fruit('banana', 'yellow')]

print("An apple is %s" % fruits[fruits.index('apple')].color)

不起作用,因为您的列表包含类型为fruit而不是String的对象,这里的情况也一样:

fruits = FruitList([Fruit('apple', 'red'), Fruit('banana', 'yellow')])

print("An apple is %s" % fruits['apple'].color)
要使上述方法起作用,请执行以下操作:

class Fruit:
    def __init__(self, name, color):
        self.name = name
        self.color = color

    def __eq__(self, other):
        if isinstance(other, Fruit):
            return (self.name, self.color) == (other.name, other.color)
        return self.name == other

fruits = [Fruit('apple', 'red'), Fruit('banana', 'yellow')]
print("An apple is %s" % fruits[fruits.index('apple')].color)

我不建议这样做,因为如果列表恰好包含字符串
apple
,那么对
color
的属性调用将无效,因为字符串没有名为
color
的属性,您可以创建一个实例

apple = Fruit('apple', 'red')
print(apple.color) # I use Python 3.x
我不确定我是否明白你的问题。但也许这有帮助

编辑:为了重新赢得我的声誉

您可以使用字典中的实例。例如

banana = Fruit('banana', 'yellow')
apple = Fruit('apple', 'red')
fruits = {'apple':apple, 'banana':banana}
或者,如果您愿意:

fruits = {'apple':Fruit('apple', 'red'), 'banana':Fruit('banana', 'yellow')}
无论哪种方式,你都可以简单地用

print(fruits['banana'].color)

除了解释:
{Foo,Bar,Baz}
是一个集合,
{'Foo':Foo,'Bar':Bar}
是一个指令。请注意,一个有键,另一个没有。傻我,我忘了
{/code>也有集合非常酷,stack exchange知道水果类的颜色!我不明白这为什么会被否决。这个方法有什么问题吗?我重写了我的问题,以澄清我在寻找什么,这是为了避免必须键入两次水果名称。谢谢。:)@blujay类是否绝对需要有name属性?您可以创建一个只需要颜色的类。。。e、 g fruits={'apple':Fruit('red'),等等)称为fruits['apple'].color。至少这样可以避免键入“apple”两次,并且只需要三行代码来编写类。那么,它不再是一个真正的“Fruit”类,而是一个“color”如果对象是作为参数传递的,那么它不会嵌入其水果类型,因此必须手动随它一起传递。此时,您最好只执行
fruits={'apple':'red','banana':'yellow'}
。这不仅是一个冗余问题,而且是以一种似乎有意义的方式将对象保持在一起的问题。“不起作用,因为您的列表包含类型为fruit而不是string的对象…”但我设置了
水果
对象上。我的问题是为什么
索引
方法在那里不起作用。谢谢。
\uuuuuuu stru\uuuuuu
方法只在打印对象时调用。它不用于比较。如果你重载了
\uuuuuuu eq\uuu
方法,那么这可能会起作用。请参阅我的editAh,
__eq_uu
。我不知道为什么我错过了用于列表的那个。我误解了,认为它是在dicts中使用的。谢谢。似乎这仍然是获得
水果['apple'的唯一方法
工作就是对
列表进行子类化。这真的是唯一的方法吗?@blujay:只使用dict。列表不是为这样使用而设计的;dict是。通过正确构建dict,可以消除使用dict时的冗长,如
{x.name:x代表x in…}
example。您甚至可以编写一个helper函数来为您构建dict,因此它看起来类似于
attrlookupdict(l,'name'))
。谢谢。我提出了一个使用dict的
DictByProperty
类,按照您建议的方式构建它。我觉得必须有一种通用的方法或标准库来实现这一点,我只是错过了。。。