【问题标题】:Overriding part of the __init__ method in a subclass in Python 2在 Python 2 的子类中覆盖部分 __init__ 方法
【发布时间】:2018-01-14 21:10:26
【问题描述】:

我想创建一个子类的子类(Barrier 是一种墙,它是一种障碍物),我希望障碍物具有相同的 init 方法除了 self.type = 'barrier' 之外,我不知道该怎么做(我对编程很陌生,所以很抱歉,如果这很简单但我做不到找到我理解的答案)。到目前为止,我有:

class Obstacle:
    def __init__(self, type):
        self.type = 'obstacle'

    def __str__(self):
        return "obstacle"

class Wall(Obstacle):

    def __init__(self, origin, end):

        self.type = 'wall'
        self.origin = origin
        self.end = end

        # etc.... (i.e. there are more things included in here which the 
        # that the barrier also needs to have (like coordinate vectors etc.)

class Barrier(Wall):

    def __str__(self):
        return "Barrier obstacle"

如何更改它以使类 Barrier 具有与 Walls 相同的 init 方法内容,除了它们的“self.type = 'barrier'”?

【问题讨论】:

    标签: python class subclass


    【解决方案1】:

    在调用Wall 版本后覆盖该属性:

    class Barrier(Wall):
        def __init__(self, origin, end):
            super().__init__(origin, end)
            self.type = 'barrier'
    
        def __str__(self):
            return "Barrier obstacle"
    

    但是,您可能需要考虑使用类属性;您的实例属性都不是动态的并且特定于类的每个实例。这些类中的每一个的type 属性肯定不会从一个实例更改为另一个实例:

    class Obstacle:
        type = 'obstacle'
    
        def __str__(self):
            return self.type
    
    class Wall(Obstacle):
        type = 'wall'
    
        def __init__(self, origin, end):
            super().__init__()
            self.origin = origin
            self.end = end
            # etc.... (i.e. there are more things included in here which the 
            # that the barrier also needs to have (like coordinate vectors etc.)
    
    class Barrier(Wall):
        type = 'barrier'
    

    【讨论】:

    • 我刚刚尝试过这样做,但是当我尝试创建该类的实例时出现错误,因为它表示 Barrier 的 init 只有一个参数,但是我还需要给出起点和终点?
    【解决方案2】:

    由于“类型”似乎取决于类,我不会type 属性放在对象中,而是放在类级别

    class Obstacle:
    
        type = 'obstacle'
    
        def __init__(self):
            # do something
            pass
    
        def __str__(self):
            return "obstacle"
    
    class Wall(Obstacle):
    
        type = 'wall'
    
        def __init__(self, origin, end):
            super().__init__()
            self.origin = origin
            self.end = end
    
    class Barrier(Wall):
    
        type = 'barrier'
    
        def __str__(self):
            return "Barrier obstacle"

    此外,如果您覆盖它,最好调用super().__init__ 方法。因为否则类层次结构中更高的初始化将不会发生(这有时是期望的行为,但通常不是)。

    这样做的好处是——至少在我看来——更优雅。因为这里很明显type 是按类定义的。但此外,它将减少使用的内存量。由于我们为每个类存储一个属性,不是每个对象一个。

    但是,如果您想更改单个对象的属性,这仍然是可能的。例如:

    >>> obs1 = Obstacle()
    >>> weird_obs = Obstacle()
    >>> weird_obs.type = 'weird obstacle'
    >>> obs2 = Obstacle()
    >>> obs1.type
    'obstacle'
    >>> weird_obs.type
    'weird obstacle'
    >>> obs2.type
    'obstacle'
    

    所以我们仍然可以灵活地将特定类型添加到特定对象。但默认情况下,如果我们查询障碍物type,它将执行回退并返回在类级别上定义的type

    【讨论】:

    • 以防万一OP不理解:在__init__type = 'barrier'中使用self.type = 'barrier'在类牙列下的区别在于后者创建了一个“静态”变量。这基本上意味着type 属性将在Barrier 的所有实例之间共享。这里的好处是,由于type = 'barrier' 永远不会在每个实例中更改,因此您可以让所有实例共享一个属性,而不是让每个实例都有自己的属性。
    猜你喜欢
    • 2011-08-07
    • 2015-03-29
    • 2016-04-19
    • 1970-01-01
    • 2013-09-24
    • 2012-04-12
    • 2013-06-18
    • 2016-02-23
    • 2016-02-01
    相关资源
    最近更新 更多