从实例而不是类继承[Python 3]

2024-05-23 13:40:01 发布

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

我想要启动一个子类的多个实例,每个实例都从一个类的特定实例获取它们的属性,而不是常规类。在

例如,如果我有建筑物和房间,则每个房间都需要属于某个建筑的特定实例,使用其属性和方法。在

class Building:
     def __init__(self, buildingName, location):
        self.buildingName = buildingName
        self.location = location
        # lots more intersting stuff

    def Evacuate_Building(self):
        # do some stuff
        pass

class Room(Building):
     def __init__(self, roomName, roomType):
        self.roomName = roomName
        self.roomType = roomType
        # lots more intersting stuff

    def Directions(self, Current_Location):
        '''do some stuff involving this.roomName and this.location which comes from the specific instance of the class'''
        pass

所以假设我有三栋楼:“北”、“南”和“西”。在

每栋楼都有自己的房间。在

只看北边的大楼就有“N1”、“N2”、“N3”、“N4”房间。在

在我的代码中,我会先检查并启动三个建筑,然后我会启动房间,一些如何将它们连接回相应的建筑。在

这使我可以使用Directions方法,该方法从其父类实例中指定属性位置,该类实例对该建筑是唯一的,而不是常规值。它还需要能够使用父类的方法esculate_Building。在

我可以通过每次使用super(buildingName,location)或Building在更标准的设置中启动一个房间时传递位置数据来解决这个问题。但是这意味着我必须为每个房间编写位置,如果我在建筑中添加或更改了某些内容,我需要改变每一个房间初始化和初始化代码,如果已经添加了其他属性。在

我还可以通过将建筑实例作为参数传递给init,然后这个位置= 建筑物.位置但这也有同样的问题,加上我没有得到这样的方法。在

我需要一些方法来传递建筑的特定实例,以便房间继承其特定属性和方法。在

欢迎任何反馈,建议,批评,完全不同的方式来做这件事!提前谢谢!


Tags: 实例方法self属性initdeflocationclass
2条回答

Room不是Building==>;Room不应是Building的子类。
一个Building有很多Room==>;使用组合。在

一种可能的方法是让每个Building都有一个Room的集合

class Building:
    def __init__(self, name, location):
        self.name = name
        self.location = location
        self.rooms = []            # or a set as in @Abamert's reply
                                   # or dict if you want to address it by floor and number, maybe?
    def add_room(self, room):
        self.rooms.append(room)

class Room:
    def __init__(self, name, model):
        self.name = roomName
        self.model = model

也可以让房间保存对其所在建筑的参照;该参照可以是在向建筑添加房间时指定的属性:

^{pr2}$

你的设计很奇怪。房间不是建筑物,那么Room为什么要继承{}?1

房间和建筑物之间有一种关系:每一个房间都在一个建筑物中,每一栋建筑物都包含零个或多个房间。您可以通过组合来表示其中一种关系,也可以同时表示这两种关系,即通过添加成员:

class Room:
    def __init__(self, building, roomName, roomType):
        self.building = building
        self.roomName = roomName
        self.roomType = roomType
        # lots more intersting stuff

或者:

^{pr2}$

如果你愿意,你甚至可以打Room.__init__电话building.add(self)。在


请注意,这正是您想要的:每个Room与特定的Building实例self.building相关,而不是与Building类相关。在

因此,您不必为每个Room编写位置,只需将相同的Building实例传递给所有这些实例。如果我在Building中添加或更改某些内容,那么该建筑中的每个Room都将在其self.building中看到该更改,而无需您重复自己的操作或做任何特殊的操作。在

甚至不只是静态地在代码中。可以使用self.location = new_location在运行时移动Building。然后,对于其中的每一个Room,它的self.building.location现在是new_location。在


另外,您通常不希望Room支持Building的方法。在Room上调用Evacuate_Building没有多大意义。调用Evacuate_Room可能。在这种情况下,Building可能会执行以下操作:

def Evacuate_Building(self):
    for room in self.rooms:
        room.Evacuate_Room()

但是如果你发现一个Room着火了,因此你需要疏散{}里面的所有房间,包括所有的房间?简单:将Roombuilding属性清空:

if is_on_fire(room):
    room.building.Evacutate_Building()

1。这就是继承的含义:class Room(Building):表示任何{}都是Building。或者,换一种方式:任何需要Building并得到Room的代码都会很满意。有时有理由颠覆这一含义(例如,mixin类只是一大堆方法实现;如果您编写class Skyscraper(Building, MajorConstructionMixin):,那么您并没有真正声明SkyscraperMajorConstructionMixin,因为这并不真正意味着什么;您只是借用了一些方便的实现代码),但这仍然是您要颠覆的意思。

2。请注意,如果在两个方向上添加引用,则有一个引用循环。这并不违法,甚至通常是一个问题;它只是意味着,当您放弃一个建筑及其所有房间时,CPython垃圾收集器不会立即找到并删除它们,直到下次运行收集器。不过,虽然这不是什么大问题,但大多数程序并不需要两个方向的关系,因此您应该看看是否可以通过消除一个来简化设计。

相关问题 更多 >