用sing检查所有对象参数的更好方法

2024-06-26 01:34:04 发布

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

我想得到所有年龄小于18岁的物体。你怎么能轻易做到? 我应该通过所有的物体才能得到它吗?你知道吗

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

    def get_nonage(self):
        # print nonage here which age<18
        # expected output: {1: 11, 3: 15}
        pass

p1 = People(1, 11)
p2 = People(2, 20)
p3 = People(3, 15)

。。。你知道吗

People.get_nonage()


Tags: selfwhichageuidgethereinitdef
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()(上面写在list 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一起玩。你知道吗

为了搜索所有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)

在评论中,你会问:

Can I just know the class is People, then use some method of People to directly get all data of its objects

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

当然,如果您真的想这样做,您可以让一个类在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。你知道吗

    @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不会知道你做了那件事;那个人仍然会在那里,而且仍然会被计算在内,即使你再也没有办法接近他们。你知道吗

相关问题 更多 >