向类列表添加属性以返回所有具有特定属性的对象

5 投票
4 回答
11698 浏览
提问于 2025-04-18 10:29

我遇到了一个问题:

让我们先了解一下背景!

假设我有一个叫做 Person 的类,它有一些基本的属性:

class Person(object):
    def __init__(self, name=None, gender=None, single=None):
        self.name=name
        self.gender=gender
        self.single=single

然后我创建了一个叫做 Dating 的列表类,这个类会存放所有的 Person 对象。

class Dating(object):
    def __init__(self):
        self.members=[]

My_People=Dating()

My_People.members.append(Person("Jack","Male",False))
My_People.members.append(Person("Jill","Female",True))
My_People.members.append(Person("George","Male",True))
My_People.members.append(Person("Sandy","Female",False))

那么,问题是什么呢?

我想知道,是否可以给这个列表类添加一个属性,这样我就能通过某种方式访问 My_People 列表中的单个成员,比如说:

My_People.members.singles

这样的话,就能返回那些属性为 single == True 的 Person 对象的列表吗?

谢谢大家的帮助。(顺便说一下,我对 Python 的经验非常有限)

相关问题:

4 个回答

0

如果你不一定要使用 My_People.members.singles 这种写法,其实可以更简单地做到这一点:

class Dating(object):

    def __init__(self):
        self.members = []

    @property
    def single_members(self):
        return [m for m in members if m.single]

现在你可以用下面的方式来访问这个列表:

My_People.single_members
1

这样怎么样:

class Attribute(list):
    def __getattr__(self, attr):
        if attr == 'single':
            return [person for person in self if person.single]
        raise AttributeError()

class Person(object):
    def __init__(self, name=None, gender=None, single=None):
        self.name = name
        self.gender = gender
        self.single = single

    def __repr__(self):
        return 'Person({person.name}, {person.gender}, {person.single})'.format(person=self)


class Dating(object):
    members = Attribute()


My_People = Dating()

My_People.members.append(Person("Jack", "Male", False))
My_People.members.append(Person("Jill", "Female", True))
My_People.members.append(Person("George", "Male", True))
My_People.members.append(Person("Sandy", "Female", False))

>>> print My_People.members.single
[Person(Jill, Female, True), Person(George, Male, True)]
>>> print My_People.members
[Person(Jack, Male, False), Person(Jill, Female, True), Person(George, Male, True), Person(Sandy, Female, False)]
4

首先,你不需要手动调用 __init__() 方法在 My_People 实例上,Python 会自动帮你处理这个。

关于这个问题,你可以从 list 这个类继承,并添加一个叫 singles 的属性,像这样:

class Person(object):
    def __init__(self, name=None, gender=None, single=None):
        self.name=name
        self.gender=gender
        self.single=single

class Dating(list):
    @property
    def singles(self):
        return [person for person in self if person.single ]

My_People=Dating()

My_People.append(Person("Jack","Male",False))
My_People.append(Person("Jill","Female",True))
My_People.append(Person("George","Male",True))
My_People.append(Person("Sandy","Female",False))

print My_People.singles
8

要添加这样的属性,你需要对列表类型进行子类化

class FilterableList(list):
    def __getattr__(self, name):
        # assume non-existing attributes are boolean filters
        return [elem for elem in self if getattr(elem, name)]

请注意,这种方法并不是特别灵活;只有True的值可以通过这种方式找到。你可以给属性名称赋予更多的意义,但通常你会想在Dating类上进行这样的操作,并使用方法来更清晰地筛选你的数据。

示例:

>>> class Person(object):
...     def __init__(self, name, gender, single):
...         self.name=name
...         self.gender=gender
...         self.single=single
...     def __repr__(self):
...         return 'Person({name!r}, {gender!r}, {single!r})'.format(**vars(self))
... 
>>> class FilterableList(list):
...     def __getattr__(self, name):
...         # assume non-existing attributes are boolean filters
...         return [elem for elem in self if getattr(elem, name)]
... 
>>> members = FilterableList([Person("Jack","Male",False), Person("Jill","Female",True), Person("George","Male",True), Person("Sandy","Female",False)])
>>> members
[Person('Jack', 'Male', False), Person('Jill', 'Female', True), Person('George', 'Male', True), Person('Sandy', 'Female', False)]
>>> members.single
[Person('Jill', 'Female', True), Person('George', 'Male', True)]

撰写回答