繁体   English   中英

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

[英]Inherit from Instance rather than Class [Python 3]

我想启动一个子类的多个实例,每个实例从一个类的特定实例而不是一般类中获取它们的属性。

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

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 方法,该方法使用来自其父类实例的属性位置,该属性对于该建筑物而言是唯一的,而不是通用值。 它还需要能够使用来自父类 Evacuate_Building 的方法。

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

我还可以通过将 Building 的实例作为参数传递给 init ,然后执行 this.location = building.location 来复制属性,但这也存在与上述相同的问题,而且我无法通过这种方式获取方法。

我想要某种方式传递 Building 的特定实例,以便房间继承其特定属性和方法。

欢迎任何反馈,建议,批评,完全不同的方法! 先感谢您!

A 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

你也可以,也许,让房间包含对它们所在建筑物的引用; 此引用可以是在向建筑物添加房间时分配的属性:

class Building:
    ...
    def add_room(self, room):
        room.bldg = self
        self.rooms.append(room)

你的设计很奇怪。 一个房间不是一个建筑物,那么为什么Room应该从Building继承呢? 1

房间和建筑物之间的关系:每个房间是在建筑物和每一个建筑包含零个或多个房间。 可以通过组合物, -即通过加入成员代表任一关系或两者,2:

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

或者:

class Building:
    def __init__(self, buildingName, location):
        self.buildingName = buildingName
        self.location = location
        self.rooms = set()
    def add(self, room):
        self.rooms.add(room)

如果你愿意,你甚至可以让Room.__init__调用building.add(self)


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

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

甚至不仅仅是静态地在代码中。 您可以在运行时使用self.location = new_location移动Building 然后,对于该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着火了,因此您需要疏散该Room所在的整个Building ,包括所有房间,该怎么办? 很简单:您撤离Roombuilding属性:

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

1. 这就是继承的意思: class Room(Building):表示任何Room都是Building 或者,换句话说:任何想要Building并获得Room都会对它感到满意。 有时有理由颠覆这种含义(例如,mixin 类只是class Skyscraper(Building, MajorConstructionMixin):方法实现;如果您编写class Skyscraper(Building, MajorConstructionMixin): ,您并没有真正声明SkyscraperMajorConstructionMixin因为那并不这真的没有任何意义;你只是借用了一些方便的实现代码)——但这仍然是你颠覆的意思。

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

虽然我意识到这是一个老问题,但我认为从实例继承到类的主要问题值得关注。

我不确定前面的答案是否完全理解你的例子,从实例继承的重要性,其中的特性不能提前详细说明,根据定义,类需要这样做。

在另一个问题中,我找到了一个描述模块 Acquisition的答案它正是从一个实例继承而来的。 可能值得一看: 从 Python 中的实例继承

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM