简体   繁体   中英

How do I create an instance of a subclass from an instance of a superclass?

I made two classes, a parent and a child. What I want to know is if it possible to initialize a child class using the parent class. This is my code:

class Pc:

    def __init__(self, brand, processor, price):
        self.brand = brand
        self.processor = processor
        self.price = price

class Laptop(Pc):
    def __init__(self,brand,processor,price, battery):
        Pc.__init__(self,brand,processor,price)
        self.battery = battery

Now I can initialize the Laptop class with:

b = Laptop('brand','processor','price')

But that doesn't seem of much use to me and my teacher hasn't explained it very well. I am interested to know if it is possible to do something like this:

a = Pc("brand","processor","price")
b = Laptop(a, "battery")

When I try this with my code I get an error. Is it even possible to do this ?

You can do:

class Laptop(Pc):
    def __init__(self, pc, battery):
        Pc.__init__(self, pc.brand, pc.processor, pc.price)
        self.battery = battery

This initializes the inherited properties from the pc argument you give to the constructor.

If you want to be able to use the short or long method, you should define the contructor to take keyword arguments, then use an if statement to call Pc.__init__() appropriately depending on which form was used.

There isn't a built-in mechanism in python to achieve what you want, so you have to do it yourself or find a 3rd-party solution.

A good approach to this is that I might take would be to add a class method on the superclass that can clone your object:

class Pc:

    @classmethod
    def clone(cls, target, *extra_args, **extra_kwargs):
        return cls(
            target.brand, target.processor, target.price, *extra_args,
            **extra_kwargs)

    def __init__(self, brand, processor, price):
        self.brand = brand
        self.processor = processor
        self.price = price


class Laptop(Pc):

    def __init__(self, brand, processor, price, battery):
        super(Laptop, self).__init__(brand, processor, price)
        self.battery = battery


a = Pc("brand","processor","price")
b = Laptop.clone(a, 'battery')

print(b.battery)

But you may find you begin to run into trouble with the initialization arguments. I would recommend keeping required arguments to __init__() to a minimum, and then configuring necessary properties afterwards:

a = Pc()
a.brand = 'brand'
# etc.

there are several option for this

  1. if you want to keepthe current behavior, while adding the new one, you can use *arg, for example like

     class Laptop(Pc): def __init__(self, *argv ): if len(argv) == 4: #the current one brand, processor, price, battery = argv elif len(argv) == 2: #the new one pc, battery = argv brand, processor, price = pc.brand, pc.processor, pc.price else: raise TypeError Pc.__init__(self,brand,processor,price) self.battery = battery 

    and use as simple as

     a = Pc("brand","processor","price") b = Laptop(a, "battery") 
  2. making a class method to handle this case

     class Laptop(Pc): def __init__(self,brand,processor,price, battery): Pc.__init__(self,brand,processor,price) self.battery = battery @classmethod def from_pc_and_battery(cls, pc, battery): return cls( pc.brand, pc.processor, pc.price, battery) 

    to use this one, is like this

     a = Pc("brand","processor","price") b = Laptop.from_pc_and_battery(a, "battery") 

You do it in somewhat hackish way:

import copy
a = Pc("brand","processor","price")
b = copy.deepcopy(a)
b.__class__ = Laptop()
b.battery = battery

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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