【问题标题】:Inheritance : transform a base class instance to a child class instance继承:将基类实例转换为子类实例
【发布时间】:2011-08-16 12:23:29
【问题描述】:

我有一个基类的实例,然后我想让它成为这个基类的子类的实例。也许我以错误的方式处理问题,并且在 OOP 中有一些我不理解的重要内容。代码只是用来说明的,可以建议一种非常不同的方法。任何帮助表示赞赏。

class Car(object):
    def __init__(self, color):
        self.color = color

    def drive(self):
        print "Driving at 50 mph"

class FastCar(Car):
    def __init__(self, color, max_speed=100):
        Car.__init__(self, color)
        self.max_speed = max_speed

    def drive_fast(self):
        print "Driving at %s mph" %self.max_speed

one_car = Car('blue')

# After the instanciation, I discovered that one_car is not just a classic car
# but also a fast one which can drive at 120 mph.
# So I want to make one_car a FastCar instance.

我看到了一个非常相似的问题,但没有一个答案适合我的问题:

  • 我不想让 FastCar 成为知道如何快速驾驶的 Car 的包装器:我真的希望 FastCar 扩展 Car ;

  • 我真的不想在 FastCar 中使用 __new__ 方法对参数进行一些测试并决定 __new__ 是否必须返回 Car 的新实例或我给它的实例 (例如:def __new__(cls, color, max_speed=100, baseclassinstance=None))。

【问题讨论】:

  • 你为什么不这样做:one_car = FastCar(one_car.color, 120) ?这不是真正的继承或其他任何东西,但应该可以工作。
  • 您的 OOP 设计似乎有点不对劲。我想 FastCar 也会实现 drive(),但会以更高的速度(你已经实现为 drive_fast)。有了你现在所拥有的,调用者必须知道类型才能知道调用哪个方法(坏),而不是调用相同的方法并让各种类型适当地实现该方法(好)。您也可以通过在 FastCar 类的末尾添加 drive = drive_fast 来做到这一点。
  • 好的。一个更好的例子:FastCar 没有drive_fast 方法,而是overtake 方法,而Car 不存在这种方法。
  • @Eugene @agf @Peter 好吧,我的例子太简单了。整件事是我不想创建一个新对象,也不想有两个不同的实例。如果有帮助,假设Car 来自外部模块,color 实际上是__colorCar 的私​​有成员。或者Car.__init__ 不仅将color 分配给self.color,而且对颜色进行了大量计算(实际上是一个很大的numpy.array),并且我无法重复这些计算来创建FastCar
  • 由于 Python 中没有真正的私有成员,您可以只使用我的任一方法的版本——只需将计算的属性复制到新实例(方法 1)或仅更改当你摆弄它的属性(我的方法2)时,类和任何必要的方法——这一切都假设你仍然不想有条件__new____init__s。不过,如果您认为需要这样做,可能需要重新设计继承/类结构。

标签: python oop inheritance


【解决方案1】:
class FastCar(Car):
    def __init__(self, color, max_speed=100):
        Car.__init__(self, color)
        self.max_speed = max_speed

    def drive_fast(self):
        print "Driving at %s mph" %self.max_speed

    @staticmethod
    def fromOtherCar(car):
        return FastCar(car.color)

actually_fast = FastCar.fromOtherCar(thought_was_classic)

这是标准方式。

根据实际的班级布局,您可以执行以下操作:

classic = Car('blue')

classic.__class__ = FastCar
classic.__dict__.update(FastCar(classic.color).__dict__)

classic.drive_fast()

但我不推荐它——它是一种 hack,它并不总是有效,而另一种方式更干净。

编辑: 基本上是要添加@PaulMcGuire 的评论所说的内容。听从这个建议,他是对的。

【讨论】:

    【解决方案2】:

    您可以借用“复制构造函数”的 C++ 概念来做这样的事情。

    允许 Car 的构造函数获取 Car 实例,并复制其所有属性。 FastCar 然后应该接受 Car 实例或 FastCar 实例。

    那么,要改装汽车,您只需执行one_car = FastCar(one_car)。请注意,这不会影响对原始 Car 对象的引用,它仍然指向同一个 Car。

    【讨论】:

      【解决方案3】:

      为什么不只使用一个类?

      class Car(object):
          def __init__(self, color, max_speed = 50):
              self.color = color
              self.max_speed = max_speed
          def drive(self):
              print "Driving at %s mph"%self.max_speed
      
      c=Car('blue')
      c.max_speed = 100
      

      【讨论】:

        【解决方案4】:

        在 OOP 中,实例化后更改活动对象的类型(类)并不常见。我几乎不知道两种语言可以将其作为肮脏的黑客。类型(类)的全部目的是事先知道对象可以执行和不可以执行的操作。如果你想要这样的东西,你可能会误解 OOP 的概念。

        【讨论】:

        • 如果您是 OOP 新手,我想您可能会考虑从字符数组中创建一个字符串来更改对象的类型。它正在从旧对象的内容中创建一个新对象,这是他真正想做的事情(他只是不知道)。
        • 谢谢,但我不认为这是我想做的。我真的不想创建一个新对象。
        猜你喜欢
        • 2021-12-27
        • 2015-05-29
        • 2019-01-06
        • 2010-10-30
        • 1970-01-01
        • 2011-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多