我正在尝试解决一个我有一个用于存储其他类对象的类的问题。我希望能够在某些类型的嵌套对象的父对象中创建一个列表。 (对不起,如果我对此措辞不好)
以我的示例为例,我正在考虑一个现实世界中的房屋问题。在房子里,我们可能有许多不同的“东西”。我们可能会有人,宠物,家具,计算机等。
我希望能够以嵌套格式存储它,因此我创建了一个内部带有任何子对象的房屋。
例如
old_rectory = House(
Person('Barry'),
Person('Bob'),
Pet('Bill'),
Pet('Brenda')
)
我创建了3个班级:第一个是针对房屋本身的班级,然后是针对人的班级和针对宠物的班级。
对于house
类,我使用* argv,以便可以根据需要添加尽可能多的其他对象。
现在在上面的示例中,我希望能够访问old_rectory.people
并查看old_rectory
中类型为Person
的所有实例的列表。
class House:
def __init__(self,*argv):
self.people = []
self.pets = []
for arg in argv:
if isinstance(arg, Person):
self.people.append(arg)
elif isinstance(arg, Pet):
self.pets.append(arg)
class Person:
def __init__(self,name):
self.name = name
class Pet:
def __init__(self,name):
self.name = name
您可以看到,我通过将列表和某些if条件硬编码到House
类中来实现此目的。但这意味着,每当我创建一个新类时,我还需要向House
类添加新列表和逻辑。
我希望能够从各个类(house
,Person
等)访问Pet
对象的属性,但是我不确定如何进行或是否确定甚至有可能。
class Doors:
NOW CREATE THE NEW LIST IN HOUSE CLASS
def __init__(self,name):
self.name = name
NOW APPEND THIS OBJECT TO THE NEW LIST IN THE HOUSE CLASS
答案 0 :(得分:1)
关于如何克服这一问题,我可以看到两种清晰的模式:
只需将每个实例放入一个大列表中,并添加方法以获取每个“子列表”:
class House:
def __init__(self,*argv):
self.things = [*argv]
@property
def pets(self):
return [thing for thing in self.things if isinstance(thing, Pet)]
@property
def people(self):
return [thing for thing in self.things if isinstance(thing, Person)]
这并不能真正解决您的最初问题,但至少对于新类而言,实现起来更容易,更清洁-如果list属性不存在,那是因为您尚未实现该方法。
hasattr
,setattr
和getattr
在__init__
方法上使用这些函数以编程方式检查每个列表是否存在,如果需要,可以创建它们,并将每个实例附加到相应的列表中:
class House:
def __init__(self,*argv):
for arg in argv:
name = arg.__class__.__name__.lower()
if not hasattr(self, name):
setattr(self, name, [])
getattr(self, name).append(arg)
我个人认为情况更糟,因为您的属性将被命名为与类名完全相同的名称(即person
,而不是people
),并且您无法清楚地看到哪些列表已初始化为属性因为它是即时完成的,所以不会,但是它应该可以用于您描述的用例。
无论您决定采用哪种方式,请注意,我个人认为您的设计对于解决此问题不是很有效。我宁愿在people
的{{1}}方法上为pets
,House
等创建空列表,并添加诸如__init__
,{{1} },add_person
等用于将对象附加到add_pet
的列表属性中。看起来似乎不多,但是这种设计:
a)明确定义了可以与add_group
类进行交互的受支持类;和
b),因为您需要显式调用该方法,因此您可以更清楚地清楚地知道谁将被放入House
。
答案 1 :(得分:0)
我已经重组了您的代码。签出:)
class House:
def __init__(self,*argv):
self.house_classes = {"people": Person, "pets": Pet}
self.house_objects = {}
for object in argv:
self.add_house_object(object)
def add_house_class(self, class_id, class):
self.house_classes["class_id"] = class
def add_house_object(self, object):
for class_id in self.house_classes:
if isinstance(object, self.house_classes[class_id]):
if class_id in self.house_objects:
self.house_objects["class_name"].append(object)
return
self.house_objects["class_id"] = [object]
class Person:
def __init__(self,name):
self.name = name
class Pet:
def __init__(self,name):
self.name = name
要向房屋对象添加新类(例如门)(如我所想)
my_house = House(house_objects...) #initialise a house object
class Doors: #your new class to add to house object
def __init__(self,name):
self.name = name
my_house.add_house_class(self, "doors", Doors) #added to house object
new_door = Door("my door") #door object
my_house.add_house_object(new_door)
我希望能对您有所帮助:)
答案 2 :(得分:-1)
您可以检查House
是否具有doors
的{{1}}列表,如果列表不存在,则可以创建该列表。此解决方案假定您打算将列表创建为类变量(我假设这样做是因为您在实例化a时不传递任何getattr(House, 'doors', None)
实例引用做House
Doors
实例)。
Doors
但我强烈建议您不要使用此模式。这似乎是类继承的一个好例子,例如,使用class Doors:
def __init__(self,name):
if getattr(House, 'doors', None) is None:
House.doors = []
self.name = name
House.doors.append(self)
创建类Doors
。
此外,我觉得您应该查看类变量和实例变量的定义和含义。
处理此任务的最佳方法是使class Doors(House):
为一个继承自Doors
的类,并要求房屋的现有实例能够创建House
实例(例如,使用Doors
检查)。然后,Doors if isinstance(new_house, House):
方法可以将列表__init__
作为实例变量创建和/或附加到doors
。
这样,您可以创建许多不同的房屋。而在House
列表中使用类别变量时,每所房屋将在所有房屋中创建所有门。
因此,我建议使用以下模式:
doors
正如jfaccioni指出的:继承不是强制性的,但是这种构造看起来从长远来看将需要方法访问等。