python类工厂继承随机父级

标签 python python-2.7 inheritance factory

我有一些这样的代码:

class Person(object):
    def drive(self, f, t):
        raise NotImplementedError

class John(Person):
    def drive(self, f, t):
        print "John drove from %s to %s" % (f,t)

class Kyle(Person):
    def drive(self, f, t):
        print "Kyle drove from %s to %s" % (f,t)

class RandomPerson(Person):
    # instansiate either John or Kyle, and inherit it.
    pass

class Vehicle(object):
    pass

class Driver(Person, Vehicle):
    def __init__(self):
        # instantiate and inherit a RandomPerson somehow
        pass

d1 = Driver()
d1.drive('New York', 'Boston')
>>> "John drove from New York to Boston"

d2 = Driver()
d2.drive('New Jersey', 'Boston')
>>> "Kyle drove from New Jersey to Boston"

我如何实现 RandomPerson,并满足以下要求:
  • 调用 person = RandomPerson()必须返回 RandomPerson目的。
  • RandomPerson应该子类化 JohnKyle随机。
  • 最佳答案

    在我最初的答案中(我删除了,因为它完全是错误的)我说我会考虑这样做:

    class RandomPerson(Person):
        def __init__(self):
            rand_person = random.choice((John, Kyle))()
            self.__dict__ = rand_person.__dict__
    

    这种方式是对 Python Borg idiom 的改编;这个想法是关于一个对象的所有重要信息都包含在它的 __dict__ 中。 .

    但是,这仅在覆盖同一类的对象时有效(这就是您在 Borg 习语中所做的);对象__dict__仅包含与对象实例相关的状态信息,不是 对象类。

    可以像这样切换对象的类:
    class RandomPerson(Person):
        def __init__(self):
            rand_person = random.choice((John, Kyle))
            self.__class__ = rand_person
    

    但是,这样做将意味着调用 RandomPerson然后不会返回 RandomPerson 的实例根据您的要求,但来自 KyleJohn .所以这是不行的。

    这是获取 RandomPerson 的方法作用类似于 Kyle 的对象或 John ,但不是:
    class RandomPerson(Person): 
        def __new__(cls):
            new = super().__new__(cls)
            new.__dict__.update(random.choice((Kyle,John)).__dict__)
            return new
    

    这个 - 与 Borg 习语非常相似,除了用类而不是实例对象来做,而且我们只复制所选类 dict 的当前版本 - 真的很邪恶:我们已经对 RandomPerson 进行了脑叶切除。类和(随机)卡住了 Kyle 的大脑或 John类(class)到位。不幸的是,没有迹象表明发生了这种情况:
    >>> rperson = RandomPerson()
    >>> assert isinstance(rperson,Kyle) or isinstance(rperson,John)
    AssertionError
    

    所以我们还没有真正子类化 KyleJohn .而且,这真的很邪恶。所以除非你有充分的理由,否则请不要这样做。

    现在,假设您确实有充分的理由,上述解决方案 应该够用了如果您所追求的只是确保您可以使用来自 Kyle 的任何类状态信息(方法和类属性)或 JohnRandomPerson .但是,如前所述,RandomPerson仍然不是两者的真正子类。

    就我所知,没有办法在实例创建时实际随机子类化一个对象的类,并使类在多个实例创建中保持状态。你将不得不伪造它。

    伪造它的一种方法是允许 RandomPerson被视为 John 的子类和 Kyle使用 abstract baseclass module and __subclasshook__ ,并将其添加到您的 Person类(class)。这看起来是一个很好的解决方案,因为 Person class 是一个接口(interface),无论如何都不会直接使用。

    这是一种方法:
    class Person(object):
        __metaclass__ = abc.ABCMeta
        def drive(self, f, t):
            raise NotImplementedError
        @classmethod
        def __subclasshook__(cls, C):
            if C.identity is cls:
                return True
            return NotImplemented
    
    class John(Person):
        def drive(self, f, t):
            print "John drove from %s to %s" % (f,t)
    
    class Kyle(Person):
        def drive(self, f, t):
            print "Kyle drove from %s to %s" % (f,t)
    
    class RandomPerson(Person): 
        identity = None
        def __new__(cls):
            cls.identity = random.choice((John,Kyle))
            new = super().__new__(cls)
            new.__dict__.update(cls.identity.__dict__)
            return new
    
    >>> type(RandomPerson())
    class RandomPerson
    >>> rperson = RandomPerson()
    >>> isinstance(rperson,John) or isinstance(rperson,Kyle)
    True
    

    现在 RandomPerson - 虽然它在技术上不是子类 - 被认为是 Kyle 的子类或 John ,并且还共享了 Kyle 的状态或 John .实际上,每次创建新实例时(或更改 RandomPerson.identity 时),它都会在两者之间随机来回切换。这样做的另一个效果:如果你有多个RandomPerson实例,它们都共享任何状态 RandomPerson恰好是在那一刻——即,rperson1可能开始是 Kyle ,然后当 rperson2被实例化,两者都是 rperson2rperson1可以是 John (或者它们都可以是 Kyle,然后在创建 John 时切换到 rperson3)。

    不用说,这是非常奇怪的行为。事实上,这太奇怪了,我怀疑你的设计需要彻底改革。我真的不认为有一个很好的理由永远这样做(除了可能对某人开个坏玩笑)。

    如果您不想将此行为混入您的 Person类,您也可以单独进行:
    class Person(object):
        def drive(self, f, t):
            raise NotImplementedError
    
    class RandomPersonABC():
        __metaclass__ = abc.ABCMeta
        @classmethod
        def __subclasshook__(cls, C):
            if C.identity is cls:
                return True
            return NotImplemented
    
    class John(Person, RandomPersonABC):
        def drive(self, f, t):
            print "John drove from %s to %s" % (f,t)
    
    class Kyle(Person, RandomPersonABC):
        def drive(self, f, t):
            print "Kyle drove from %s to %s" % (f,t)
    
    class RandomPerson(Person): 
        identity = None
        def __new__(cls):
            cls.identity = random.choice((John,Kyle))
            new = super().__new__(cls)
            new.__dict__.update(cls.identity.__dict__)
            return new
    

    关于python类工厂继承随机父级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30899499/

    相关文章:

    python - 将变量列表转换为字符串

    c++ - 通过基类调用时,实现的虚方法调用失败

    c# - 为什么不能从扩展类型的基类中调用扩展方法?

    python - 在 Python 中用一个字符串和一个整数创建一个字符串

    python - 从源安装时,laspy 找不到 laszip。 laszip 在路径中

    performance - Python any() + 生成器表达式

    python - 如何向自动生成的 Python Selenium 脚本添加参数

    python-2.7 - 为 ssl 包装的套接字调用连接方法时出现一些错误

    c# - 没有给出与 'firstName' 所需的形参 'Person.Person(string, string)' 相对应的参数

    python - 沿给定轴的 numpy kron