【问题标题】:Extend independent classes with a set of methods and attributes (wrapper)使用一组方法和属性扩展独立类(包装器)
【发布时间】:2019-12-31 11:12:48
【问题描述】:

我的目标是创建一个类,它使用一组功能扩展不同的类。 在下面的代码中,我能够创建问题的解决方案,但对我来说,这似乎不是解决问题的方法。

要求:
- 不能更改基类(猫、狗)。
- 具有附加功能的类(Pet_Dog、Pet_Cat)应该具有最少的代码量,因为我需要很多代码,只需进行微小的更改。
- 我需要能够导入 BaseClasses(Cat、Dog)以及增强类(Pet_Dog、Pet_Cat)。

到目前为止我的“解决方案”:

class Cat:
    def __init__(self, legs):
        self.legs = 4
        self.lives = 9

    def make_sound(self):
        print('Meow!')

class Dog:
    def __init__(self, legs):
        self.legs = 4
        self.hobby = 'Digging holes'

    def make_sound(self):
        print('Woof!')

    def chase_tail(self):
        print('Chasing tail')

def create_pet(BaseClass):
    class Pet(BaseClass):
        has_owner = True
        def __init__(self, name, legs):
            super().__init__(legs)
            self.name = name

        def plays_with_owner(self):
            print('playing with owner...')
    return Pet


class Pet_Dog(Dog):
    def __init__(self, BaseClass, name, legs):
        self.__class__ = create_pet(BaseClass)(name, legs).__class__
        self.__init__(name, legs)


class Pet_Cat(Cat):
    def __init__(self, BaseClass, name, legs):
        self.__class__ = create_pet(BaseClass)(name, legs).__class__
        self.__init__(name, legs)


print('Create Pet Dog')
pet_dog = Pet_Dog(Dog, 'Woofer', 4)
print('Dog Name:', pet_dog.name)
print('Dog Lives:', pet_dog.hobby)
print('Dog Owner:', pet_dog.has_owner)
pet_dog.make_sound()
pet_dog.chase_tail()
pet_dog.plays_with_owner()

【问题讨论】:

    标签: python python-3.x software-design


    【解决方案1】:

    在 Python 中,您可以拥有从多个其他类继承的类,因此我们可以创建一个 CatDog 类,以及一个单独的 Pet 类。然后我们可以让Pet_CatPet_Dog 继承自Pet 和它们各自的动物,即:

    class Cat:
        def __init__(self, legs):
            self.legs = legs
            self.lives = 9
    
        def make_sound(self):
            print('Meow!')
    
    class Dog:
        def __init__(self, legs):
            self.legs = legs
            self.hobby = 'Digging holes'
    
        def make_sound(self):
            print('Woof!')
    
        def chase_tail(self):
            print('Chasing tail')
    
    class Pet:
        has_owner = True
        name = None
    
        def plays_with_owner(self):
            print('playing with owner...')
    
    class Pet_Dog(Dog, Pet):
        def __init__(self, name, legs):
            super().__init__(legs)
            self.name = name
    
    class Pet_Cat(Cat, Pet):
        def __init__(self, name, legs):
            super().__init__(legs)
            self.name = name
    
    
    print('Create Pet Dog')
    pet_dog = Pet_Dog('Woofer', 4)
    print('Dog Name:', pet_dog.name)
    print('Dog Lives:', pet_dog.hobby)
    print('Dog Owner:', pet_dog.has_owner)
    pet_dog.make_sound()
    pet_dog.chase_tail()
    pet_dog.plays_with_owner()
    

    输出:

    Create Pet Dog
    Dog Name: Woofer
    Dog Lives: Digging holes
    Dog Owner: True
    Woof!
    Chasing tail
    playing with owner...
    

    编辑:

    如果您希望两者都具有 init 函数,请改用它:

    class Cat:
        def __init__(self, legs):
            self.legs = legs
            self.lives = 9
    
        def make_sound(self):
            print('Meow!')
    
    class Dog:
        def __init__(self, legs):
            self.legs = legs
            self.hobby = 'Digging holes'
    
        def make_sound(self):
            print('Woof!')
    
        def chase_tail(self):
            print('Chasing tail')
    
    class Pet:
        def __init__(self):
            self.has_owner = True
            self.name = None
    
        def plays_with_owner(self):
            print('playing with owner...')
    
    class Pet_Dog(Dog, Pet):
        def __init__(self, name, legs):
            Dog.__init__(self, legs)
            Pet.__init__(self)
    
            self.name = name
    
    class Pet_Cat(Cat, Pet):
        def __init__(self, name, legs):
            Cat.__init__(self, legs)
            Pet.__init__(self)
    
            self.name = name
    

    【讨论】:

    • 感谢您的快速回答!我之前尝试过使用多重继承,但后来我被处理两个 init 方法卡住了。 Pet 需要有一个,但它应该在 BaseClass 中的那个之后调用。多重继承有可能吗?
    • 有更好的方法来处理对超类初始化器的调用,参见我的回答。
    【解决方案2】:

    如果你真的想在这里使用继承,可以使用多重继承和协作super调用,避免无用的重复:

    class Cat:
        def __init__(self, legs):
            self.legs = legs
            self.lives = 9
    
    
    class Dog:
        def __init__(self, legs):
            self.legs = legs
            self.hobby = 'Digging holes'
    
    class Pet:
        def __init__(self, name, *args, **kwargs):
            self.has_owner = True
            self.name = name
            super().__init__(*args, **kwargs)
    
        def plays_with_owner(self):
            print('playing with owner...')
    
    
    # Pet has to come before the "animal" class for the cooperative
    # super() call to work
    
    class PetCat(Pet, Cat):
        pass
    
    class PetDog(Pet, Dog):
        pass
    

    您甚至可以自动创建这些子类,但这不一定是一种改进:

    def make_pet_class(name, base):
        return type.__new__(name, (Pet, base), {})
    
    PetCat = make_pet_class("PetCat", Cat)
    

    现在继承不一定是所有事情的最佳解决方案。继承主要是一种非常受限制的组合/委托形式,Python 使组合/委托变得非常容易:

    class Pet:
        def __init__(self, name, animal):
            self._animal  = animal
            self.name = name
            self.has_owner = True
    
        def plays_with_owner(self):
            print('playing with owner...')
    
        def __getattr__(self, attr):
            return getattr(self._animal, attr)
    
    
    kitty = Pet("kitty", Cat(4))
    pluto = Pet("pluto", Dog(4))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-07
      • 2021-02-20
      • 1970-01-01
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多