简体   繁体   中英

Adding class inheritance dynamically

I want to create dynamic class inheritance with python. For example ( x is maybe an random number)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Test3(object):
  def sub(self):
    self.c = self.a - self.b

class Test2(object):
  def add(self):
    self.c = self.a + self.b


class Test1(object):
  def __init__(self):
    self.a = 1
    self.b = 2
    self.c = 0


if x >= 0:
  test = Test1
  ## do something to load Test2 methods
  test.add()
  print (test.c)
elif x >= 10:
  test = Test1
  ## do something to load Test3 methods
  test.sub()
  print (test.c)
else:
  test = Test1
  ## do something to load Test3 & Test2 methods
  test.add()
  print (test.c)
  test.sub()
  print (test.c)

I have tried different things to make this working. I couldn't manage anyway other than staticly implement the subclasses, which is not what I want:

class Test1(Test2, Test3)

I also don't want to load a object in a variable and get access about the variables name like:

test1.test3.sub()

There are a couple of tricks you can do to achieve this sort of thing.

First of you can do something ugly like this:-

def extend(instance, new_class):
    """Add new_class mixin to existing instance"""
    instance.__class__ = type(
            '%s_extended_with_%s' % (instance.__class__.__name__, new_class.__name__), 
            (instance.__class__, new_class), 
            {}
        )

You can use that like this

   extend(test , Test2 )

But I would normally prefer to create the dynamic type before initialization rather than overwrtting __class__ so instead of the above for your first example you would do

   custom_class = type('special_extended_class', ( Test, Test2 ), {} )
   test  = custom_class()

Note that in the above Test, and Test2 are variable refernces so you cna use anything here, but it isn't hugely different from doing the following which is more readable.

  class1 = Test
  class2 = Test2
  class TmpClass(class1, class2):pass
  test = TmpClass()

I don't really understand why you would want to do things that way. I would create a base test class then inherit different methods based off of that class.

class BaseTest(object):
    def __init__(self):
        super().__init__()

        self.a = 1
        self.b = 2
        self.c = 0

class Test3(BaseTest):
    def sub(self):
        self.c = self.a - self.b

class Test2(BaseTest):
    def add(self):
        self.c = self.a + self.b

class Test4(Test3, Test2):
    pass

if __name__ == '__main__':
    x = -1
    if x >= 10:
        test = Test3()
        ### load test3 methodes
        test.sub()
        print (test.c)

    elif x >= 0:
        test = Test2()
        ## load test2 methodes
        test.add()
        print (test.c)

    else:
        test = Test4()
        ### load test 2 & test 3 methodes
        test.add()
        print (test.c)
        test.sub()
        print (test.c)

If you really want something dynamic then you will have to set the x value on import

import random

class Test3(object):
    def sub(self):
        self.c = self.a - self.b

class Test2(object):
    def add(self):
        self.c = self.a + self.b

class Test4(Test3, Test2):
    pass

val = random.randint(0, 3)
print(val)
x = {0: object,
     1: Test3,
     2: Test2,
     3: Test4,
     }.get(val, object)
print(x)

class BaseTest(x):
    def __init__(self):
        super().__init__()

        self.a = 1
        self.b = 2
        self.c = 0


if __name__ == '__main__':
    b = BaseTest()
    print(b.c)

You could probably make this work by manually setting the members of the class member dictionary as suggested by rgammans, but the easiest way would be with exec:

super = 'list'
exec('class Awesome(' + super +'):\n  pass')

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