#python #list #class #filter #attributes
#python #Список #класс #Фильтр #атрибуты
Вопрос:
У меня следующая проблема:
Давайте установим сцену!
Допустим, у меня есть класс 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))
Правильно, так в чем проблема?
Можно ли присвоить атрибут классу list для доступа к отдельным элементам списка My_People, создав какой-то атрибут, например:
My_People.members.singles
Так что это вернет список объектов Person, которые имеют один атрибут == True?
Спасибо за всю помощь. (кстати, у меня очень мало предыдущего опыта работы с Python)
Комментарии:
1. прекратите вызывать
__init__
метод, он работает таким образом без вашей помощи)2. Отредактировал вопрос. Теперь лучше?
3. Кто-нибудь знает, почему это было отклонено? Обратная связь полезна, поэтому я могу отредактировать вопрос и, надеюсь, решить проблему
Ответ №1:
Чтобы добавить подобные атрибуты, вам нужно будет подкласс типа списка:
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)]
Комментарии:
1. Спасибо за это, это именно то, что мне нужно, и мне нравится гибкость вашего решения. Кроме того, я никогда раньше не использовал repr , и это действительно пригодится!
Ответ №2:
Прежде всего, вам не нужно вызывать __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
Комментарии:
1. отлично, я это понимаю. Поэтому вам нужно перебирать список My_People каждый раз, когда вы хотите получить доступ к My_People.singles, и нет прямого способа вызвать эти объекты с помощью атрибута single==True .
2. Мне нравится предложение создать подкласс из списка, очень удобно
3. @user1083734 Вы, конечно, можете сохранить
.singles
возвращаемые результаты, чтобы избежать повторения списка при каждом доступе.4. но тогда мне не пришлось бы обновлять результаты синглов, вызывая функцию снова каждый раз, когда изменяется список My_People?
Ответ №3:
Как насчет этого:
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:
Если вы не привязаны к 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