一次调用即可检查所有对象参数的更好方法

时间:2018-07-27 06:16:21

标签: python

我想获取所有年龄小于18岁的对象。如何轻松地做到这一点? 我是否应该将所有对象都传递给get_nonage来获得它?

post_id

...

related_posts

2 个答案:

答案 0 :(得分:2)

您的设计在这里似乎有缺陷。首先,People实际上是Person。这是一个重要的区别,因为类名称应与其构建所依据的数据和功能相匹配。就您而言,一群人没有年龄和身分,但一个人却没有。创建人员后,将其放入名为人员的列表中。然后,减少/过滤/映射操作(例如您要求的操作)就很简单。

class Person:
    def __init__(self, uid, age):
        self.uid = uid
        self.age = age

    def __repr__(self):
        return "Person (id: {}, age: {})".format(self.uid, self.age) 

people = [
    Person(1, 11),
    Person(2, 20),
    Person(3, 15)
]

underage_people = [p for p in people if p.age < 18]
print(underage_people)

输出:

[Person (id: 1, age: 11), Person (id: 3, age: 15)]

如果需要,您可以像atline's answer一样将此列表理解放在静态类函数中,但对我来说似乎不合适。这种方法应该属于其他一些管理人员的类,例如VoterRegistration应用程序类,它需要确定谁没有资格投票。或者它可以在People类中,以某种方式收集Person。无论哪种方式,我认为重要的是要清楚地建立要在此处使用类和对象建模的数据和关系。在这两种情况下,People类都将具有Person对象的成员列表以及用于操纵和报告该数据的各种函数,例如get_underage()(如上表所示)例如comp)或get_median_age()。这是我在说什么的具体草图:

class Person:
    def __init__(self, uid, age):
        self.uid = uid
        self.age = age

    def __lt__(self, other):
        return self.age < other.age

    def __repr__(self):
        return "Person (id: {}, age: {})".format(self.uid, self.age) 

class People:
    def __init__(self, people):
        self.people = people

    def get_underage(self):
        return [p for p in self.people if p.age < 18]

    def get_average_age(self):
        return sum([p.age for p in self.people]) / len(self.people)

    def get_oldest(self):
        return max(self.people)

    def get_youngest(self):
        return min(self.people)

people = People([
    Person(1, 11),
    Person(2, 20),
    Person(3, 15)
])

print("Underage people: {}".format(people.get_underage()))
print("Average age: {}".format(people.get_average_age()))
print("Oldest: {}".format(people.get_oldest()))
print("Youngest: {}".format(people.get_youngest()))

输出:

Underage people: [Person (id: 1, age: 11), Person (id: 3, age: 15)]
Average age: 15.333333333333334
Oldest: Person (id: 2, age: 20)
Youngest: Person (id: 1, age: 11)

和一个repl一起玩。

答案 1 :(得分:1)

要搜索所有People对象,必须拥有所有People对象。

但这意味着您一开始不应该将它们放在一堆单独的变量中,而应该放在一个列表等集合中。

然后,get_nonage可以列出该列表。

虽然我们正在这样做,但没有理由将get_nonage用作方法。这不是People实例所做的事情,而是您对一堆People实例所做的事情。

所以:

class People:
    # ...

def get_nonage(people):
    nonage = {person.uid: person.age for person in people if person.age<18}
    print(nonage)

people = [
    People(1, 11),
    People(2, 20),
    People(3, 35)
]

get_nonage(people)

在评论中,您询问:

  

我能知道类是People吗,然后使用People的某种方法直接获取其对象的所有数据

那是什么方法?你还没有写。一个类通常并不知道所有实例。

当然,如果确实需要,可以使一个类在class属性中记录其实例。 (普通实例,例如age,每个实例都有一个单独的值。类属性具有一个由所有实例共享的值。)

例如:

class People:
    all_people = []

    def __init__(self, uid, age):
        self.uid = uid
        self.age = age
        self.all_people.append(self)

如果这样做,则可以使get_nonage成为类方法-即要在类本身而不是实例上调用的方法。类方法获取类cls作为其第一个参数,而不是实例self,它只能访问类属性,例如我们上面刚刚创建的all_people。 / p>

    @classmethod 
    def get_nonage(cls):
        nonage = {person.uid: person.age for person in cls.all_people if person.age<18}
        print(nonage)

现在,您可以调用它,而无需传递任何内容,因为它已经知道所有内容:

people = [
    People(1, 11),
    People(2, 20),
    People(3, 35)
]

People.get_nonage()

但是,这通常不是一个很好的设计。例如,如果要删除一个人怎么办?以前,您只是将它们从列表中删除(或者,在您的原始版本中,将p3重新分配给其他内容)。但是People.all_people会不知道您这样做了;即使您再也无法访问此人,该人仍将在那里,并且仍会被计数。